Nodweddion Afreal o Mathau Go Iawn, neu Byddwch yn ofalus gyda REAL

Ar ôl ei gyhoeddi erthyglau am nodweddion teipio yn PostgreSQL, roedd y sylw cyntaf un yn ymwneud ag anawsterau gweithio gyda rhifau real. Penderfynais edrych yn gyflym ar god yr ymholiadau SQL sydd ar gael i mi i weld pa mor aml maen nhw'n defnyddio'r math REAL. Mae'n ymddangos ei fod yn cael ei ddefnyddio'n eithaf aml, ac nid yw datblygwyr bob amser yn deall y peryglon y tu ôl iddo. A hyn er gwaethaf y ffaith bod cryn dipyn o erthyglau da ar y Rhyngrwyd ac ar Habré am nodweddion storio rhifau real yng nghof y cyfrifiadur ac am weithio gyda nhw. Felly, yn yr erthygl hon byddaf yn ceisio cymhwyso nodweddion o'r fath i PostgreSQL, a byddaf yn ceisio edrych yn gyflym ar y trafferthion sy'n gysylltiedig â nhw, fel y bydd yn haws i ddatblygwyr ymholiad SQL eu hosgoi.

Mae dogfennaeth PostgreSQL yn nodi’n gryno: “Mae rheoli gwallau o’r fath a’u lluosogi yn ystod cyfrifiant yn destun cangen gyfan o fathemateg a chyfrifiadureg, ac nid yw wedi’i gynnwys yma” (tra’n cyfeirio’r darllenydd yn ddoeth at safon IEEE 754). Pa fath o wallau a olygir yma? Gadewch i ni eu trafod mewn trefn, a buan iawn y daw'n amlwg pam y cymerais y gorlan eto.

Gadewch i ni gymryd er enghraifft cais syml:

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

O ganlyniad, ni welwn unrhyw beth arbennig - byddwn yn cael y 0.1 disgwyliedig. Ond nawr gadewch i ni ei gymharu â 0.1:

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

Ddim yn gyfartal! Pa wyrthiau! Ond ymhellach, mwy. Bydd rhywun yn dweud, gwn fod REAL yn ymddwyn yn wael gyda ffracsiynau, felly byddaf yn nodi rhifau cyfan yno, a bydd popeth yn bendant yn iawn gyda nhw. Iawn, gadewch i ni fwrw'r rhif 123 i REAL:

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

Ac roedd yn troi allan i fod yn 3 arall! Dyna ni, mae'r bas data o'r diwedd wedi anghofio sut i gyfri! Neu a ydym yn camddeall rhywbeth? Gadewch i ni chyfrif i maes.

Yn gyntaf, gadewch i ni gofio'r materiel. Fel y gwyddoch, gellir ehangu unrhyw rif degol i bwerau o ddeg. Felly, bydd y rhif 123.456 yn hafal i 1 * 102 + 2 * 101 + 3 * 100 + 4 * 10-1 + 5 * 10-2 + ​​6 * 10-3. Ond mae'r cyfrifiadur yn gweithredu gyda rhifau ar ffurf ddeuaidd, felly mae'n rhaid iddynt gael eu cynrychioli ar ffurf ehangu pwerau dau. Felly, cynrychiolir y rhif 5.625 mewn deuaidd fel 101.101 a bydd yn hafal i 1*22 + 0*21 + 1*20 + 1*2-1 + 0*2-2 + 1*2-3. Ac os yw pwerau positif dau bob amser yn rhoi rhifau degol cyfan (1, 2, 4, 8, 16, ac ati), yna gyda rhai negyddol mae popeth yn fwy cymhleth (0.5, 0.25, 0.125, 0,0625, ac ati). Y broblem yw hynny Ni ellir cynrychioli pob degolyn fel ffracsiwn deuaidd meidraidd. Felly, mae ein 0.1 drwg-enwog ar ffurf ffracsiwn deuaidd yn ymddangos fel y gwerth cyfnodol 0.0(0011). O ganlyniad, bydd gwerth terfynol y rhif hwn yng nghof y cyfrifiadur yn amrywio yn dibynnu ar y dyfnder did.

