Подтвердить что ты не робот

Работа модуля с отрицательными номерами

В c-программе я пытался выполнить приведенные ниже операции (просто чтобы проверить поведение)

 x = 5 % (-3);
 y = (-5) % (3);
 z = (-5) % (-3); 

printf("%d ,%d ,%d", x, y, z); 

дал мне вывод как (2, -2 , -2) в gcc. Я ожидал положительного результата каждый раз. Может ли модуль быть отрицательным? Может ли кто-нибудь объяснить это поведение?

4b9b3361

Ответ 1

C99 требует, чтобы при a/b было представлено:

(a/b) * b + a%b должен быть равен a

Это имеет смысл, логично. Правильно?

Посмотрим, к чему это приведет:


Пример A. 5/(-3) - -1

= > (-1) * (-3) + 5%(-3)= 5

Это может произойти только в том случае, если 5%(-3) равно 2.


Пример B. (-5)/3 - -1

= > (-1) * 3 + (-5)%3= -5

Это может произойти только в том случае, если (-5)%3 -2

Ответ 2

Оператор % в C не является модульным оператором, а оператором остатка.

Операторы Modulo и остатки отличаются относительно отрицательных значений.

С оператором остатка знак результата совпадает с знаком дивиденда, а с модульным оператором знак результата совпадает с признаком делителя.

C определяет операцию % для a % b как:

  a == (a / b * b) + a % b

с / целочисленным делением с усечением в сторону 0. Это усечение, которое выполняется по отношению к 0 (а не к отрицательной неистинности), которое определяет % как оператор остатка, а не оператор modulo.

Ответ 3

Основано на спецификации C99: a == (a / b) * b + a % b

Мы можем написать функцию для вычисления (a % b) == a - (a / b) * b!

int remainder(int a, int b)
{
    return a - (a / b) * b;
}

Для работы по модулю мы можем иметь следующую функцию (при условии b > 0)

int mod(int a, int b)
{
    int r = a % b;
    return r < 0 ? r + b : r;
}

Я пришел к выводу, что a % b в C - это операция остатка, а не операция по модулю.

Ответ 4

Я не думаю, что нужно проверять, является ли число отрицательным.

Простая функция для нахождения положительного по модулю была бы такой -

Изменение: Предполагая N > 0 и N + N - 1 <= INT_MAX

int modulo(int x,int N){
    return (x % N + N) %N;
}

Это будет работать для как положительных, так и отрицательных значений x.

Оригинальный P.S: также, как указал @chux, если ваши x и N могут достигать чего-то вроде INT_MAX-1 и INT_MAX соответственно, просто замените int на long long int.

И если они также пересекают пределы long long (т.е. около LLONG_MAX), то вы должны обрабатывать положительные и отрицательные случаи отдельно, как описано в других ответах здесь.

Ответ 5

Другие ответы объясняются в C99 или позже, деление целых чисел, содержащих отрицательные операнды, всегда усекать в нуль.

Обратите внимание, что в C89, будет ли результат округлен вверх или вниз, определяется реализацией. Поскольку (a/b) * b + a%b равно a во всех стандартах, результат %, включающий отрицательные операнды, также определен в C89.

Ответ 6

Может ли модуль быть отрицательным?

% может быть отрицательным, поскольку это оператор остатка, остаток после деления, а не после Euclidean_division. Начиная с C99 результат может быть 0, отрицательным или положительным.

 // a % b
 7 %  3 -->  1  
 7 % -3 -->  1  
-7 %  3 --> -1  
-7 % -3 --> -1  

Требуемый по модулю ОП является классическим евклидовым по модулю, а не %.

Я ожидал положительного результата каждый раз.

Для выполнения евклидова модуля, который хорошо определен всякий раз, когда определено a/b, a,b имеют любой знак, и результат никогда не бывает отрицательным:

int modulo_Euclidean(int a, int b) {
  int m = a % b;
  if (m < 0) {
    // m += (b < 0) ? -b : b; // avoid this form: it is UB when b == INT_MIN
    m = (b < 0) ? m - b : m + b;
  }
  return m;
}

modulo_Euclidean( 7,  3) -->  1  
modulo_Euclidean( 7, -3) -->  1  
modulo_Euclidean(-7,  3) -->  2  
modulo_Euclidean(-7, -3) -->  2   

Ответ 7

Результат операции Modulo зависит от знака числителя, и вы получаете -2 для y и z

Здесь ссылка

http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_14.html

Целочисленное подразделение

В этом разделе описываются функции для выполнения целочисленного деления. Эти функции являются избыточными в библиотеке GNU C, поскольку в GNU C Оператор '/' всегда округляется к нулю. Но в других C реализации, '/' могут вращаться по-разному с отрицательными аргументами. div и ldiv полезны, поскольку они указывают, как округлить quotient: к нулю. Остаток имеет тот же знак, что и числитель.

