У Java, коли ти робиш
a % b
Якщо а негативний, він поверне негативний результат замість того, щоб обертатися навколо b, як слід. Який найкращий спосіб це виправити? Єдиний спосіб я можу подумати
a < 0 ? b + a : a % b
У Java, коли ти робиш
a % b
Якщо а негативний, він поверне негативний результат замість того, щоб обертатися навколо b, як слід. Який найкращий спосіб це виправити? Єдиний спосіб я можу подумати
a < 0 ? b + a : a % b
Відповіді:
Він поводиться так, як слід,% b = a - a / b * b; тобто це залишок.
Ви можете зробити (% 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 (довгий х, довгий y) . Обидва ці методи дають ті самі результати, що і відповідь Петра.
Math.floorMod( 2, 3) = 2
Math.floorMod(-2, 3) = 1
Math.floorMod( 2, -3) = -1
Math.floorMod(-2, -3) = -2
float
або double
аргументами. Модний бінарний оператор ( %
) також працює float
і double
оперує.
Для тих, хто ще не використовує (або не може використовувати) Java 8, на допомогу Guava прийшов IntMath.mod () , доступний з Guava 11.0.
IntMath.mod( 2, 3) = 2
IntMath.mod(-2, 3) = 1
Одне застереження: на відміну від Math.floorMod () Java 8, дільник (другий параметр) не може бути негативним.
У теорії чисел результат завжди позитивний. Я б здогадався, що це не завжди так у комп’ютерних мовах, оскільки не всі програмісти є математиками. Мої два центи, я вважаю це недоліком дизайну мови, але ви не можете його змінити зараз.
= MOD (-4,180) = 176 = MOD (176, 180) = 176
тому що 180 * (-1) + 176 = -4 те саме, що 180 * 0 + 176 = 176
Використовуючи тут приклад годинника, http://mathworld.wolfram.com/Congruence.html, ви б не сказали, що тривалість_файлу тривалість циклу_довжина становить -45 хвилин, ви б сказали 15 хвилин, хоча обидві відповіді відповідають базовому рівнянню.
-1
замість, n-1
наприклад,) то майте на це.
У Java 8 є Math.floorMod
, але це дуже повільно (її реалізація має кілька підрозділів, множень і умовний). Можливо, що JVM має внутрішню оптимізовану заглушку для цього, однак, це значно пришвидшить його.
Найшвидший спосіб зробити це floorMod
, як і деякі інші відповіді тут, але без умовних гілок і лише з однією повільною%
оп.
Припустимо, що n позитивний, а х може бути будь-що:
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
«s НЕ кластерний поруч 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.
(Редагувати: виправлено формулу.)