Dili Tinuod nga Mga Feature sa Tinuod nga Mga Uri, o Pag-amping sa TINUOD

Human sa publikasyon mga artikulo bahin sa mga bahin sa pag-type sa PostgreSQL, ang una nga komento mao ang bahin sa mga kalisud sa pagtrabaho sa tinuud nga mga numero. Nakahukom ko nga tan-awon dayon ang code sa mga pangutana sa SQL nga magamit nako aron makita kung unsa ka sagad nila gigamit ang TINUOD nga tipo. Kini nahimo nga kini gigamit kanunay, ug ang mga developer dili kanunay nga makasabut sa mga kapeligrohan sa luyo niini. Ug kini bisan pa sa kamatuoran nga adunay daghang maayong mga artikulo sa Internet ug sa Habré bahin sa mga bahin sa pagtipig sa tinuud nga mga numero sa memorya sa kompyuter ug bahin sa pagtrabaho kauban nila. Busa, sa niini nga artikulo ako mosulay sa paggamit sa maong mga bahin ngadto sa PostgreSQL, ug mosulay sa pagkuha sa usa ka dali nga pagtan-aw sa mga kasamok nga nalangkit niini, aron nga kini mahimong mas sayon ​​alang sa SQL query developers sa paglikay kanila.

Ang dokumentasyon sa PostgreSQL nag-ingon: "Ang pagdumala sa ingon nga mga sayup ug ang ilang pagpadaghan sa panahon sa pagkuwenta mao ang hilisgutan sa usa ka tibuuk nga sanga sa matematika ug siyensya sa kompyuter, ug wala gilakip dinhi" (samtang maalamon nga gipunting ang magbabasa sa sumbanan sa IEEE 754). Unsang matang sa mga sayop ang gipasabot dinhi? Atong hisgotan sila sa han-ay, ug kini sa dili madugay mahimong tin-aw nganong gikuha ko pag-usab ang pluma.

Atong kuhaon pananglitan ang usa ka yano nga hangyo:

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

Ingon usa ka sangputanan, wala kami makakita bisan unsang espesyal - makuha namon ang gipaabut nga 0.1. Apan karon atong itandi kini sa 0.1:

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

Dili parehas! Unsang mga milagro! Apan dugang pa. Adunay moingon, I know that REAL behave badly with fractions, so I'll enter whole numbers there, and everything will sure be fine with them. Ok, ibutang nato ang numero nga 123 sa TINUOD:

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

Ug nahimo nga 3 pa! Mao na, ang database sa katapusan nakalimot unsaon pag-ihap! O nasayop ba kita sa pagsabot? Atong hisgotan kini.

Una, atong hinumdoman ang materyal. Sama sa imong nahibal-an, ang bisan unsang desimal nga numero mahimong mapalapad ngadto sa gahum sa napulo. Busa, ang numero nga 123.456 mahimong katumbas sa 1*102 + 2*101 + 3*100 + 4*10-1 + 5*10-2 + ​​6*10-3. Apan ang kompyuter naglihok nga adunay mga numero sa binary nga porma, busa kinahanglan silang irepresentar sa porma sa pagpalapad sa gahum sa duha. Busa, ang numero nga 5.625 sa binary girepresentahan isip 101.101 ug mahimong katumbas sa 1*22 + 0*21 + 1*20 + 1*2-1 + 0*2-2 + 1*2-3. Ug kung ang positibo nga mga gahum sa duha kanunay nga naghatag tibuuk nga mga numero sa desimal (1, 2, 4, 8, 16, ug uban pa), nan sa negatibo ang tanan mas komplikado (0.5, 0.25, 0.125, 0,0625, ug uban pa). Ang problema mao kana Dili tanang desimal mahimong irepresentar isip usa ka finite binary fraction. Busa, ang atong bantogang 0.1 sa porma sa binary fraction makita isip periodic value 0.0(0011). Tungod niini, ang katapusan nga kantidad niini nga numero sa memorya sa kompyuter magkalainlain depende sa gamay nga giladmon.