Ответ 8

В математике, откуда вытекают эти соглашения, нет утверждения о том, что по модулю арифметики должен давать положительный результат.

Eg.

1 mod 5 = 1, но он также может равняться -4. То есть 1/5 дает остаток 1 от 0 или -4 от 5. (Оба фактора 5)

Аналогично, -1 mod 5 = -1, но он также может равняться 4. То есть -1/5 дает остаток -1 от 0 или 4 от -5. (Оба фактора 5)

Для дальнейшего чтения просмотрите классы эквивалентности в математике.

Ответ 9

Оператор модуля дает остаток. Оператор модуля в c обычно принимает знак числителя

  • x = 5% (-3) - здесь числитель положителен, и в результате получается 2
  • y = (-5)% (3) - здесь числитель отрицателен, поэтому он дает -2
  • z = (-5)% (-3) - здесь числитель отрицателен, поэтому он дает -2

Также оператор модуля (остаточный) может использоваться только с целым типом и не может использоваться с плавающей точкой.

Ответ 10

Согласно стандарту C99, раздел 6.5.5. Мультипликативные операторы, требуется следующее:

(a / b) * b + a % b = a

Заключение

Знак результата операции остатка, согласно C99, совпадает с признаком дивиденда.

Рассмотрим некоторые примеры (dividend/divisor):

Когда только дивиденд отрицательный

(-3 / 2) * 2  +  -3 % 2 = -3

(-3 / 2) * 2 = -2

(-3 % 2) must be -1

Когда только делитель отрицателен

(3 / -2) * -2  +  3 % -2 = 3

(3 / -2) * -2 = 2

(3 % -2) must be 1

Когда оба делителя и дивиденда отрицательны

(-3 / -2) * -2  +  -3 % -2 = -3

(-3 / -2) * -2 = -2

(-3 % -2) must be -1

6.5.5 Мультипликативные операторы

Синтаксис

  1. мультипликативный выражение:
    • cast-expression
    • multiplicative-expression * cast-expression
    • multiplicative-expression/cast-expression
    • multiplicative-expression % cast-expression

Ограничения

  1. Каждый из операндов должен иметь арифметический тип. Операнды оператора % должны иметь целочисленный тип.

Семантика

  1. Обычные арифметические преобразования выполняются в операндах.

  2. Результатом двоичного * оператора является произведение операндов.

  3. Результатом оператора / является фактор от деления первого операнда на второй; результатом оператора % является остаток. В обеих операциях, если значение второго операнда равно нулю, поведение не определено.

  4. Когда целые числа делятся, результатом оператора / является алгебраическое отношение с любой дробной частью, отброшенной [1]. Если частное a/b представимо, выражение (a/b)*b + a%b должно быть равно a.

[1]: Это часто называют "усечением к нулю".

Ответ 11

Я считаю, что более полезно думать о mod как он определен в абстрактной арифметике; не как операция, а как целый класс арифметики, с разными элементами и разными операторами. Это означает, что добавление в mod 3 не то же самое, что "нормальное" добавление; то есть; целочисленное сложение.

Итак, когда вы делаете:

5 % -3

Вы пытаетесь отобразить целое число 5 на элемент в наборе mod -3. Это элементы mod -3:

{ 0, -2, -1 }

Так:

0 => 0, 1 => -2, 2 => -1, 3 => 0, 4 => -2, 5 => -1

Скажем, вам нужно не спать по какой-то причине 30 часов, сколько часов у вас останется в этот день? 30 mod -24.

Но то, что реализует C, - это не mod, а остаток. В любом случае, смысл в том, что имеет смысл возвращать негативы.

Ответ 12

Оператор modulo аналогичен оператору mod, когда число положительное, но другое, если число отрицательно.

Много раз в проблемах нас просят дать ответ по модулю 10 ^ 9 + 7.

Пусть ответ (до использования по модулю) обозначается символом 'a'.

Простое прямое правило -

если a положительный, то по модулю 10 ^ 9 + 7 = a% (10 ^ 9 + 7)

если a отрицательный, то по модулю 10 ^ 9 + 7 = (a% (10 ^ 9 + 7)) + (10 ^ 9 + 7)

Если в таких проблемах мы обнаружим, что любой шаг цикла может вычислять значение, выходящее за пределы целого диапазона (если мы используем целые числа), то мы можем использовать оператор modulo на этом самом шаге. Окончательный ответ будет таким, как если бы мы использовали оператор modulo только один раз.

Это потому, что: (a * b)% c = ((a% c) (b% c))% c То же самое относится к сложениям и вычитанию.

Ответ 13

Посмотрите это видео, чтобы понять модульную арифметику. Ссылка для криптографии в целом, и модули являются одной большой темой в этом. Однако, чтобы понять модуль -ve, пожалуйста, посмотрите следующие видео в этой серии, как этот