Jaka jest składnia mod w Javie


231

Jako przykład w pseudokodzie:

if ((a mod 2) == 0)
{
    isEven = true;
}
else
{
    isEven = false;
}

Odpowiedzi:


357

Zamiast operatora modulo, który ma nieco inną semantykę, dla liczb całkowitych nieujemnych można użyć operatora reszty% . Dla twojego dokładnego przykładu:

if ((a % 2) == 0)
{
    isEven = true;
}
else
{
    isEven = false;
}

Można to uprościć do jednej linijki:

isEven = (a % 2) == 0;

80
Jeśli / else jest niepotrzebny, wystarczy użyć isEven = (a% 2) == 0,
Steve Kuo

59
Ostrożnie z terminami mod i modular, ponieważ n (mod m) JEST ZAWSZE> = 0, ale nie n% m. n% m jest w zakresie> -m oraz <m. Chociaż Java ma operator reszty dla typów int i long, nie ma funkcji modułu ani operatora. To znaczy, -12% 10 = -2, podczas gdy -12 mod 10 = 8. Jeśli operator% zwraca wartość ujemną dla n% m, to (n% m) + m da ci n mod m. BigInteger zapewnia funkcje dla obu, a specyfikacje dla nich dość dobrze wyjaśniają różnicę. Uważaj też na zero. W matematyce, podczas gdy zero jest liczbą parzystą, NIE jest dodatnie ani ujemne.
Jim

4
@ nl-x Prawdopodobnie dlatego, że lepiej jest wyraźnie określać pierwszeństwo, niż pozostawić to konwencji. Dla jednego nie wiedziałem, że %jest to oceniane przed sprawdzeniem ==go, więc nie byłoby jasne, czy wyrażenie jest równoważne (a%2)==0czy a%(2==0). Myślę, że to mniej ważne w Javie, gdzie wartość logiczna to nie to samo, co liczba całkowita
Matthew Sainsbury

8
To nie jest operator modułu - to pozostały operator. Popraw post!
Kieren Johnstone,

2
boolean even = ((a & 1) == 0). Dużo łatwiej.
mdev,

111

Oto reprezentacja twojego pseudo-kodu w minimalnym kodzie Java;

boolean isEven = a % 2 == 0;

Teraz podzielę go na części. Operatorem modułu w Javie jest znak procentu (%). Dlatego przyjęcie int% int zwraca inną int. Operator double equals (==) służy do porównywania wartości, takich jak para liczb całkowitych i zwraca wartość logiczną. Jest to następnie przypisywane do zmiennej boolowskiej „isEven”. W oparciu o pierwszeństwo operatora moduł zostanie oceniony przed porównaniem.


12
minimum byłoby bez nawiasów;)
pstanton

3
Jest to operator reszty, a nie operator modułu.
Markiz Lorne

@ user207421 Jego nazwa jest w rzeczywistości pozostałym operatorem, ale czy nie są równoważne: „ moduł - 4. (obliczenia, programowanie) Operator umieszczony między dwiema liczbami, aby uzyskać pozostałą część podziału tych liczb.”?
GeroldBroser przywraca Monikę

93

Ponieważ wszyscy inni już udzielili odpowiedzi, dodam trochę dodatkowego kontekstu. % operator „modułu” faktycznie wykonuje pozostałą operację. Różnica między modem a remem jest subtelna, ale ważna.

(-1 mod 2) normalnie dałoby 1. Dokładniej biorąc pod uwagę dwie liczby całkowite, X i Y, operacja (X mod Y) zwraca wartość z zakresu [0, Y). Inaczej mówiąc, moduł X i Y jest zawsze większy lub równy zero i mniejszy niż Y.

Wykonywanie tej samej operacji za pomocą operatora „%” lub rem utrzymuje znak wartości X. Jeśli X jest ujemne, otrzymujesz wynik w zakresie (-Y, 0). Jeśli X jest dodatni, otrzymujesz wynik w zakresie [0, Y).

Często to subtelne rozróżnienie nie ma znaczenia. Wracając do pytania o kod, istnieje wiele sposobów rozwiązania „równości”.

Pierwsze podejście jest dobre dla początkujących, ponieważ jest szczególnie szczegółowe.

// Option 1: Clearest way for beginners
boolean isEven;
if ((a % 2) == 0)
{
  isEven = true
}
else
{
  isEven = false
}

Drugie podejście lepiej wykorzystuje język i prowadzi do bardziej zwięzłego kodu. (Nie zapominaj, że operator == zwraca wartość logiczną).

// Option 2: Clear, succinct, code
boolean isEven = ((a % 2) == 0);

Trzecie podejście jest tutaj dla kompletności i wykorzystuje operator trójskładnikowy . Chociaż operator trójskładnikowy jest często bardzo przydatny, w tym przypadku uważam, że drugie podejście jest lepsze.

