La funzione Javascript riscritta in Java dà risultati diversi


9

C'è questa funzione Javascript che sto cercando di riscrivere in Java:

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

Il mio adattamento Java:

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

Quando passo -1954896768, la versione di Javascript ritorna 70528, mentre Java ritorna -896768. Non sono sicuro del perché. La differenza sembra iniziare all'interno del se la condizione: in funzione Javascript dopo il caso encodingRound2 = 2340070528, mentre in Java: encodingRound2 = -1954896768.

Ho fatto queste sostituzioni per mostrarlo online:

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

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

EDIT : Modifica della funzione Java in questo

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

non sembra influenzare il risultato - è ancora -896768


1
Perché esegui il casting encondindRound2in un intcodice Java? Dal momento che è definito come a long, potresti perdere potenzialmente la precisione se lo esegui su un tipo più stretto.
Giordania,

1
@Jordan perché - all'interno dell'if - è in esecuzione un'operazione bit a bit. Javascript, sebbene memorizzi i numeri come float a 64 bit, quando fa bit a bit, converte i numeri in numeri interi a 32 bit. Ho avuto questo problema con un altro pezzo di codice prima, quando facevo bit a bit con Java ha longdato risultati diversi, a causa dell'overflow.
parsecer

Rimuovere il (int)cast dalla returnlinea non cambia il risultato Java, rimane-896768
parsecer

4
Ah, ho trovato il problema. Quando si attacca ... + 0x80000000, Java converte il valore in un int, perché 0x80000000è considerato un letterale int. Cambia quel numero in 0x80000000L.
Giordania,

1
@Jordan Wow, sei un mago! Ha funzionato!
Pubblica la

Risposte:


9

In Java, 0x80000000 è al di fuori dell'intervallo di un int a 32 bit, quindi si avvolge a -2147483648.

In JavaScript, 0x80000000 è ben all'interno dell'intervallo di un doppio a 64 bit, quindi rimane 2147483648.

Ovviamente, aggiungendo -2147483648vs aggiungendo 2147483648risultati in una discrepanza molto grande.

Puoi usare uno long0x80000000L in Java o forzare il tuo numero JS in un int a 32 bit (0x80000000|0), a seconda di quale vuoi.


2

Prova questo. È necessario specificare valori lunghi durante la conversione.

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

        return  (encondindRound2 % 1_000_000);
    }

Ma c'è un altro problema che dovresti conoscere. Javascript considera %un operatore modulo mentre Java lo tratta come un semplice operatore residuo. Dai un'occhiata a questo post qui per maggiori informazioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.