Я пытаюсь изменить целое число, чтобы получить позицию массива, чтобы он зациклился. Выполнение i %
arrayLength
работает хорошо для положительных чисел, но для отрицательных чисел все идет не так, как надо.
4 % 3 == 1
3 % 3 == 0
2 % 3 == 2
1 % 3 == 1
0 % 3 == 0
-1 % 3 == -1
-2 % 3 == -2
-3 % 3 == 0
-4 % 3 == -1
так что мне нужна реализация
int GetArrayIndex(int i, int arrayLength)
такой, что
GetArrayIndex( 4, 3) == 1
GetArrayIndex( 3, 3) == 0
GetArrayIndex( 2, 3) == 2
GetArrayIndex( 1, 3) == 1
GetArrayIndex( 0, 3) == 0
GetArrayIndex(-1, 3) == 2
GetArrayIndex(-2, 3) == 1
GetArrayIndex(-3, 3) == 0
GetArrayIndex(-4, 3) == 2
Я делал это раньше, но почему-то сегодня мой мозг тает :(
Ответы:
Я всегда использую свою собственную
mod
функцию, определенную какКонечно, если вам надоело иметь два вызова операции модуля, вы можете написать это как
или их варианты.
Причина, по которой это работает, заключается в том, что «x% m» всегда находится в диапазоне [-m + 1, m-1]. Поэтому, если он вообще отрицательный, добавление m к нему приведет к положительному диапазону, не меняя его значения по модулю m.
источник
r = x%m
есть-1
, после которогоr+m
есть1
. Цикл while не нужен. Дело в том, что (как я написал в ответе)x%m
всегда строго больше-m
, поэтому вам нужно добавитьm
не более одного раза, чтобы сделать его положительным.r
поa
модулюb
, то такое , что 0 ≤ г <| B |.Обратите внимание, что оператор% C # и C ++ на самом деле НЕ является модулем, это остаток. Формула для модуля по вашему желанию в вашем случае:
Вы должны перекодировать это в C # (или C ++), но это способ, которым вы получаете по модулю, а не остаток.
источник
-21 mod 4 is 3 because -21 + 4 x 6 is 3.
но-21 divided by 4 gives -5
с собойremainder of -1
. Для положительных значений разницы нет. Поэтому, пожалуйста, ознакомьтесь с этими различиями. И не доверяй Википедии все время :)%
остаток?Однострочная реализация, использующая
%
только один раз:источник
mod(-10, 6)
вручную, вы либо добавляете, либо вычитаете 6 раз, пока ответ не окажется в диапазоне[0, 6)
. Это обозначение означает «включительно слева и исключительно справа». В нашем случае мы добавляем 6 дважды, давая 2. Код довольно прост, и легко видеть, что он прав: во-первых, он эквивалентен сложению / вычитанию,n
как указано выше, за исключением того, что он останавливается на одноn
короткое, если приближается отрицательная сторона. В таком случае мы это исправим. Там: комментарии :)%
может быть хорошей идеей. См. Таблицу « Что стоит в управляемом коде» в статье « Написание более быстрого управляемого кода: знайте, что стоит» . Использование так%
же дорого, какint div
указано в таблице: примерно в 36 раз дороже, чем сложение или вычитание, и примерно в 13 раз дороже, чем умножение. Конечно, ничего страшного, если только это не лежит в основе того, что делает ваш код.%
дороже ли тест, чем тест и прыжок, особенно если его трудно предсказать?Ответ ShreevatsaR не будет работать во всех случаях, даже если вы добавите «if (m <0) m = -m;», если вы учтете отрицательные дивиденды / делители.
Например, -12 мод -10 будет 8, и это должно быть -2.
Следующая реализация будет работать как для положительных, так и для отрицательных дивидендов / делителей и соответствует другим реализациям (а именно, Java, Python, Ruby, Scala, Scheme, Javascript и Google's Calculator):
Тестовый набор с использованием xUnit:
источник
mod
функция обычно вызывается с положительным модулем (обратите внимание на переменнуюarrayLength
в исходном вопросе, на который здесь дан ответ, который, по-видимому, никогда не бывает отрицательным), поэтому на самом деле функцию не нужно заставлять работать для отрицательного модуля. (Вот почему я упоминаю трактовку отрицательного модуля в комментарии к моему ответу, а не в самом ответе.) (Продолжение ...)r = a - b floor(a/b)
всегда положительно). Даже среди компьютерных систем, например, Паскаль и Мэйпл, это всегда положительно.Добавление некоторого понимания.
По евклидову определению мод мод всегда должен быть положительным.
Пример:
Вывод:
источник
-1
?the positive remainder is always chosen
но языки программирования выбирают в зависимости от языка и знаков a и / или n. [5] Стандартные Pascal и Algol68 дают положительный остаток (или 0) даже для отрицательных делителей, а некоторые языки программирования, такие как C90, оставляют его на усмотрение, когда любой из n или a отрицателен.Сравнивая два преобладающих ответа
и
На самом деле никто не упомянул тот факт, что первый может бросить,
OverflowException
а второй нет. Хуже того, при непроверенном контексте по умолчанию первый ответ может вернуть неправильный ответ (см.,mod(int.MaxValue - 1, int.MaxValue)
Например). Таким образом, второй ответ не только кажется более быстрым, но и более правильным.источник
Просто добавьте свой модуль (arrayLength) к отрицательному результату%, и все будет в порядке.
источник
Для более эффективной работы разработчиков
Небольшое сравнение производительности
Что касается производительности стоимость приведения к Uint, посмотрите здесь
источник
-3 % 10
должен быть либо -3, либо 7. Так как нужен неотрицательный результат, 7 будет ответом. Ваша реализация вернет 3. Вы должны изменить оба параметраuint
и удалить приведение.n
является степенью двойки, и в этом случае вы можете просто использовать логические и ((uint)k & (n - 1)
) вместо этого, если компилятор еще не сделал этого за вас (компиляторы часто достаточно умны, чтобы понять это).Мне нравится трюк, представленный Питером Н. Льюисом в этой теме : «Если n имеет ограниченный диапазон, то вы можете получить желаемый результат, просто добавив известную постоянную, кратную [делителю], которая больше абсолютного значения минимум «.
Так что, если у меня есть значение d в градусах, и я хочу взять
и я хочу избежать проблем, если d отрицательно, то вместо этого я просто делаю это:
Это предполагает, что хотя d может быть отрицательным, известно, что оно никогда не будет более отрицательным, чем -720.
источник
%
.Вы ожидаете поведения, которое противоречит документированному поведению оператора% в c # - возможно, потому, что вы ожидаете, что оно будет работать так, как оно работает на другом языке, к которому вы более привыкли. Документация на C # государств (курсив мой):
Требуемое значение можно рассчитать с помощью одного дополнительного шага:
источник
Однострочная реализация ответа dcastro (наиболее совместимого с другими языками):
Если вы хотите сохранить использование
%
оператора (вы не можете перегружать нативные операторы в C #):Вариант использования, оба работает:
источник
Все ответы здесь отлично работают, если ваш делитель положительный, но не совсем полный. Вот моя реализация, которая всегда возвращает диапазон
[0, b)
, такой, что знак выхода совпадает со знаком делителя, что позволяет использовать отрицательные делители в качестве конечной точки для выходного диапазона.PosMod(5, 3)
возвращает2
PosMod(-5, 3)
возвращает1
PosMod(5, -3)
возвращает-1
PosMod(-5, -3)
возвращает-2
(где
real_t
может быть любой тип номера)источник