Seorang kolega saya menemukan metode untuk meratakan angka float menggunakan bitwise atau:
var a = 13.6 | 0; //a == 13
Kami membicarakannya dan bertanya-tanya beberapa hal.
- Bagaimana cara kerjanya? Teori kami adalah bahwa menggunakan operator seperti itu melemparkan angka ke bilangan bulat, sehingga menghilangkan bagian fraksional
- Apakah ada kelebihan dibandingkan melakukannya
Math.floor
? Mungkin ini sedikit lebih cepat? (pun tidak dimaksudkan) - Apakah ada kekurangannya? Mungkin itu tidak berhasil dalam beberapa kasus? Kejelasan itu jelas, karena kami harus mengetahuinya, dan yah, saya menulis pertanyaan ini.
Terima kasih.
javascript
floating-point
bit-manipulation
Alex Turpin
sumber
sumber
3000000000.1 | 0
mengevaluasi ke -1294967296. Jadi metode ini tidak dapat diterapkan untuk perhitungan uang (terutama dalam kasus di mana Anda mengalikan dengan 100 untuk menghindari angka desimal).0.1 + 0.2 == 0.3
konsol JavaScript. Jika bahasa Anda mendukungnya, Anda harus menggunakan tipe desimal. Jika tidak, simpan sen sebagai gantinya.Jawaban:
Semua operasi bitwise kecuali pergeseran kanan yang tidak ditandatangani
>>>
,, bekerja pada bilangan bulat 32-bit yang telah ditandatangani. Jadi menggunakan operasi bitwise akan mengubah float menjadi integer.http://jsperf.com/or-vs-floor/2 tampaknya sedikit lebih cepat
Math.floor(NaN) === NaN
sementara(NaN | 0) === 0
sumber
Math.floor(NaN) === NaN
, sementara(NaN | 0) === 0
. Perbedaan itu mungkin penting dalam beberapa aplikasi.asm.js
(tempat saya pertama kali mempelajarinya). Lebih cepat jika tanpa alasan lain karena itu tidak memanggil fungsi padaMath
objek, fungsi yang bisa kapan saja diganti sepertiMath.floor = function(...)
.(value | 0) === value
dapat digunakan untuk memeriksa bahwa suatu nilai sebenarnya adalah bilangan bulat dan hanya bilangan bulat (seperti dalam kode sumber Elm @ dwayne-penjahat yang ditautkan). Danfoo = foo | 0
dapat digunakan untuk memaksa nilai apa pun ke integer (di mana angka 32-bit terpotong dan semua non-angka menjadi 0).Ini pemotongan karena bertentangan dengan lantai. Jawaban Howard agak benar; Tapi saya akan menambahkan bahwa
Math.floor
tidak persis apa yang seharusnya sehubungan dengan angka negatif. Secara matematis, itulah lantai itu.Dalam kasus yang Anda jelaskan di atas, programmer lebih tertarik memotong atau memotong desimal sepenuhnya. Meskipun, sintaks yang mereka gunakan agak mengaburkan fakta bahwa mereka mengubah float menjadi int.
sumber
Math.floor(8589934591.1)
menghasilkan hasil yang diharapkan,8589934591.1 | 0
JANGAN .Dalam ECMAScript 6, padanannya
|0
adalah Math.trunc , jenis yang harus saya katakan:sumber
Math.trunc()
bekerja dengan angka lebih tinggi atau sama dengan 2 ^ 31 dan| 0
tidakPoin pertama Anda benar. Angka dilemparkan ke bilangan bulat dan dengan demikian setiap angka desimal dihapus. Harap dicatat, bahwa
Math.floor
putaran ke bilangan bulat berikutnya menuju minus tak terhingga dan dengan demikian memberikan hasil yang berbeda ketika diterapkan pada angka negatif.sumber
Javascript mewakili
Number
sebagai angka mengambang ganda presisi 64-bit .Math.floor
bekerja dengan ini dalam pikiran.Operasi bitwise bekerja dalam bilangan bulat bertanda 32bit . Bilangan bulat 32bit yang ditandatangani menggunakan bit pertama sebagai penanda negatif dan 31 bit lainnya adalah angka. Karena itu, angka min dan maks yang diizinkan adalah angka 32bit yang ditandatangani adalah -2.147.483.648 dan 2147483647 (0x7FFFFFFFFFF), masing-masing.
Jadi, ketika Anda melakukannya
| 0
, pada dasarnya Anda lakukan& 0xFFFFFFFF
. Ini berarti, angka apa pun yang direpresentasikan sebagai 0x80000000 (2147483648) atau lebih besar akan kembali sebagai angka negatif.Sebagai contoh:
Juga. Operasi bitwise jangan "lantai". Mereka memotong , yang sama dengan mengatakan, mereka berkeliling paling dekat
0
. Setelah Anda berputar ke angka negatif,Math.floor
bulatkan ke bawah saat bitwise mulai membulatkan ke atas .Seperti yang saya katakan sebelumnya,
Math.floor
lebih aman karena beroperasi dengan angka mengambang 64bit. Bitwise lebih cepat , ya, tetapi terbatas pada lingkup 32bit yang ditandatangani.Untuk meringkas:
0 to 2147483647
.-2147483647 to 0
.-2147483648
dan lebih besar dari2147483647
.Jika Anda benar - benar ingin mengubah kinerja dan menggunakan keduanya:
Hanya untuk menambahkan
Math.trunc
karya seperti operasi bitwise. Jadi Anda bisa melakukan ini:sumber
Spesifikasi mengatakan bahwa itu dikonversi ke integer:
Kinerja: ini telah diuji di jsperf sebelumnya.
catatan: tautan mati ke spec dihapus
sumber