Функція Javascript, переписана на Java, дає різні результати


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. Я не впевнений, чому. Здається, різниця починається всередині умови if: у функції Javascript після if encodingRound2 = 2340070528, тоді як у Java : encodingRound2 = -1954896768.

Я зробив ці відповіді, щоб показати це в Інтернеті:

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

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

EDIT : Зміна функції Java на цю

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

не здається, що це впливає на результат - все одно -896768


1
Чому ви кастинг encondindRound2на intв коді Java? Оскільки це визначено як "a" long, ви потенційно втратите точність, якщо відкинете його на більш вузький тип.
Йордан

1
@ Джордан, тому що - всередині if - на ньому виконується побітова операція. Javascript, хоча зберігає числа як 64-бітові плаваючі, при виконанні побітових перетворень перетворює числа в 32-бітні цілі числа. Я мав цю проблему з іншим фрагментом коду раніше, коли побіжно з Java використовували longрізні результати через переповнення.
розбір

Видалення (int)return-896768
амплітуди

4
Ах, я знайшов проблему. Під час включення ... + 0x80000000Java перетворює значення в int, оскільки 0x80000000вважається int буквалом. Змініть це число на 0x80000000L.
Йорданія

1
@Jordan Wow, ти майстер! Це спрацювало! Будь ласка, опублікуйте свою відповідь, і я прийму її
розбір

Відповіді:


9

У Java 0x80000000 знаходиться поза діапазоном 32-бітового int, тому він обертається до -2147483648.

У JavaScript 0x80000000 добре знаходиться в діапазоні 64-бітового подвійного, тому він залишається 2147483648.

Очевидно, що додавання -2147483648vs додавання 2147483648призводить до дуже великої невідповідності.

Ви можете або використовувати long0x80000000L на Java, або примусити свій JS номер в 32-бітовий int (0x80000000|0), залежно від того, який ви хочете.


2

Спробуйте це. Вам потрібно вказати довгі значення при здійсненні конверсії.

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

        return  (encondindRound2 % 1_000_000);
    }

Але є ще одне питання, про яке слід знати. Javascript розглядає %як оператор модуля, де Java трактує його як простий оператор, що залишився. Перегляньте цю публікацію тут для отримання додаткової інформації.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.