// Option 3: Ternary operator
boolean isEven = ((a % 2) == 0) ? true : false;

Czwarte i ostatnie podejście polega na wykorzystaniu wiedzy o binarnej reprezentacji liczb całkowitych . Jeśli najmniej znaczącym bitem jest 0, liczba jest parzysta. Można to sprawdzić za pomocą operatora bitowego i operatora (&). Chociaż takie podejście jest najszybsze (wykonujesz proste maskowanie bitów zamiast dzielenia), być może jest trochę zaawansowane / skomplikowane dla początkującego.

// Option 4: Bitwise-and
boolean isEven = ((a & 1) == 0);

Tutaj użyłem operatora bitowego i operatora i przedstawiłem go w zwięzłej formie pokazanej w opcji 2. Przepisanie go w formie opcji 1 (i alternatywnie opcji 3) pozostawia się jako ćwiczenie dla czytelnika. ;)

Mam nadzieję, że to pomaga.


Dziękuję Rob. To zamieszanie powoduje ogromne trudności w wyjaśnianiu programistom sposobu implementacji algorytmów o właściwościach matematycznych z arytmetyki modułowej. Reszta nie jest modułem, ale można szybko uzyskać moduł z reszt.
Jim

1
@TickledPink Tyle, że nie kompiluje się w Javie.
Eugene Beresovsky

33

Aby operacja% (REM) Java działała jak MOD dla ujemnych wartości X i dodatnich wartości Y, możesz użyć tej metody:

private int mod(int x, int y)
{
    int result = x % y;
    if (result < 0)
    {
        result += y;
    }
    return result;
}

lub z operatorem trójskładnikowym (krótszy, ale w niektórych sytuacjach niemożliwy lub mniej wydajny):

private int mod(int x, int y)
{
    int result = x % y;
    return result < 0? result + y : result;
}

12

Java faktycznie nie ma operatora modulo, podobnie jak C. % w Javie jest operatorem reszty. Na dodatnich liczbach całkowitych działa dokładnie tak jak modulo, ale działa inaczej na ujemnych liczbach całkowitych i, w przeciwieństwie do modulo, może również pracować z liczbami zmiennoprzecinkowymi. Nadal jednak rzadko używa się% na liczbach całkowitych innych niż dodatnie, więc jeśli chcesz nazwać to modulo, nie krępuj się!


Ale chcę, aby jeden był prawdziwym operatorem modulo, który działa również dla ujemnych liczb całkowitych, aby array[x mod array.length]zawsze miał dostęp do elementu w mojej tablicy, zamiast próbować indeksować ujemne pozycje.
Kris,

2
(x % y + y) % y lub począwszy od Java 8,Math.floorMod(x, y)
Greg Charles

12

Chociaż możliwe jest wykonanie właściwego modulo poprzez sprawdzenie, czy wartość jest ujemna i poprawienie, jeśli tak jest (jak sugerowało wielu), istnieje bardziej zwarte rozwiązanie.

(a % b + b) % b

To najpierw zrobi modulo, ograniczając wartość do zakresu -b -> + b, a następnie doda b, aby upewnić się, że wartość jest dodatnia, pozwalając następnemu modulo ograniczyć ją do zakresu 0 -> b.

Uwaga: Jeśli b jest ujemne, wynik również będzie ujemny


Może to spowodować przepełnienie, gdy a i b są dużymi liczbami, więc nie jest to właściwe rozwiązanie.
Trixie Wolf,

11

Kod działa znacznie szybciej bez użycia modulo:

public boolean isEven(int a){
    return ( (a & 1) == 0 );
}

public boolean isOdd(int a){
    return ( (a & 1) == 1 );
}

3
To wygląda na znacznie czystsze niż zaakceptowana odpowiedź. Nie ma to nic wspólnego z przedwczesną optymalizacją. Jest po prostu lepszy - jeśli działa.
AlexWien

4
@LluisMartinez Jest to jedno z najczęściej cytowanych powiedzeń w informatyce. Pełny cytat brzmi: „Programiści marnują ogromną ilość czasu na myślenie lub martwienie się o szybkość niekrytycznych części swoich programów, a te próby wydajności mają silny negatywny wpływ na debugowanie i konserwację. Powinniśmy zapomnieć o małych wydajność, powiedzmy w 97% przypadków: przedwczesna optymalizacja jest źródłem wszelkiego zła. Jednak nie powinniśmy tracić naszych możliwości w tak krytycznych 3%. ”. Co właściwie oznacza coś zupełnie innego.
Markiz Lorne

3
@EJP Prawdopodobnie masz rację. Zrobiłem test (pętla z 1 milionem iteracji) zajęło 4000 nanosekund z modułem, 2500 nanosekund z logicznym i.
Lluis Martinez,

