Переписанная на Java функция Javascript дает разные результаты

9

Есть эта функция Javascript, которую я пытаюсь переписать в Java:

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

Моя адаптация Java:

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

Когда я передаю -1954896768, возвращается версия Javascript 70528, а возвращается Java -896768. Я не уверен почему. Разница , кажется, начинается внутри , если условие: в функции Javascript , если после того , как encodingRound2 = 2340070528, в то время как в Java: encodingRound2 = -1954896768.

Я сделал эти repls, чтобы показать это онлайн:

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

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

РЕДАКТИРОВАТЬ : изменение функции Java на это

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

кажется, не влияет на результат - это все еще -896768

parsecer
источник
1
Почему вы encondindRound2приводите intв код Java? Поскольку он определен как a long, вы потенциально потеряете точность, если приведете его к более узкому типу.
Джордан
1
@Jordan, потому что - внутри if - выполняется побитовая операция. Javascript, хотя и хранит числа в виде 64-разрядных чисел с плавающей запятой, при выполнении побитового преобразования преобразует числа в 32-разрядные целые числа. У меня была эта проблема с другим фрагментом кода раньше, когда побитовое выполнение с Java longдавало разные результаты из-за переполнения.
парсер
Удаление (int)приведения из returnстроки не меняет результат Java, оно остается-896768
парсер
4
Ах, я нашел проблему. Когда вы подключаетесь ... + 0x80000000, Java преобразует значение в int, потому что 0x80000000считается литералом int. Измените это число на 0x80000000L.
Джордан
1
@ Джордан Вау, ты волшебник! Это сработало! Пожалуйста,
оставьте

Ответы:

9

В Java 0x80000000 находится вне диапазона 32-битного типа int, поэтому он оборачивается до -2147483648.

В JavaScript 0x80000000 находится в пределах 64-битного двойного, поэтому остается 2147483648.

Очевидно, что добавление -2147483648против добавления 2147483648приводит к очень большому расхождению.

Вы можете использовать long 0x80000000L в Java, либо преобразовать свой номер JS в 32-битное целое число в (0x80000000|0)зависимости от того, что вы хотите.

тот другой парень
источник
2

Попробуй это. Вы должны указать длинные значения при выполнении преобразования.

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

        return  (encondindRound2 % 1_000_000);
    }

Но есть еще одна проблема, о которой вы должны знать. Javascript рассматривается %как оператор по модулю, а Java - как простой оператор остатка. Проверьте этот пост здесь для получения дополнительной информации.

WJS
источник