La fonction Javascript réécrite en Java donne des résultats différents

9

Il y a cette fonction Javascript que j'essaie de réécrire en Java:

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

Mon adaptation Java:

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

Quand je passe -1954896768, la version Javascript revient 70528, tandis que Java revient -896768. Je ne sais pas pourquoi. La différence semble commencer à l' intérieur de la si la condition: en fonction Javascript après si encodingRound2 = 2340070528, tout en Java: encodingRound2 = -1954896768.

J'ai fait ces réponses pour le montrer en ligne:

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

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

EDIT : modification de la fonction Java à ce

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

ne semble pas affecter le résultat - c'est toujours -896768

parsecer
la source
1
Pourquoi transformez-vous encondindRound2en un intdans le code Java? Puisqu'il est défini comme un long, vous allez potentiellement perdre en précision si vous le transformez en un type plus étroit.
Jordan
1
@Jordan car - à l'intérieur de l'if - il y a une opération au niveau du bit qui y est effectuée. Javascript, bien que stockant des nombres sous forme de flottants 64 bits, lors de l'exécution au niveau du bit, convertit les nombres en entiers 32 bits. J'ai eu ce problème avec un autre morceau de code avant, lorsque faire au niveau du bit avec Java longdonnait des résultats différents, à cause du débordement.
parsecer
Supprimer le (int)casting de la returnligne ne change pas le résultat Java, il reste-896768
parsecer
4
Ah, j'ai trouvé le problème. Lorsque vous poursuivez ... + 0x80000000, Java convertit la valeur en entier, car il 0x80000000est considéré comme un littéral int. Remplacez ce nombre par 0x80000000L.
Jordan
1
@Jordan Wow, tu es sorcier! Ça a marché! Veuillez poster votre réponse et je l'accepterai
parsecer

Réponses:

9

En Java, 0x80000000 est en dehors de la plage d'un int 32 bits, il se termine donc à -2147483648.

En JavaScript, 0x80000000 est bien à l'intérieur de la plage d'un double 64 bits, il reste donc 2147483648.

De toute évidence, l'ajout par -2147483648rapport à l'ajout 2147483648entraîne des écarts très importants.

Vous pouvez soit utiliser un long0x80000000L en Java, soit contraindre votre numéro JS en un int 32 bits avec (0x80000000|0), selon ce que vous voulez.

cet autre gars
la source
2

Essaye ça. Vous devez spécifier des valeurs longues lors de la conversion.

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

        return  (encondindRound2 % 1_000_000);
    }

Mais il y a un autre problème que vous devez connaître. Javascript est traité %comme un opérateur modulo alors que Java le traite comme un simple opérateur résiduel. Consultez cet article ici pour plus d'informations.

WJS
la source