Fitur Ora Nyata saka Jinis Nyata, utawa Ati-ati karo REAL

Sawise publikasi artikel babagan fitur ngetik ing PostgreSQL, komentar sing pisanan yaiku babagan kesulitan nggarap angka nyata. Aku mutusaké kanggo njupuk dipikir cepet ing kode saka pitakonan SQL kasedhiya kanggo kula kanggo ndeleng carane asring padha nggunakake jinis REAL. Pranyata metu sing digunakake cukup asring, lan pangembang ora tansah ngerti beboyo konco iku. Lan iki senadyan kasunyatan manawa ana cukup akeh artikel apik ing Internet lan ing Habré babagan fitur nyimpen nomer nyata ing memori komputer lan babagan nggarap. Mulane, ing artikel iki aku bakal nyoba kanggo aplikasi fitur kuwi kanggo PostgreSQL, lan bakal nyoba kanggo njupuk dipikir cepet ing masalah sing digandhengake karo wong-wong mau, supaya iku bakal luwih gampang kanggo pangembang query SQL supaya wong-wong mau.

Dokumentasi PostgreSQL nyatakake kanthi ringkes: "Manajemen kesalahan kasebut lan panyebaran sajrone komputasi minangka subyek kabeh cabang matematika lan ilmu komputer, lan ora ana ing kene" (nalika kanthi wicaksana ngrujuk maca menyang standar IEEE 754). Apa jenis kesalahan sing dimaksud ing kene? Ayo padha rembugan ing urutan, lan bakal dadi cetha apa aku njupuk maneh pulpen.

Ayo dadi conto panjalukan prasaja:

********* ЗАПРОС *********
SELECT 0.1::REAL;
**************************
float4
--------
    0.1
(1 строка)

Akibaté, kita ora bakal weruh apa-apa khusus - kita bakal entuk 0.1 samesthine. Nanging saiki ayo mbandhingake karo 0.1:

********* ЗАПРОС *********
SELECT 0.1::REAL = 0.1;
**************************
?column?
----------
f
(1 строка)

Ora padha! Apa mukjijat! Nanging luwih, luwih. Wong bakal ngomong, Aku ngerti sing REAL tumindak ala karo pecahan, aku bakal ngetik nomer wutuh ana, lan kabeh mesthi bakal nggoleki karo wong-wong mau. Oke, ayo nyelehake nomer 123 menyang REAL:

********* ЗАПРОС *********
SELECT 123456789::REAL::INT;
**************************
   int4   
-----------
123456792
(1 строка)

Lan dadi 3 liyane! Wis, database akhire lali carane ngitung! Utawa kita misunderstanding soko? Ayo dadi tokoh metu.

Kaping pisanan, ayo ngelingi materi. Kaya sing sampeyan ngerteni, nomer desimal apa wae bisa ditambahi dadi sepuluh. Dadi, nomer 123.456 bakal padha karo 1*102 + 2*101 + 3*100 + 4*10-1 + 5*10-2 + ​​6*10-3. Nanging komputer makaryakke karo nomer ing wangun binar, mulane padha kudu dituduhake ing wangun expansion ing kakuwasan saka loro. Mulane, angka 5.625 ing binar dituduhake minangka 101.101 lan bakal padha karo 1*22 + 0*21 + 1*20 + 1*2-1 + 0*2-2 + 1*2-3. Lan yen kakuwasan positif saka loro tansah menehi nomer desimal wutuh (1, 2, 4, 8, 16, etc.), banjur karo negatif kabeh luwih rumit (0.5, 0.25, 0.125, 0,0625, etc.). Masalahe yaiku Ora saben desimal bisa diwakili minangka pecahan biner sing winates. Mangkono, 0.1 kondhang kita ing wangun pecahan binar katon minangka nilai periodik 0.0(0011). Akibaté, nilai final saka nomer iki ing memori komputer bakal beda-beda gumantung ing ambane dicokot.

