Fungsi Javascript yang ditulis ulang di Jawa memberikan hasil yang berbeda

9

Ada fungsi Javascript yang saya coba tulis ulang di Java:

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

Adaptasi Java saya:

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

Ketika saya lulus -1954896768, versi Javascript kembali 70528, sedangkan Java kembali -896768. Saya tidak yakin mengapa. Perbedaannya tampaknya mulai dalam kondisi jika: dalam fungsi Javascript setelah jika encodingRound2 = 2340070528, sementara di Jawa: encodingRound2 = -1954896768.

Saya membuat balasan ini untuk ditampilkan secara online:

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

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

EDIT : Mengubah fungsi Java untuk ini

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

tampaknya tidak mempengaruhi hasilnya - masih -896768

parsecer
sumber
1
Mengapa Anda melakukan casting encondindRound2ke intdalam kode Java? Karena itu didefinisikan sebagai long, Anda akan berpotensi kehilangan presisi jika Anda melemparkannya ke tipe yang lebih sempit.
Jordan
1
@ Jordan karena - di dalam if - ada operasi bitwise yang dilakukan di atasnya. Javascript, meskipun menyimpan angka sebagai pelampung 64-bit, saat melakukan bitwise, mengubah angka menjadi bilangan bulat 32-bit. Saya memiliki masalah ini dengan potongan kode lain sebelumnya, ketika melakukan bitwise dengan Java longmemberikan hasil yang berbeda, karena overflow.
parsecer
Menghapus (int)gips dari returngaris tidak mengubah hasil Java, tetap-896768
parsecer
4
Ah, saya menemukan masalahnya. Ketika Anda melakukan tack ... + 0x80000000, Java mengkonversi nilai menjadi int, karena 0x80000000dianggap sebagai int literal. Ubah nomor itu menjadi 0x80000000L.
Jordan
1
@ Jordan Wow, kau penyihir! Berhasil! Silakan kirim jawaban Anda dan saya akan menerimanya
parsecer

Jawaban:

9

Di Jawa, 0x80000000 berada di luar kisaran int 32bit, sehingga membungkus ke -2147483648.

Dalam JavaScript, 0x80000000 berada dalam kisaran 64bit ganda, sehingga tetap 2147483648.

Jelas, menambahkan -2147483648vs menambahkan 2147483648hasil dalam perbedaan yang sangat besar.

Anda bisa menggunakan long0x80000000L di Java, atau memaksa nomor JS Anda ke int 32bit (0x80000000|0), tergantung yang Anda inginkan.

pria lain itu
sumber
2

Coba ini. Anda perlu menentukan nilai panjang dalam melakukan konversi.

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

        return  (encondindRound2 % 1_000_000);
    }

Tetapi ada masalah lain yang harus Anda waspadai. Javascript memperlakukan %sebagai operator modulo di mana Java memperlakukannya sebagai operator sisa sederhana. Lihat posting ini di sini untuk informasi lebih lanjut.

WJS
sumber