В java, когда вы делаете
a % b
Если a отрицательно, он вернет отрицательный результат, вместо того, чтобы оборачиваться до b, как должно. Как лучше всего это исправить? Я могу думать только так
a < 0 ? b + a : a % b
В java, когда вы делаете
a % b
Если a отрицательно, он вернет отрицательный результат, вместо того, чтобы оборачиваться до b, как должно. Как лучше всего это исправить? Я могу думать только так
a < 0 ? b + a : a % b
Ответы:
Он ведет себя так, как должен a% b = a - a / b * b; т.е. это остаток.
Вы можете сделать (a% b + b)% b
Это выражение работает, поскольку результат (a % b)
обязательно ниже чем b
, независимо от того a
, положительный он или отрицательный. Добавление b
заботится о отрицательных значениях a
, так как (a % b)
имеет отрицательное значение между -b
и 0
, (a % b + b)
обязательно ниже b
и положительный результат . Последний модуль присутствует в случае, если a
с самого начала было положительным, так как если a
положительное значение (a % b + b)
станет больше, чем b
. Следовательно, (a % b + b) % b
превращает его в меньшее, чем b
снова (и не влияет на отрицательные a
значения).
(a % b)
обязательно меньше чем b
(независимо от того a
, положительный он или отрицательный), добавление b
учитывает отрицательные значения a
, поскольку (a % b)
меньше b
и меньше чем 0
, (a % b + b)
обязательно меньше b
и положительно. Последний модуль присутствует в случае, если a
с самого начала было положительным, так как если a
положительное значение (a % b + b)
станет больше, чем b
. Следовательно, (a % b + b) % b
превращает его в меньшее, чем b
снова (и не влияет на отрицательные a
значения).
a < 0
, может быть, вы могли бы взглянуть)
(a % b + b) % b
распадается на очень большие значения a
и b
. Например, использование a = Integer.MAX_VALUE - 1
и b = Integer.MAX_VALUE
даст в -3
качестве результата отрицательное число, чего вы хотели избежать.
while
будет медленнее, если он вам действительно нужен, за исключением того, что вам нужен только, и if
в этом случае он действительно быстрее.
Начиная с Java 8, вы можете использовать Math.floorMod (int x, int y) и Math.floorMod (long x, long y) . Оба эти метода возвращают те же результаты, что и ответ Питера.
Math.floorMod( 2, 3) = 2
Math.floorMod(-2, 3) = 1
Math.floorMod( 2, -3) = -1
Math.floorMod(-2, -3) = -2
float
или double
аргументами. Mod бинарный оператор ( %
) также работает с float
и double
операнды.
Для тех, кто еще не использует (или не может использовать) Java 8, Guava пришел на помощь с IntMath.mod () , доступным с Guava 11.0.
IntMath.mod( 2, 3) = 2
IntMath.mod(-2, 3) = 1
Одно предостережение: в отличие от Java 8 Math.floorMod (), делитель (второй параметр) не может быть отрицательным.
В теории чисел результат всегда положительный. Я предполагаю, что это не всегда так в компьютерных языках, потому что не все программисты являются математиками. Мои два цента, я бы посчитал это конструктивным дефектом языка, но вы не можете его сейчас изменить.
= МОД (-4,180) = 176 = МОД (176, 180) = 176
потому что 180 * (-1) + 176 = -4 то же самое, что 180 * 0 + 176 = 176
Используя пример часов здесь, http://mathworld.wolfram.com/Congruence.html, вы бы не сказали, что duration_of_time mod cycle_length составляет -45 минут, вы бы сказали 15 минут, даже если оба ответа удовлетворяют базовому уравнению.
-1
вместо, n-1
например) тогда займись этим.
В Java 8 есть Math.floorMod
, но он очень медленный (в его реализации есть несколько делений, умножений и условное выражение). Вполне возможно, что JVM имеет внутреннюю оптимизированную заглушку для нее, однако, что значительно ускорит ее.
Самый быстрый способ обойтись без этого floorMod
- как и некоторые другие ответы здесь, но без условных переходов и только с одной медленной %
операцией.
Предполагая, что n положительно, а x может быть любым:
int remainder = (x % n); // may be negative if x is negative
//if remainder is negative, adds n, otherwise adds 0
return ((remainder >> 31) & n) + remainder;
Результаты при n = 3
:
x | result
----------
-4| 2
-3| 0
-2| 1
-1| 2
0| 0
1| 1
2| 2
3| 0
4| 1
Если вам нужно только равномерное распределение между 0
и, n-1
а не точным оператором мода, и ваши операторы x
не сгруппированы рядом 0
, следующее будет еще быстрее, так как параллелизм на уровне инструкций больше, и медленные %
вычисления будут происходить параллельно с другим частей, поскольку они не зависят от его результата.
return ((x >> 31) & (n - 1)) + (x % n)
Результаты для вышеуказанного с n = 3
:
x | result
----------
-5| 0
-4| 1
-3| 2
-2| 0
-1| 1
0| 0
1| 1
2| 2
3| 0
4| 1
5| 2
Если вход является случайным во всем диапазоне int, распределение обоих двух решений будет одинаковым. Если входные кластеры близки к нулю, n - 1
в последнем решении будет слишком мало результатов .
Вот альтернатива:
a < 0 ? b-1 - (-a-1) % b : a % b
Это может быть или не быть быстрее, чем другая формула [(a% b + b)% b]. В отличие от другой формулы, она содержит ветвь, но использует на одну операцию по модулю меньше. Вероятно, выигрыш, если компьютер сможет правильно предсказать <0.
(Изменить: исправлена формула.)