Saiki iki wektu kanggo ngelingi carane nomer nyata disimpen ing memori komputer. Umumé, nomer nyata dumadi saka telung bagean utama - tandha, mantissa lan eksponen. Tandha kasebut bisa ditambah utawa dikurangi, mula disedhiyakake siji bit. Nanging jumlah bit mantissa lan eksponen ditemtokake dening jinis nyata. Dadi, kanggo jinis REAL, dawa mantissa yaiku 23 bit (siji sing padha karo 1 ditambahake kanthi implisit ing wiwitan mantissa, lan asile 24), lan eksponen yaiku 8 bit. Gunggunge 32 bit, utawa 4 bita. Lan kanggo jinis DOUBLE PRECISION, dawa mantissa bakal dadi 52 bit, lan eksponen bakal dadi 11 bit, kanthi total 64 bit, utawa 8 bita. PostgreSQL ora ndhukung presisi sing luwih dhuwur kanggo angka floating point.

Ayo bungkus nomer desimal 0.1 dadi jinis REAL lan DOUBLE PRECISION. Amarga tandha lan nilai eksponen padha, kita bakal fokus ing mantissa (aku sengaja ngilangi fitur sing ora jelas kanggo nyimpen nilai eksponen lan nol nyata, amarga padha rumit pangerten lan ngganggu saka inti. saka masalah, yen kasengsem, ndeleng IEEE 754 standar). Apa sing bakal kita entuk? Ing baris ndhuwur aku bakal menehi "mantissa" kanggo jinis REAL (njupuk menyang akun babak saka bit pungkasan dening 1 kanggo nomer paling cedhak representable, digunakake bakal 0.099999 ...), lan ing ngisor baris - kanggo Tipe DOUBLE PRECISION:

0.000110011001100110011001101
0.00011001100110011001100110011001100110011001100110011001

Temenan iki rong nomer temen beda! Mulane, nalika mbandhingake, nomer pisanan bakal dilapisi karo nul lan, mulane, bakal luwih gedhe tinimbang nomer loro (nyatane dibunderake - sing ditandhani kanthi kandel). Iki nerangake ambiguitas saka conto kita. Ing conto kapindho, nomer 0.1 sing ditemtokake kanthi tegas dibuwang menyang jinis PRESISI GANDA, banjur dibandhingake karo sawetara jinis REAL. Loro-lorone dikurangi dadi jinis sing padha, lan kita duwe persis apa sing kita deleng ing ndhuwur. Ayo ngowahi pitakon supaya kabeh bisa ditrapake:

********* ЗАПРОС *********
SELECT 0.1::REAL > 0.1::DOUBLE PRECISION;
**************************
?column?
----------
t
(1 строка)

Lan pancen, kanthi nindakake pangurangan kaping pindho nomer 0.1 dadi REAL lan PRESISI GANDA, kita entuk jawaban kanggo teka-teki:

********* ЗАПРОС *********
SELECT 0.1::REAL::DOUBLE PRECISION;
**************************

      float8       
-------------------
0.100000001490116
(1 строка)

Iki uga nerangake conto katelu ing ndhuwur. Nomer 123 prasaja iku mokal kanggo pas mantissa menyang 24 bit (23 eksplisit + 1 diwenehake). Integer maksimum sing bisa pas menyang 24 bit yaiku 224-1 = 16. Mulane, nomer kita 777 dibunderaké menyang representable paling cedhak 215. Kanthi ngganti jinis dadi DOUBLE PRECISION, kita ora bisa ndeleng skenario iki maneh:

********* ЗАПРОС *********
SELECT 123456789::DOUBLE PRECISION::INT;
**************************
   int4   
-----------
123456789
(1 строка)

Mekaten. Pranyata ora ana kaelokan. Nanging kabeh sing diterangake minangka alesan sing apik kanggo mikir babagan sampeyan butuh jinis REAL. Mbok kauntungan paling gedhe saka nggunakake punika kacepetan petungan karo mundhut dikenal saka akurasi. Nanging apa iki bakal dadi skenario universal sing bakal mbenerake panggunaan jinis iki? Aja mikir.

Source: www.habr.com

Add a comment