In Java quando lo fai
a % b
Se a è negativo, restituirà un risultato negativo, invece di avvolgere in b come dovrebbe. Qual è il modo migliore per risolvere questo problema? L'unico modo in cui posso pensare è
a < 0 ? b + a : a % b
In Java quando lo fai
a % b
Se a è negativo, restituirà un risultato negativo, invece di avvolgere in b come dovrebbe. Qual è il modo migliore per risolvere questo problema? L'unico modo in cui posso pensare è
a < 0 ? b + a : a % b
Risposte:
Si comporta come dovrebbe a% b = a - a / b * b; cioè è il resto.
Puoi fare (a% b + b)% b
Questa espressione funziona in quanto il risultato di (a % b)è necessariamente inferiore a b, non importa se aè positivo o negativo. L'aggiunta si bprende cura dei valori negativi di a, poiché (a % b)è un valore negativo tra -be 0, (a % b + b)è necessariamente inferiore a be positivo. L'ultimo modulo è presente nel caso in cui all'inizio afosse positivo, poiché se afosse positivo (a % b + b)diventerebbe maggiore di b. Pertanto, lo (a % b + b) % btrasforma in più piccolo di bnuovo (e non influisce sui avalori negativi ).
(a % b)è necessariamente inferiore a b(non importa se aè positivo o negativo), l'aggiunta si bprende cura dei valori negativi di a, poiché (a % b)è inferiore be inferiore a 0, (a % b + b)è necessariamente inferiore a be positivo. L'ultimo modulo è presente nel caso in cui all'inizio afosse positivo, poiché se afosse positivo (a % b + b)diventerebbe maggiore di b. Pertanto, lo (a % b + b) % btrasforma in più piccolo di bnuovo (e non influisce sui avalori negativi ).
a < 0, forse potresti dare un'occhiata)
(a % b + b) % binterrompe per valori molto grandi di ae b. Ad esempio, l'utilizzo di a = Integer.MAX_VALUE - 1e b = Integer.MAX_VALUEdarà -3come risultato, che è un numero negativo, che è ciò che si voleva evitare.
whilesarebbe più lento se ne hai davvero bisogno tranne che hai solo bisogno di un, ifnel qual caso è effettivamente più veloce.
A partire da Java 8, puoi usare Math.floorMod (int x, int y) e Math.floorMod (long x, long y) . Entrambi questi metodi restituiscono gli stessi risultati della risposta di Peter.
Math.floorMod( 2, 3) = 2
Math.floorMod(-2, 3) = 1
Math.floorMod( 2, -3) = -1
Math.floorMod(-2, -3) = -2
floato doubleargomenti. L'operatore binario Mod ( %) funziona anche con gli operandi floate double.
Per coloro che non usano ancora (o non sono in grado di usare) Java 8, Guava è venuto in soccorso con IntMath.mod () , disponibile da Guava 11.0.
IntMath.mod( 2, 3) = 2
IntMath.mod(-2, 3) = 1
Un avvertimento: a differenza di Math.floorMod () di Java 8, il divisore (il secondo parametro) non può essere negativo.
Nella teoria dei numeri, il risultato è sempre positivo. Immagino che non sia sempre così nei linguaggi dei computer perché non tutti i programmatori sono matematici. I miei due centesimi, lo considererei un difetto di progettazione del linguaggio, ma non puoi cambiarlo ora.
= MOD (-4,180) = 176 = MOD (176, 180) = 176
perché 180 * (-1) + 176 = -4 equivale a 180 * 0 + 176 = 176
Usando l'esempio dell'orologio qui, http://mathworld.wolfram.com/Congruence.html non diresti duration_of_time mod cycle_length è -45 minuti, diresti 15 minuti, anche se entrambe le risposte soddisfano l'equazione di base.
-1invece di n-1per esempio) allora fallo.
Java 8 lo ha Math.floorMod, ma è molto lento (la sua implementazione ha più divisioni, moltiplicazioni e un condizionale). È possibile che la JVM abbia uno stub ottimizzato intrinseco, tuttavia, che lo velocizzerebbe in modo significativo.
Il modo più veloce per farlo senza floorModè come alcune altre risposte qui, ma senza rami condizionali e solo una operazione lenta %.
Supponendo che n sia positivo e x possa essere qualsiasi cosa:
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;
I risultati quando n = 3:
x | result
----------
-4| 2
-3| 0
-2| 1
-1| 2
0| 0
1| 1
2| 2
3| 0
4| 1
Se hai solo bisogno di una distribuzione uniforme tra 0e n-1e non l'esatto operatore mod, e il tuo xnon si raggruppa vicino 0, il seguente sarà ancora più veloce, poiché c'è più parallelismo a livello di istruzione e il %calcolo lento avverrà in parallelo con l'altro parti in quanto non dipendono dal suo risultato.
return ((x >> 31) & (n - 1)) + (x % n)
I risultati per quanto sopra con 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
Se l'input è casuale nell'intero intervallo di un int, la distribuzione di entrambe le due soluzioni sarà la stessa. Se i cluster di input sono vicini allo zero, ci saranno troppi pochi risultati n - 1in quest'ultima soluzione.
Ecco un'alternativa:
a < 0 ? b-1 - (-a-1) % b : a % b
Questo potrebbe o non potrebbe essere più veloce dell'altra formula [(a% b + b)% b]. A differenza dell'altra formula, contiene un ramo, ma utilizza un'operazione modulo in meno. Probabilmente una vittoria se il computer può prevedere correttamente uno <0.
(Modifica: corretta la formula.)