W Javie, kiedy to robisz
a % b
Jeśli a jest ujemne, zwróci wynik ujemny, zamiast zawijać się do b, tak jak powinno. Jak najlepiej to naprawić? Jedyny sposób, w jaki mogę myśleć, to
a < 0 ? b + a : a % b
java
modulo
negative-number
fent
źródło
źródło
Odpowiedzi:
Zachowuje się tak, jak powinien a% b = a - a / b * b; tj. to reszta.
Możesz zrobić (a% b + b)% b
To wyrażenie działa, ponieważ wynik
(a % b)
jest koniecznie niższy niżb
, bez względu naa
to, czy jest dodatni czy ujemny. Dodawanieb
uwzględnia ujemne wartościa
, ponieważ(a % b)
jest wartością ujemną między-b
i0
,(a % b + b)
jest z konieczności mniejsze niżb
i dodatnie. Ostatni modulo jest tam na wypadek, gdybya
był dodatni na początku, ponieważ jeślia
jest dodatnie,(a % b + b)
stałoby się większe niżb
. Dlatego(a % b + b) % b
zmienia go na mniejszy niżb
ponownie (i nie wpływa naa
wartości ujemne ).źródło
(a % b)
jest koniecznie niższy niżb
(nieważne, czya
jest dodatni czy ujemny), dodawanieb
uwzględnia ujemne wartościa
, ponieważ(a % b)
jest niższeb
i niższe niż0
,(a % b + b)
jest z konieczności niższeb
i dodatnie. Ostatni modulo jest tam na wypadek, gdybya
był dodatni na początku, ponieważ jeślia
jest dodatnie,(a % b + b)
stałoby się większe niżb
. Dlatego(a % b + b) % b
zmienia go na mniejszy niżb
ponownie (i nie wpływa naa
wartości ujemne ).a < 0
, może mógłbyś rzucić okiem)(a % b + b) % b
rozkłada się na bardzo duże wartościa
ib
. Na przykład użyciea = Integer.MAX_VALUE - 1
ib = Integer.MAX_VALUE
da-3
jako wynik, czyli liczbę ujemną, czego chciałeś uniknąć.while
byłoby wolniejsze, jeśli naprawdę go potrzebujesz, z wyjątkiem tego, że potrzebujesz tylko wtedy,if
gdy jest to faktycznie szybsze.Od wersji Java 8 można używać Math.floorMod (int x, int y) i Math.floorMod (long x, long y) . Obie te metody zwracają te same wyniki, co odpowiedź Petera.
źródło
float
anidouble
. Operator binarny mod (%
) działa również z operandamifloat
idouble
.Dla tych, którzy jeszcze nie używają (lub nie mogą jeszcze używać) Java 8, Guava przyszedł na ratunek dzięki IntMath.mod () , dostępnym od wersji Guava 11.0.
Jedno zastrzeżenie: w przeciwieństwie do Math.floorMod () w Java 8, dzielnik (drugi parametr) nie może być ujemny.
źródło
W teorii liczb wynik jest zawsze pozytywny. Wydaje mi się, że nie zawsze tak jest w językach komputerowych, ponieważ nie wszyscy programiści są matematykami. Moje dwa centy, uznałbym to za defekt konstrukcyjny języka, ale nie możesz tego teraz zmienić.
= MOD (-4,180) = 176 = MOD (176, 180) = 176
ponieważ 180 * (-1) + 176 = -4 to samo co 180 * 0 + 176 = 176
Korzystając z przykładu zegara tutaj, http://mathworld.wolfram.com/Congruence.html , nie powiedziałbyś, że czas trwania_czasu mod długość_cyklu wynosi -45 minut, powiedziałbyś, że 15 minut, mimo że obie odpowiedzi spełniają podstawowe równanie.
źródło
-1
zamiastn-1
na przykład) to mieć na to.Java 8 ma
Math.floorMod
, ale jest bardzo powolna (jej implementacja ma wiele podziałów, mnożeń i warunek). Możliwe, że JVM ma wbudowany zoptymalizowany kod pośredniczący, co znacznie przyspieszyłoby to.Najszybszym sposobem na zrobienie tego bez
floorMod
jest jak inne odpowiedzi tutaj, ale bez gałęzi warunkowych i tylko z jedną wolną%
operacji.Zakładając, że n jest dodatnie, a x może być dowolne:
Wyniki, gdy
n = 3
:Jeśli potrzebne jest tylko rozkład jednolity między
0
an-1
i nie dokładna operatora mod, a twojex
„s nie klaster blisko0
dodaje będzie jeszcze szybciej, ponieważ nie ma więcej poziom instrukcja równoległość i powolne%
obliczenie nastąpi równolegle z innymi części, ponieważ nie zależą one od wyniku.return ((x >> 31) & (n - 1)) + (x % n)
Wyniki dla powyższego z
n = 3
:Jeśli dane wejściowe są losowe w pełnym zakresie liczby int, rozkład obu rozwiązań będzie taki sam. Jeśli klastry wejściowe są bliskie zeru,
n - 1
w tym drugim rozwiązaniu wyników będzie za mało .źródło
Oto alternatywa:
To może, ale nie musi, być szybsze niż ta inna formuła [(a% b + b)% b]. W przeciwieństwie do drugiej formuły zawiera gałąź, ale wykorzystuje jedną operację modulo mniej. Prawdopodobnie wygrana, jeśli komputer może poprawnie przewidzieć <0.
(Edycja: Poprawiono formułę.)
źródło