Karon ang panahon sa paghinumdom kung giunsa ang tinuud nga mga numero gitipigan sa memorya sa kompyuter. Sa kinatibuk-an, ang usa ka tinuod nga numero naglangkob sa tulo ka nag-unang mga bahin - sign, mantissa ug exponent. Ang ilhanan mahimo nga plus o minus, mao nga ang usa ka bit gigahin alang niini. Apan ang gidaghanon sa mga tipik sa mantissa ug exponent gitino sa tinuod nga tipo. Busa, alang sa TINUOD nga matang, ang gitas-on sa mantissa mao ang 23 bits (usa ka gamay nga katumbas sa 1 implicitly gidugang sa sinugdanan sa mantissa, ug ang resulta mao ang 24), ug ang exponent mao ang 8 bits. Ang kinatibuk-an mao ang 32 bits, o 4 bytes. Ug alang sa DOUBLE PRECISION type, ang gitas-on sa mantissa mahimong 52 bits, ug ang exponent mahimong 11 bits, alang sa total nga 64 bits, o 8 bytes. Wala gisuportahan sa PostgreSQL ang mas taas nga katukma alang sa mga numero sa floating point.

Atong i-pack ang atong decimal nga numero 0.1 ngadto sa TINUOD ug DOUBLE PECISION nga mga tipo. Tungod kay managsama ang timaan ug kantidad sa exponent, mag-focus kami sa mantissa (tinuyo nako nga gitangtang ang dili klaro nga mga bahin sa pagtipig sa mga kantidad sa exponent ug zero nga tinuud nga mga kantidad, tungod kay gikomplikado nila ang pagsabut ug pagkabalda gikan sa esensya. sa problema, kon interesado, tan-awa ang IEEE 754 standard). Unsay atong makuha? Sa taas nga linya akong ihatag ang "mantissa" alang sa TINUOD nga tipo (nga gikonsiderar ang paglibot sa katapusan nga gamay sa 1 sa labing duol nga representable nga numero, kung dili kini mahimong 0.099999 ...), ug sa ilawom nga linya - alang sa ang DOUBLE PECISION nga tipo:

0.000110011001100110011001101
0.00011001100110011001100110011001100110011001100110011001

Dayag nga kini duha ka lahi nga mga numero! Busa, kung itandi, ang una nga numero mapuno sa mga sero ug, busa, mas dako kaysa sa ikaduha (gikonsiderar ang paglibot - ang usa nga gimarkahan nga bold). Kini nagpatin-aw sa pagkadili klaro gikan sa atong mga panig-ingnan. Sa ikaduha nga pananglitan, ang tin-aw nga gipiho nga numero 0.1 gihulog sa DOUBLE PRECISION type, ug unya itandi sa usa ka numero sa TINUOD nga tipo. Ang duha gipamubu sa parehas nga tipo, ug kami adunay eksakto kung unsa ang among nakita sa taas. Atong usbon ang pangutana aron ang tanan mabutang sa lugar:

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

Ug sa tinuud, pinaagi sa paghimo sa usa ka doble nga pagkunhod sa numero nga 0.1 ngadto sa TINUOD ug DOUBLE PECISION, makuha namon ang tubag sa tigmo:

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

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

Kini usab nagpatin-aw sa ikatulo nga pananglitan sa ibabaw. Simple ra ang numero nga 123 imposible nga mahaum ang mantissa sa 24 bits (23 ang klaro + 1 ang gipasabot). Ang pinakataas nga integer nga mahimong mohaum sa 24 ka bits mao ang 224-1 = 16. Busa, ang atong numero nga 777 gilibot ngadto sa labing duol nga representable nga 215. Pinaagi sa pag-ilis sa tipo ngadto sa DOUBLE PRECISION, dili na nato makita kini nga senaryo:

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

Mao ra. Kini nahimo nga walay mga milagro. Apan ang tanan nga gihulagway usa ka maayong rason nga hunahunaon kung unsa ka kinahanglan nimo ang TINUOD nga tipo. Tingali ang pinakadako nga bentaha sa paggamit niini mao ang katulin sa mga kalkulasyon nga adunay nahibal-an nga pagkawala sa katukma. Apan mahimo ba kini nga usa ka unibersal nga senaryo nga maghatag katarungan sa kanunay nga paggamit sa kini nga tipo? Ayaw hunahunaa.

Source: www.habr.com

Idugang sa usa ka comment