Dlaczego miałaby to być odpowiedź? Jasne, że robi parzyste, ale nie robi nic z operatorem mod / reszta. Pytanie dotyczy operatora modów, a nie tego, jak znaleźć parzystą parzystą.
Mark Walsh



4

W Javie jest to %operator: 15.17.3. Pozostały operator%

Należy pamiętać, że istnieje również floorModw java.lang.Mathklasie, która da inny wynik z %argumentów z różnych znaków:

public static int floorMod​(int x, int y)


1
Pozytywnie oceniany, ponieważ floorMod jest lepszym operatorem „modulo” niż %działa również poprawnie, gdy argument jest również ujemny. Żadna z pozostałych odpowiedzi tak naprawdę nie jest poprawna, ponieważ zawierają zastrzeżenie, że% nie jest tak naprawdę modulo, chyba że argumenty są pozytywne. W szczególności, jeśli chcesz zmapować każdą liczbę całkowitą na kolejną pozycję w tablicy, to array[floorMod(i, array.length)działa poprawnie, nawet jeśli indeks iprzechodzi na terytorium ujemne. Nie tak z %.
Kris

3

Również mod może być użyty w ten sposób:

int a = 7;
b = a % 2;

bbyłoby równe 1. Ponieważ 7 % 2 = 1.


prawdopodobnie błędem jest stosowanie operatorów złożonych w przykładzie dla początkujących i bez danych wyjściowych.
Stu Thompson,

3

Pozostałym operatorem w Javie jest %operator modulo, który można wyrazić jako

public int mod(int i, int j)
{
  int rem = i % j;
  if (j < 0 && rem > 0)
  {
    return rem + j;
  }
  if (j > 0 && rem < 0)
  {
    return rem + j;
  }
  return rem;
}

2

Jak zauważyli inni, %operator (reszta) nie jest tym samym co modoperacja / funkcja modułu matematycznego .

mod vs %

x mod nFunkcja odwzorowuje xsię nw przedziale [0,n).
Natomiast x % noperator odwzorowuje xsię nw przedziale (-n,n).

Aby mieć metodę korzystania z operacji modułu matematycznego i nie dbać o znak przed xjednym, można użyć:

((x % n) + n) % n

Może to zdjęcie pomaga lepiej to zrozumieć (ciężko mi było owinąć głowę tym pierwszym)

wprowadź opis zdjęcia tutaj


1
Ładny rysunek. Jeszcze jedna złożoność: nie bierze pod uwagę modułowości intsamej zmiennej 2 ^ 32 . floorModMetoda robi to poprawnie (ale być może trzeba dodatkowych obliczeń, jeśli njest ujemna).
Maarten Bodewes

1

Innym sposobem jest:

boolean isEven = false;
if((a % 2) == 0)
{
    isEven = true;
}

Ale najłatwiejszym sposobem jest nadal:

boolean isEven = (a % 2) == 0;

Jak powiedział @Steve Kuo.


0

W Javatrybie mod można wykonać jako taki:

Math.floorMod(a, b)

Uwaga: Operacja mod różni się od operacji reszty . W JavaThe pozostała operacja może być przeprowadzona w następujący sposób:

a % b

Cóż, nie do końca ... Jawadok Math.floorMod()ma to: The floor modulus is x - (floorDiv(x, y) * y), has the same sign as the divisor y, and is in the range of -abs(y) < r < +abs(y).więc nie jest dokładnie taki sam jak moduł matematyczny. Ale istnieje sposób na uzyskanie pozytywnego wyniku, również w Javadoc tej samej metody:If the signs of arguments are unknown and a positive modulus is needed it can be computed as (floorMod(x, y) + abs(y)) % abs(y).
WesternGun

@WesternGun To może być prawda, ale jeśli wiesz, że moduł jest dodatni, floorModoperacja działa zgodnie z oczekiwaniami. Istnieją również wartości floorModfor long, a poza tym BigIntegerwartości większe.
Maarten Bodewes

-1

Operatorem modulo jest% (znak procentu). Aby sprawdzić równość lub ogólnie zrobić modulo dla potęgi 2, możesz również użyć & (the i operator) jak isEven =! (A & 1).


-3

Alternatywa dla kodu z @Cody:

Za pomocą operatora modułu:

bool isEven = (a % 2) == 0;

Myślę, że jest to nieznacznie lepszy kod niż pisanie if / else, ponieważ jest mniej powielania i nieużywana elastyczność. Badanie wymaga nieco więcej mocy mózgu, ale dobre nazewnictwo isEvenkompensuje.


2
Jest to operator reszty, a nie operator modułu.
Markiz Lorne

@EJP ok. Czym więc jest operator modułu?
TheRealChx101
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.