Java 8 tiene Math.floorMod
, pero es muy lento (su implementación tiene múltiples divisiones, multiplicaciones y un condicional). Sin embargo, es posible que la JVM tenga un código auxiliar optimizado intrínseco, lo que lo aceleraría significativamente.
La forma más rápida de hacer esto sin floorMod
es como algunas otras respuestas aquí, pero sin ramas condicionales y solo una %
operación lenta .
Suponiendo que n es positivo y x puede ser cualquier 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;
Los resultados cuando n = 3
:
x | result
----------
-4| 2
-3| 0
-2| 1
-1| 2
0| 0
1| 1
2| 2
3| 0
4| 1
Si solo necesita una distribución uniforme entre 0
y n-1
y no el operador de mod exacto, y x
los suyos no se agrupan cerca 0
, lo siguiente será aún más rápido, ya que hay más paralelismo a nivel de instrucción y el %
cálculo lento ocurrirá en paralelo con el otro partes ya que no dependen de su resultado.
return ((x >> 31) & (n - 1)) + (x % n)
Los resultados de lo anterior 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
Si la entrada es aleatoria en el rango completo de un int, la distribución de ambas soluciones será la misma. Si los grupos de entrada se acercan a cero, habrá muy pocos resultados n - 1
en la última solución.