Adakah terdapat masalah dengan pengiraan titik terapung?
P粉071602406
2023-08-20 16:48:26
<p>Pertimbangkan kod berikut: </p>
<pre class="brush:js;toolbar:false;">0.1 + 0.2 == 0.3 ->
</pra>
<pre class="brush:js;toolbar:false;">0.1 + 0.2 ->
</pra>
<p>Mengapakah ketidaktepatan ini berlaku? </p>
Perspektif Pereka Perkakasan
Saya fikir saya perlu menambah perspektif pereka perkakasan, kerana saya mereka bentuk dan membina perkakasan titik terapung. Mengetahui asal usul ralat boleh membantu memahami perkara yang berlaku dalam perisian, dan akhirnya, saya berharap ini akan menjelaskan mengapa ralat titik terapung berlaku dan nampaknya terkumpul dari semasa ke semasa.
1. Gambaran keseluruhan
Dari perspektif kejuruteraan, kebanyakan operasi titik terapung akan mengalami sedikit ralat kerana perkakasan yang melakukan pengiraan titik terapung hanya memerlukan kurang daripada setengah unit ralat dalam bit terakhir. Oleh itu, kebanyakan perkakasan hanya akan berhenti pada ketepatan dan hanya perlu menghasilkan ralat kurang daripada setengah unit bit terakhir, yang amat bermasalah dalam pembahagian titik terapung. Apa yang membentuk satu operasi bergantung kepada bilangan operan yang diterima oleh unit. Untuk kebanyakan unit, ini ialah dua operan, tetapi sesetengah unit menerima 3 atau lebih operan. Oleh itu, tiada jaminan bahawa operasi berulang akan menghasilkan ralat yang ideal, kerana ralat terkumpul dari semasa ke semasa.
2
Kebanyakan pemproses mengikut piawaiIEEE-754, tetapi sesetengahnya menggunakan piawaian yang tidak normal atau berbeza. Sebagai contoh, terdapat mod penyahnormalan dalam IEEE-754 yang membenarkan perwakilan nombor titik terapung yang sangat kecil dengan mengorbankan ketepatan. Walau bagaimanapun, kandungan berikut akan merangkumi mod biasa IEEE-754, yang merupakan mod operasi biasa.
Dalam piawai IEEE-754, pereka perkakasan boleh membenarkan sebarang nilai ralat/ε asalkan kurang daripada setengah unit bit terakhir, dan hasilnya mestilah kurang daripada setengah unit bit terakhir hanya untuk satu operasi. Ini menerangkan sebab ralat terkumpul apabila operasi diulang. Untuk ketepatan berganda IEEE-754, ini adalah bit 54 kerana terdapat 53 bit yang digunakan untuk mewakili bahagian berangka (normalisasi) nombor titik terapung, juga dipanggil mantissa (cth. 5.3 dalam 5.3e5). Beberapa bahagian seterusnya membincangkan punca ralat perkakasan dalam pelbagai operasi titik terapung dengan lebih terperinci.(ditambah beberapa bit pilihan).
Z=X/Y
和Z = X * (1/Y)
中。除法是迭代计算的,即每个周期计算一些商的位数,直到达到所需的精度,对于IEEE-754来说,这是任何误差小于最后一位的一个单位的情况。Y的倒数表(1/Y)被称为慢除法中的商选择表(QST),商选择表的位数通常是基数的宽度,或者在每次迭代中计算的商的位数加上几个保护位。对于IEEE-754标准的双精度(64位),它将是除法器的基数大小加上几个保护位k,其中k>=2
。因此,例如,一个典型的每次计算2位商(基数为4)的除法器的商选择表将是2+2= 4
3.1 Ralat pembundaran bahagian: penghampiran timbal balik
Timbal balik dalam jadual pemilihan quotient bergantung pada kaedah bahagi: pembahagian perlahan (seperti pembahagian SRT) atau pembahagian pantas (seperti pembahagian Goldschmidt); setiap entri diubah suai mengikut algoritma pembahagian untuk menghasilkan ralat yang paling rendah. Walau apa pun, semua timbal balik adalah hampiran salingan sebenar dan memperkenalkan tahap kesilapan. Kedua-dua kaedah pembahagian perlahan dan cepat mengira hasil bahagi secara berulang, iaitu sebilangan digit hasil bahagi tertentu dikira pada setiap langkah, hasilnya kemudian ditolak daripada dividen dan pembahagi mengulangi langkah ini sehingga ralat kurang daripada setengah unit digit terakhir. Kaedah pembahagian perlahan mengira bilangan digit hasil bahagi yang tetap pada setiap langkah dan secara amnya lebih murah, manakala kaedah pembahagian pantas mengira nombor pembolehubah digit hasil pada setiap langkah dan secara amnya lebih mahal. Bahagian yang paling penting dalam kaedah bahagi ialah kebanyakannya bergantung pada pendaraban berulang penghampiran kepada timbal balik dan oleh itu terdedah kepada ralat.
4. Ralat pembulatan dalam operasi lain: pemotongan
Satu lagi punca ralat pembundaran dalam semua operasi ialah mod pemangkasan berbeza yang dibenarkan oleh IEEE-754. Terdapat potong, bulat ke arah sifar, bulat (lalai) , bulat ke bawah dan bulat ke atas. Semua kaedah memperkenalkan ralat kurang daripada unit bit terakhir, untuk satu operasi. Dari masa ke masa dan operasi berulang, pemotongan juga terkumpul ke dalam ralat yang terhasil. Ralat pemotongan ini amat bermasalah dalam aritmetik eksponen, yang melibatkan beberapa bentuk pendaraban berulang.
5. Ulangi operasi
Memandangkan perkakasan yang melakukan pengiraan titik terapung hanya perlu menghasilkan hasil dalam satu operasi yang kurang daripada setengah unit ralat dalam bit terakhir, jika tidak dipantau, ralat akan berkembang apabila operasi diulang. Inilah sebabnya mengapa dalam pengiraan yang memerlukan ralat terhad, ahli matematik menggunakan kaedah seperti menggunakan pembundaran nombor genap digit terakhir dalam IEEE-754, kerana ralat lebih berkemungkinan untuk membatalkan satu sama lain dari semasa ke semasa, serta menggabungkan Perubahan dalam Aritmetik Selang dan Mod Pembundaran IEEE 754 untuk meramal ralat pembundaran dan membetulkannya. Membundarkan kepada digit genap terdekat (digit terakhir) ialah mod pembundaran lalai IEEE-754 disebabkan oleh ralat relatif yang lebih rendah berbanding dengan mod pembundaran lain.
Sila ambil perhatian bahawa mod pembundaran lalai, membundarkan kepada angka genap yang terdekat, menjamin operasi dengan ralat kurang daripada setengah unit digit terakhir. Gunakan hanya potong, bulatkan dan bulatkan ke bawah
BinariTitik terapungBegitulah cara matematik berfungsi. Dalam kebanyakan bahasa pengaturcaraan, ia adalah berdasarkan IEEE 754 standard. Intinya ialah nombor diwakili dalam format ini sebagai integer dikali kuasa dua nombor rasional yang penyebutnya bukan kuasa dua (seperti
0.1
,即1/10
) tidak boleh diwakili dengan tepat.Untuk standard
binary64
格式中的0.1
, representasinya boleh ditulis betul-betul seperti0.1000000000000000055511151231257827021181583404541015625
0x1.999999999999ap-4
Sebaliknya, nombor rasional
0.1
,即1/10
, boleh ditulis tepat seperti0.1
0x1.99999999999999...p-4
,其中...
Mewakili urutan 9s yang tidak berkesudahan.Pemalar
0.2
dan0.3
dalam program anda juga akan menganggarkan nilai sebenar mereka. Kebetulan bahawadouble
yang paling hampir dengan0.2
adalah lebih besar daripada nombor rasional0.2
, tetapidouble
yang paling hampir kepada0.3
code>adalah kurang daripada nombor rasional0.3
. Jumlah0.2
和0.3
也将近似于它们的真实值。恰好,最接近0.2
的double
大于有理数0.2
,但最接近0.3
的double
小于有理数0.3
。0.1
和0.2
的和最终比有理数0.3
dan0.2
akhirnya menjadi lebih besar daripada nombor rasional0.3
dan oleh itu tidak konsisten dengan pemalar dalam kod.Rawatan yang agak menyeluruh bagi masalah aritmetik titik terapung ialah Perkara Setiap Saintis Komputer Patut Tahu Mengenai Aritmetik Titik Terapung. Untuk penjelasan yang lebih mudah difahami, lihat floating-point-gui.de.
Masalah yang sama wujud dengan nombor perpuluhan biasa (asas 10), itulah sebabnya nombor seperti 1/3 akhirnya menjadi 0.333333333...
Anda baru sahaja terjumpa nombor (3/10) yang mudah diwakili dalam sistem perpuluhan, tetapi tidak boleh diwakili dalam sistem binari. Sebaliknya juga benar (setakat satu tahap): 1/16 ialah nombor hodoh dalam perpuluhan (0.0625), tetapi dalam binari ia kelihatan sama kemas seperti satu persepuluh ribu dalam perpuluhan (0.0001)* * - Jika kita biasa menggunakan sistem nombor binari dalam kehidupan harian kita, anda akan melihat nombor itu dan secara naluri memahami bahawa anda boleh mendapatkannya dengan sentiasa membahagikan dengan 2.
Sudah tentu, ini bukan cara nombor terapung disimpan dalam ingatan (ia menggunakan bentuk tatatanda saintifik). Walau bagaimanapun, ia menggambarkan bahawa ralat ketepatan titik terapung binari cenderung timbul kerana nombor "dunia nyata" yang biasanya kita minati cenderung kepada kuasa sepuluh - tetapi itu hanya kerana kita menggunakan sistem nombor perpuluhan pada hari ke- asas hari. Itulah sebabnya kami mengatakan 71% dan bukannya "5 daripada setiap 7" (71% ialah anggaran kerana 5/7 tidak boleh diwakili dengan tepat oleh sebarang nombor perpuluhan).
Jadi tidak, tidak ada yang salah dengan nombor titik terapung binari, ia hanya tidak sempurna seperti sistem nombor asas N yang lain :)
Dalam amalan, isu ketepatan ini bermakna anda perlu menggunakan fungsi pembundaran untuk membundarkan nombor titik terapung kepada bilangan tempat perpuluhan yang anda minati sebelum memaparkannya.
Anda juga perlu menggantikan ujian tanda sama dengan perbandingan yang membenarkan toleransi tertentu, yang bermaksud:
Jangan guna
if (x == y) { ... }
Gunakan
if (abs(x - y) < myToleranceValue) { ... }
sebaliknya.Manakah
abs
是绝对值函数。myToleranceValue
perlu dipilih berdasarkan aplikasi khusus anda, ia mempunyai banyak kaitan dengan berapa banyak "ruang goyang" yang anda sediakan untuk membenarkan dan bilangan maksimum yang akan anda bandingkan (kerana isu kehilangan ketepatan). Berhati-hati dengan pemalar gaya "epsilon" dalam bahasa pilihan anda. Pemalar ini boleh digunakan sebagai nilai toleransi, tetapi keberkesanannya bergantung pada saiz nombor yang anda hadapi, kerana pengiraan dengan nombor yang besar mungkin melebihi ambang epsilon.