Странное поведение мода 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 делает это тоже. Смотрите также запись в Википедии.