java - reales - La forma más rápida de verificar si dos enteros están en el mismo lado de 0
libro de android studio en español pdf (6)
Los enviaría por bit a int sin signo, y xo el MSB (bit más significativo) - mucho más rápido que cualquier comparación (que hace una resta) o multiplicación
Necesito verificar si dos enteros están en el mismo lado de cero muchas veces. No me importa si es positivo o negativo, solo que es el mismo lado ... y el rendimiento es muy importante.
Actualmente estoy haciendo esto:
if (int1 == 0 || int2 == 0) {
// handle zero
} else if ((int1 ^ int2) > 0) {
// different side
} else {
// same side
}
Esta es una mejora del 30% en la velocidad (probado con caliper ) en comparación con lo más obvio:
if ((int1 > 0 && int2 > 0) || (int1 < 0 && int2 < 0)) {
¿Se puede hacer más rápido?
Si alguien quiere ver el marco de prueba que estoy usando para el 30%, está aquí. Utilicé calibre 0.5-rc1
NOTA: Todas estas soluciones verifican el primer bit, básicamente, que para cero es lo mismo que un número positivo. Entonces, si eso funciona para su aplicación, no necesita hacer una comprobación de cero.
Lista de referencia:
- XOR: respuesta original con corrección de errores
- Ifs: Solución obvia
((&&)||(&&))
- Bits: la solución de @ hatchet
(>>31) == (>>31)
- BitAndXor: la solución de @ greedybuddha
(0x80000000)
- BitAndEquals: la solución de @ greedybuddha modificada para usar
==
no^
- XorShift: la solución de @ aaronman
(^)>>31 == 0
Salida de pinza:
0% Scenario{vm=java, trial=0, benchmark=XOR} 1372.83 ns; ?=7.16 ns @ 3 trials
17% Scenario{vm=java, trial=0, benchmark=Ifs} 2397.32 ns; ?=16.81 ns @ 3 trials
33% Scenario{vm=java, trial=0, benchmark=Bits} 1311.75 ns; ?=3.04 ns @ 3 trials
50% Scenario{vm=java, trial=0, benchmark=XorShift} 1231.24 ns; ?=12.11 ns @ 5 trials
67% Scenario{vm=java, trial=0, benchmark=BitAndXor} 1446.60 ns; ?=2.28 ns @ 3 trials
83% Scenario{vm=java, trial=0, benchmark=BitAndEquals} 1492.37 ns; ?=14.62 ns @ 3 trials
benchmark us linear runtime
XOR 1.37 =================
Ifs 2.40 ==============================
Bits 1.31 ================
XorShift 1.23 ===============
BitAndXor 1.45 ==================
BitAndEquals 1.49 ==================
vm: java
trial: 0
Parece que @aaronman es el ganador
Otra respuesta ...
final int i = int1 ^ int2;
if (i == 0 && int1 == 0) {
// both are zero
} else if (i & Integer.MIN_VALUE == Integer.MIN_VALUE) {
// signs differ
} else {
// same sign
}
Respuestas alternativas
Compara el bit de signo
return ((n >> 31) ^ (n2 >> 31) ) == 0 ? /* same */ : /* different */;
Manera alternativa de comparar bit de signo
return (((int1 & 0x80000000) ^ (int2 & 0x80000000))) == 0 ? /* same */ : /* different */;
y acabo de verificar, pero el código de Op es incorrecto cuando int1 == int2
. Lo siguiente siempre se imprimirá diferente si son lo mismo.
if (int1 == 0 || int2 == 0) {
// handle zero
} else if ((int1 ^ int2) < 0) {
// same side
} else {
// different side
}
(int1 ^ int2) >> 31 == 0 ? /*on same side*/ : /*different side*/ ;
Esto no necesariamente maneja 0 correctamente. No estoy seguro de lo que quería hacer en ese caso.
EDITAR: también quería señalar que si esto estuviera en c en lugar de java, podría optimizarse aún más eliminando el == 0
debido a la forma en que los booleanos trabajan en c, aunque los casos se cambiarían
int int1 = 3;
int int2 = 4;
boolean res = ( (int1 * int2) >= 0) ? true : false;
System.out.println(res);
if (int1 == 0 || int2 == 0) {
// handle zero
} else if ((int1 >> 31) == (int2 >> 31)) {
// same side
} else {
// different side
}
o
if (int1 == 0 || int2 == 0) {
// handle zero
} else if ((int1 & Integer.MIN_VALUE) == (int2 & Integer.MIN_VALUE)) {
// same side
} else {
// different side
}
La idea de ambos es la misma: elimine todo menos el bit de signo y, a continuación, compárelo para determinar la igualdad. No estoy seguro de cuál es más rápido, el cambio a la derecha (>>) o al bit y (&).