La función Javascript reescrita en Java da resultados diferentes

9

Existe esta función Javascript que estoy tratando de reescribir en Java:

function normalizeHash(encondindRound2) {
    if (encondindRound2 < 0) {
        encondindRound2 = (encondindRound2 & 0x7fffffff) + 0x80000000;
    }
    return encondindRound2 % 1E6;
}

Mi adaptación de Java:

public long normalizeHash(long encondindRound2) {
        if (encondindRound2 < 0) {
            encondindRound2 = (((int) encondindRound2) & 0x7fffffff) + 0x80000000;
        }
        return (((int) encondindRound2) % 1_000_000);
    }

Cuando paso -1954896768, la versión de Javascript regresa 70528, mientras que Java regresa -896768. No estoy seguro de por qué. La diferencia parece comenzar dentro de la condición if: en función Javascript después de que el caso encodingRound2 = 2340070528, mientras que en Java: encodingRound2 = -1954896768.

Hice estas respuestas para mostrarlo en línea:

Javascript : https://repl.it/repls/NumbGuiltyHack

Java : https://repl.it/repls/ClumsyQualifiedProblem

EDITAR : Cambiar la función de Java a esto

public long normalizeHash(long encondindRound2) {
        if (encondindRound2 < 0) {
            encondindRound2 = (encondindRound2 & 0x7fffffff) + 0x80000000;
        }
        return (encondindRound2 % 1_000_000);
    }

no parece afectar el resultado, sigue siendo -896768

analizador
fuente
1
¿Por qué estás enviando encondindRound2a un intcódigo Java? Como se define como a long, potencialmente perderá precisión si lo convierte en un tipo más estrecho.
Jordan
1
@Jordan porque, dentro del if, hay una operación bit a bit en él. Javascript, aunque almacena números como flotantes de 64 bits, al hacer bit a bit, convierte los números a enteros de 32 bits. Tuve este problema con otra pieza de código antes, cuando hacer bit a bit con Java longdio resultados diferentes, debido al desbordamiento.
analizador
Eliminar el (int)lanzamiento de la returnlínea no cambia el resultado de Java, permanece-896768
analizador
44
Ah, encontré el problema. Cuando agrega ... + 0x80000000, Java convierte el valor en int, porque 0x80000000se considera que es un literal int. Cambia ese número a 0x80000000L.
Jordan
1
@ Jordan Wow, eres un mago! ¡Funcionó!
Publique

Respuestas:

9

En Java, 0x80000000 está fuera del rango de 32 bits int, por lo que se ajusta a -2147483648.

En JavaScript, 0x80000000 está dentro del rango de un doble de 64 bits, por lo que sigue siendo 2147483648.

Obviamente, agregar -2147483648vs agregar 2147483648resultados en una gran discrepancia.

Puede usar un long0x80000000L en Java, o coaccionar su número JS en un int de 32 bits (0x80000000|0), según lo que desee.

ese otro chico
fuente
2

Prueba esto. Debe especificar valores largos al realizar la conversión.

    public static long normalizeHash(long encondindRound2) {
        if (encondindRound2 < 0) {
            encondindRound2 =  (encondindRound2 & 0x7fffffffL) + 0x80000000L;
        }

        return  (encondindRound2 % 1_000_000);
    }

Pero hay otro problema que debe tener en cuenta. Javascript trata %como un operador de módulo donde Java lo trata como un simple operador restante. Mira esta publicación aquí para más información.

WJS
fuente