Rumah > hujung hadapan web > tutorial js > Di luar JavaScript - Mengapa tidak sama dalam pengaturcaraan

Di luar JavaScript - Mengapa tidak sama dalam pengaturcaraan

DDD
Lepaskan: 2024-09-13 22:17:02
asal
995 orang telah melayarinya

JavaScript sering diejek apabila pembangun mula-mula menemui hasil yang kelihatan membingungkan ini:

0.1 + 0.2 == 0.30000000000000004
Salin selepas log masuk

Meme tentang pengendalian nombor JavaScript tersebar luas, sering menyebabkan ramai percaya bahawa tingkah laku ini unik kepada bahasa tersebut.

Beyond JavaScript - Why     doesn

Walau bagaimanapun, kebiasaan ini bukan sahaja terhad kepada JavaScript. Ini adalah akibat daripada cara kebanyakan bahasa pengaturcaraan mengendalikan aritmetik titik terapung.

Sebagai contoh, berikut ialah coretan kod daripada Java dan Go yang menghasilkan hasil yang serupa:

Beyond JavaScript - Why     doesn

Beyond JavaScript - Why     doesn

Komputer secara asli hanya boleh menyimpan integer. Mereka tidak faham pecahan. (Bagaimanakah mereka? Satu-satunya cara komputer boleh melakukan aritmetik ialah dengan menghidupkan atau mematikan beberapa lampu. Lampu boleh sama ada dihidupkan atau dimatikan. Ia tidak boleh "separuh" menyala!) Mereka memerlukan beberapa cara untuk mewakili nombor titik terapung . Oleh kerana perwakilan ini tidak tepat dengan sempurna, lebih kerap daripada tidak, 0.1 0.2 tidak sama dengan 0.3.

Semua pecahan yang penyebutnya terdiri daripada faktor perdana asas sistem nombor boleh dinyatakan dengan bersih manakala mana-mana pecahan lain akan mempunyai perpuluhan berulang. Sebagai contoh, dalam sistem nombor dengan asas 10, pecahan seperti 1/2, 1/4, 1/5, 1/10 diwakili dengan jelas kerana penyebut dalam setiap kes terdiri daripada 2 atau 5 - faktor perdana 10 . Bagaimanapun, pecahan seperti 1/3, 1/6, 1/7 semuanya mempunyai perpuluhan berulang.

Begitu juga, dalam pecahan sistem binari seperti 1/2, 1/4, 1/8 dinyatakan dengan bersih manakala semua pecahan lain mempunyai perpuluhan berulang. Apabila anda melakukan aritmetik pada perpuluhan berulang ini, anda akan mendapat sisa yang terbawa apabila anda menukar perwakilan binari nombor komputer kepada perwakilan asas-10 yang boleh dibaca manusia. Inilah yang membawa kepada hasil yang lebih kurang betul.

Sekarang kami telah menetapkan bahawa masalah ini bukan eksklusif untuk JavaScript, mari kita terokai cara nombor titik terapung diwakili dan diproses di bawah hud untuk memahami sebab gelagat ini berlaku.

Untuk memahami cara nombor titik terapung diwakili dan diproses di bawah hud, kami perlu memahami piawaian titik terapung IEEE 754 terlebih dahulu.

Piawaian IEEE 754 ialah spesifikasi yang digunakan secara meluas untuk mewakili dan melaksanakan aritmetik pada nombor titik terapung dalam sistem komputer. Ia dicipta untuk menjamin ketekalan apabila menggunakan aritmetik titik terapung pada pelbagai platform pengkomputeran. Kebanyakan bahasa pengaturcaraan dan pelaksanaan perkakasan (CPU, GPU, dll.) mematuhi standard ini.

Beginilah cara nombor dilambangkan dalam format IEEE 754:

Beyond JavaScript - Why     doesn

Di sini s ialah bit tanda (0 untuk positif, 1 untuk negatif), M ialah mantissa (memegang digit nombor) dan E ialah eksponen yang menentukan skala nombor.

Anda tidak akan dapat mencari sebarang nilai integer untuk M dan E yang betul-betul boleh mewakili nombor seperti 0.1, 0.2 atau 0.3 dalam format ini. Kami hanya boleh memilih nilai untuk M dan E yang memberikan hasil yang paling hampir.

Berikut ialah alat yang boleh anda gunakan untuk menentukan Notasi IEEE 754 nombor perpuluhan: https://www.h-schmidt.net/FloatConverter/IEEE754.html

IEEE 754 tatatanda 0.25:

Beyond JavaScript - Why     doesn

IEEE 754 tatatanda 0.1 dan 0.2 masing-masing:

Beyond JavaScript - Why     doesn
Beyond JavaScript - Why     doesn

Sila ambil perhatian bahawa ralat disebabkan penukaran dalam kes 0.25 ialah 0, manakala 0.1 dan 0.2 mempunyai ralat bukan sifar.

IEEE 754 mentakrifkan format berikut untuk mewakili nombor titik terapung:

  • Ketepatan tunggal (32-bit): 1 bit untuk tanda, 8 bit untuk eksponen, 23 bit untuk mantissa

  • Ketepatan dua kali (64-bit): 1 bit untuk tanda, 11 bit untuk eksponen, 52 bit untuk mantissa

Demi kesederhanaan, mari kita pertimbangkan format ketepatan tunggal yang menggunakan 32 bit.

Perwakilan 32 bit 0.1 ialah:

0 01111011 10011001100110011001101
Salin selepas log masuk

Here the first bit represents the sign (0 which means positive in this case), the next 8 bits (01111011) represent the exponent and the final 23 bits (10011001100110011001101) represent the mantissa.

This is not an exact representation. It represents ≈ 0.100000001490116119384765625

Similarly, the 32 bit representation of 0.2 is:

0 01111100 10011001100110011001101
Salin selepas log masuk

This is not an exact representation either. It represents ≈ 0.20000000298023223876953125

When added, this results in:

0 01111101 11001101010011001100110 
Salin selepas log masuk

which is ≈ 0.30000001192092896 in decimal representation.

In conclusion, the seemingly perplexing result of 0.1 + 0.2 not yielding 0.3 is not an anomaly specific to JavaScript, but a consequence of the limitations of floating-point arithmetic across programming languages. The roots of this behaviour lie in the binary representation of numbers, which inherently leads to precision errors when handling certain fractions.

Atas ialah kandungan terperinci Di luar JavaScript - Mengapa tidak sama dalam pengaturcaraan. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan