Странное поведение мода Objective-C для отрицательных чисел

Поэтому я подумал, что отрицательные числа, когда мод, должны быть помещены в положительное пространство... Я не могу заставить это произойти в target-c

Я ожидаю этого:

-1 % 3 = 2
 0 % 3 = 0
 1 % 3 = 1
 2 % 3 = 2

Но получите это

-1 % 3 = -1
 0 % 3 = 0
 1 % 3 = 1
 2 % 3 = 2

Почему это так и есть ли обходной путь?

12 ответов

Решение
result = n % 3;
if( result < 0 ) result += 3;

Не выполняйте дополнительные операции с модами, как предлагается в других ответах. Они очень дорогие и ненужные.

В C и Objective-C операторы деления и модуля выполняют усечение до нуля. a / b является floor(a / b) если a / b > 0в противном случае это ceiling(a / b) если a / b < 0, Это всегда так a == (a / b) * b + (a % b)если конечно b равно 0. Как следствие, positive % positive == positive, positive % negative == positive, negative % positive == negative, а также negative % negative == negative (Вы можете выработать логику для всех 4 случаев, хотя это немного сложно).

Если n имеет ограниченный диапазон, то вы можете получить желаемый результат, просто добавив известную постоянную, кратную 3, которая больше абсолютного значения минимума.

Например, если n ограничено -1000..2000, то вы можете использовать выражение:

result = (n+1002) % 3;

Убедитесь, что максимум плюс ваша константа не будут переполнены при суммировании.

У нас проблема с языком:

математика говорит: я беру это число плюс этот номер мод другой номер
код-эр-слышит: я добавляю два числа, а затем делю результат на другое число
код-эр-говорит: как насчет отрицательных чисел?
математика говорит: что? поля mod other-number не имеют понятия отрицательных чисел?
код-эр-говорит: поле что? ...
  • математик в этих разговорах говорит о выполнении математики в круговой числовой линии. Если вы отнимаете от дна, вы оборачиваетесь к вершине.
  • человек кода говорит об операторе, который вычисляет остаток.

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

Если это будет поведение, и вы знаете, что это будет, то для m % n = rПросто используйте r = n + r, Если вы не знаете, что здесь произойдет, используйте r = r % n,

Редактировать: чтобы подвести итог, используйте r = ( n + ( m % n ) ) % n

Я бы также ожидал положительного числа, но я нашел это из ISO/IEC 14882:2003: Языки программирования - C++, 5.6.4 (находится в статье в Википедии о работе модуля):

Двоичный оператор% возвращает остаток от деления первого выражения на второе..... Если оба операнда неотрицательны, то остаток неотрицателен; если нет, знак остатка определяется реализацией

Почему: потому что именно так указывается оператор мода в стандарте C (Помните, что Objective-C является расширением C). Это сбивает с толку большинство людей, которых я знаю (как я), потому что это удивительно, и вы должны помнить это.

Что касается обходного пути: я бы использовал uncleo's.

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

int result = (n + 3) % 3;

Так как вы все равно делаете мод, добавление 3 к начальному значению не имеет никакого эффекта, если n не отрицательно (но не меньше -3), и в этом случае результат приводит к ожидаемому положительному модулю.

JavaScript тоже это делает. Я был пойман этим пару раз. Думайте об этом как об отражении вокруг нуля, а не как о продолжении.

Вместо a%b

Использование: a-b*floor((float)a/(float)b)

Вы ожидаете остаток и используете по модулю. В математике они одно и то же, в С они разные. В GNU-C есть Rem() и Mod(), у target-c есть только mod(), поэтому вам придется использовать приведенный выше код для имитации функции rem (которая аналогична mod в мире математики, но не в программировании). мир [для большинства языков по крайней мере])


Также обратите внимание, что вы можете определить простой в использовании макрос для этого.

#define rem(a,b) ((int)(a-b*floor((float)a/(float)b)))

Тогда вы могли бы просто использовать rem(-1,3) в вашем коде, и он должен работать нормально.

Не только java-скрипт, почти все языки показывают неправильный ответ: "что сказал coneybeare, правильно, когда у нас есть режим, нам нужно получить остаток. Остаток - это не что иное, как остаток от деления, и он должен быть положительным целым числом....

Если вы проверите номер строки, вы можете понять, что

Я также столкнулся с той же проблемой в VB, и это заставило меня принудительно добавить дополнительную проверку, например, если результат отрицательный, мы должны добавить делитель к результату.

Есть два варианта для остатка, и знак зависит от языка. ANSI C выбирает знак дивиденда. Я подозреваю, что именно поэтому Objective-C делает это тоже. Смотрите также запись в Википедии.

Другие вопросы по тегам