Nawr yw'r amser i gofio sut mae rhifau real yn cael eu storio yng nghof y cyfrifiadur. Yn gyffredinol, mae rhif real yn cynnwys tair prif ran - arwydd, mantissa ac esboniwr. Gall yr arwydd fod naill ai plws neu finws, felly neilltuir un darn ar ei gyfer. Ond y math go iawn sy'n pennu nifer y darnau o'r mantissa a'r esboniwr. Felly, ar gyfer y math REAL, hyd y mantissa yw 23 did (mae un did yn hafal i 1 yn cael ei ychwanegu'n ymhlyg at ddechrau'r mantissa, a'r canlyniad yw 24), ac mae'r esboniwr yn 8 did. Y cyfanswm yw 32 did, neu 4 beit. Ac ar gyfer y math PRECISION DWBL, bydd hyd y mantissa yn 52 did, a'r esboniwr fydd 11 did, am gyfanswm o 64 did, neu 8 beit. Nid yw PostgreSQL yn cefnogi manylder uwch ar gyfer rhifau pwynt arnawf.

Gadewch i ni bacio ein rhif degol 0.1 i fathau DARPARU GO IAWN a DWBL. Gan fod arwydd a gwerth yr esboniwr yr un fath, byddwn yn canolbwyntio ar y mantissa (rwyf yn hepgor yn fwriadol y nodweddion nad ydynt yn amlwg o storio gwerthoedd yr esboniwr a sero gwerthoedd real, gan eu bod yn cymhlethu dealltwriaeth ac yn tynnu sylw oddi wrth yr hanfod o'r broblem, os oes gennych ddiddordeb, gweler safon IEEE 754). Beth gawn ni? Yn y llinell uchaf byddaf yn rhoi'r “mantissa” ar gyfer y math REAL (gan gymryd i ystyriaeth talgrynnu'r did olaf gan 1 i'r rhif cynrychioliadwy agosaf, fel arall bydd yn 0.099999...), ac yn y llinell waelod - ar gyfer y math MANYLION DWBL:

0.000110011001100110011001101
0.00011001100110011001100110011001100110011001100110011001

Yn amlwg mae'r rhain yn ddau rif hollol wahanol! Felly, wrth gymharu, bydd y rhif cyntaf yn cael ei badio â sero ac, felly, yn fwy na'r ail (gan ystyried talgrynnu - yr un sydd wedi'i farcio mewn print trwm). Mae hyn yn egluro'r amwysedd o'n hesiamplau. Yn yr ail enghraifft, mae'r rhif penodol 0.1 yn cael ei fwrw i'r math PRECISION DWBL, ac yna'n cael ei gymharu â nifer o'r math REAL. Mae'r ddau yn cael eu lleihau i'r un math, ac mae gennym yn union yr hyn a welwn uchod. Gadewch i ni addasu'r ymholiad fel bod popeth yn disgyn i'w le:

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

Ac yn wir, trwy berfformio gostyngiad dwbl o'r rhif 0.1 i MANWERTHU REAL a DWBL, rydym yn cael yr ateb i'r pos:

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

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

Mae hyn hefyd yn esbonio'r drydedd enghraifft uchod. Mae'r rhif 123 yn syml mae'n amhosib ffitio'r mantissa yn 24 did (23 amlwg + 1 ymhlyg). Y cyfanrif uchaf a all ffitio i 24 did yw 224-1 = 16 Felly, mae ein rhif 777 yn cael ei dalgrynnu i'r 215 agosaf y gellir ei gynrychioli.

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

Dyna i gyd. Mae'n troi allan nad oes unrhyw wyrthiau. Ond mae popeth a ddisgrifir yn rheswm da i feddwl faint rydych chi wir angen y math REAL. Efallai mai mantais fwyaf ei ddefnydd yw cyflymder cyfrifiadau y gwyddys eu bod yn colli cywirdeb. Ond a fyddai hon yn senario cyffredinol a fyddai'n cyfiawnhau defnydd mor aml o'r math hwn? Peidiwch â meddwl.

Ffynhonnell: hab.com

Ychwanegu sylw