A função Javascript reescrita em Java fornece resultados diferentes

9

Existe esta função Javascript que estou tentando reescrever em Java:

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

Minha adaptação Java:

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

Quando passo -1954896768, a versão Javascript retorna 70528, enquanto Java retorna -896768. Não sei por que. A diferença parece começar dentro da condição if: em função Javascript após o caso encodingRound2 = 2340070528, enquanto em Java: encodingRound2 = -1954896768.

Fiz essas réplicas para mostrá-lo on-line:

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

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

EDIT : Alterando a função Java para este

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

parece não afetar o resultado - ainda é -896768

parsecer
fonte
11
Por que você está convertendo encondindRound2para um intno código Java? Como é definido como a long, você provavelmente perderá precisão se a converter para um tipo mais restrito.
Jordan
11
@ Jordânia porque - dentro do if - há uma operação bit a bit sendo executada nele. Javascript, embora armazene números como flutuadores de 64 bits, ao fazer bit a bit, converte números em números inteiros de 32 bits. Eu tive esse problema com outro trecho de código antes, ao fazer bit a bit com Java longdeu resultados diferentes, por causa do estouro.
parsecer 30/01
Remover o (int)elenco da returnlinha não altera o resultado do Java, ele permanece-896768
parsecer 30/01
4
Ah, eu encontrei o problema. Quando você adere ... + 0x80000000, Java converte o valor em um int, porque 0x80000000é considerado um literal int. Mude esse número para 0x80000000L.
Jordan
11
@ Jordan Wow, você é um mago! Funcionou! Por favor, poste sua resposta e eu a aceito
parsecer 30/01

Respostas:

9

Em Java, 0x80000000 está fora do intervalo de um int de 32 bits e, portanto, se aproxima de -2147483648.

No JavaScript, 0x80000000 está bem dentro do intervalo de um dobro de 64 bits e permanece 2147483648.

Obviamente, adicionar -2147483648vs adicionar 2147483648resulta em uma discrepância muito grande.

Você pode usar um long0x80000000L em Java ou coagir seu número JS em um int de 32 bits (0x80000000|0), dependendo do que você deseja.

aquele outro cara
fonte
2

Tente isso. Você precisa especificar valores longos ao fazer a conversão.

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

        return  (encondindRound2 % 1_000_000);
    }

Mas há outro problema que você deve estar ciente. O Javascript trata %como um operador de módulo, enquanto o Java o trata como um operador simples de restante. Confira este post aqui para mais informações.

WJS
fonte