Tvrdíte, že v číslech s pohyblivou řádovou čárkou jsou přirozené nepřesnosti. Myslím, že si to zaslouží, abychom to nejprve trochu prozkoumali.
Při rozhodování o číselné soustavě pro znázornění čísla (ať už na kousku papíru, v počítačovém obvodu nebo jinde) existují dva oddělené problémy ke zvážení:
-
jeho základ; a
-
jeho formát .
Vyberte základnu, jakoukoli základnu…
Omezeno konečným prostorem, nelze reprezentovat libovolný člen nekonečné množiny
. Například:bez ohledu na to, kolik papíru si koupíte nebo jak malý je váš rukopis, vždy bude možné najít celé číslo, které se nevejde do daného prostoru (můžete prostě přidávat další číslice, dokud papír nedojde). Tedy s celými čísly , obvykle omezujeme svůj konečný prostor na reprezentaci pouze těch, které spadají do nějakého konkrétního intervalu – např. pokud máme místo pro kladné/záporné znaménko a tři číslice, můžeme se omezit na interval [-999,+999]
.
Každý neprázdné interval
obsahuje nekonečnou množinu reálných čísel. Jinými slovy, bez ohledu na to, v jakém intervalu se přebírají reálná čísla —ať už je to [-999,+999]
, [0,1]
, [0.000001,0.000002]
nebo cokoli jiného – v tomto intervalu stále existuje nekonečná množina reálných hodnot (stačí pouze přidávat (nenulové) desetinné číslice)! Libovolná reálná čísla proto musí vždy být „zaokrouhleno“ na něco, co může být reprezentován v konečném prostoru.
Množina reálných čísel, která mohou být reprezentována v konečném prostoru, závisí na použité číselné soustavě. V našem (známém) poziční
základ-10
systému bude konečný prostor stačit na jednu polovinu (0.510
), ale ne za jednu třetinu (0.33333…10
); naopak v (méně známé) poziční základě-9
systému, je to naopak (stejná čísla jsou v tomto pořadí 0.44444…9
a 0.39
). Důsledkem toho všeho je, že některá čísla, která mohou být reprezentována s použitím pouze malého prostoru v pozičním základu-10 (a proto se objevují být k nám lidem velmi „kulatý“), kupř. jedna desetina, by ve skutečnosti vyžadovalo přesné uložení nekonečných binárních obvodů (a proto se našim digitálním přátelům nezdají být příliš „kulaté“)! Je pozoruhodné, že protože 2 je faktor 10, totéž neplatí obráceně:jakékoli číslo, které lze reprezentovat konečnou dvojkovou soustavou, lze také reprezentovat konečnou desítkovou soustavou.
Pro kontinuální množství nemůžeme udělat nic lepšího. Nakonec takové veličiny musí používat konečnou reprezentaci v nějakých číselná soustava:je libovolné, zda je tento systém náhodou snadný na počítačových obvodech, na lidských prstech, na něčem jiném nebo vůbec na ničem – ať už se použije kterýkoli systém, hodnota musí být zaokrouhlený a proto vždy výsledkem je "chyba reprezentace".
Jinými slovy, i když máme dokonale přesný měřicí přístroj (což je fyzicky nemožné), pak každé měření, které uvádí, bude již zaokrouhleno na číslo, které se náhodou vejde na jeho displej (v jakémkoliv základu, který používá – ze zřejmých důvodů obvykle v desítkové soustavě). Takže „86,2 oz“ ve skutečnosti nikdy není „86,2 oz “, ale spíše reprezentace „něco mezi 86,1500000... oz a 86,2499999... oz ". (Ve skutečnosti, protože ve skutečnosti je nástroj nedokonalý, můžeme opravdu říci jen to, že máme nějaký míra důvěry že skutečná hodnota spadá do tohoto intervalu – ale to se rozhodně poněkud odchyluje od tohoto bodu).
Ale pro diskrétní množství to můžeme udělat lépe . Takové hodnoty nejsou „libovolná reálná čísla“, a proto se na ně nevztahuje nic z výše uvedeného:mohou být reprezentovány přesně v číselné soustavě, ve které byly definovány – a skutečně by měly být (protože převod na jinou číselnou soustavu a zkrácení na konečnou délku by mělo za následek zaokrouhlení na nepřesné číslo). Počítače mohou takové situace (neefektivně) řešit tak, že číslo reprezentují jako řetězec:např. zvažte ASCII nebo BCD kódování.
Použít formát…
Vzhledem k tomu, že se jedná o vlastnost (poněkud libovolného) základu číselné soustavy, to, zda se hodnota jeví jako „kulatá“, nemá žádný vliv na její přesnost . To je skutečně důležité pozorování , což je v rozporu s intuicí mnoha lidí (a to je důvod, proč jsem strávil tolik času vysvětlováním číselných základů výše).
Přesnost je místo toho určena kolikem významných čísel
reprezentace má . Potřebujeme formát úložiště, který dokáže zaznamenat naše hodnoty alespoň tolik významných čísel, jak je považujeme za správné . Vezměme si jako příklad hodnoty, které považujeme za správné, když jsou uvedeny jako 86.2
a 0.0000862
, dvě nejběžnější možnosti jsou:
-
Pevný bod , kde počet platných číslic závisí na velikosti :např. v pevné reprezentaci na 5 desetinných míst by naše hodnoty byly uloženy jako
86.20000
a0.00009
(a proto mají 7 a 1 platné číslice přesnosti). V tomto příkladu došlo ke ztrátě přesnosti v té druhé hodnotě (a skutečně by to netrvalo o moc víc, abychom nebyli úplně schopni reprezentovat nic význam); a dřívější uložená hodnota falešná přesnost , což je plýtvání naším konečným prostorem (a skutečně by to netrvalo o moc víc, aby se hodnota stala tak velkou, že přeteče úložnou kapacitu).Běžným příkladem, kdy může být tento formát vhodný, je účetní systém:peněžní částky musí být obvykle sledovány do centů bez ohledu na jejich velikost (proto je vyžadována menší přesnost pro malé hodnoty a větší přesnost je vyžadována pro velké hodnoty). Jak už to tak bývá, měna je obvykle také považována za diskrétní (haléře jsou nedělitelné), takže je to také dobrý příklad situace, kdy je žádoucí konkrétní základ (desetinný u většiny moderních měn), aby se předešlo chybám v reprezentaci diskutovaným výše.
-
Plovoucí desetinná čárka , kde je počet platných číslic konstantní bez ohledu na velikost :např. v desítkové reprezentaci s 5 platnými číslicemi by naše hodnoty byly uloženy jako
86.200
a0.000086200
(a podle definice mít v obou případech 5 platných číslic přesnosti). V tomto příkladu byly obě hodnoty uloženy bez jakékoli ztráty přesnosti; a oba mají také stejné množství s falešnou přesností, což je méně plýtvání (a proto můžeme využít náš konečný prostor k reprezentaci mnohem většího rozsahu hodnot – velkých i malých).Běžným příkladem, kdy může být tento formát vhodný, je záznam jakýchkoli skutečných měření :přesnost měřicích přístrojů (které všechny trpí jak systematičností a náhodné chyby) je poměrně konstantní bez ohledu na měřítko, takže při dostatečném počtu platných číslic (obvykle kolem 3 nebo 4 číslic) se neztrácí absolutně žádná přesnost i když změna základu vedla k zaokrouhlení na jiné číslo .
Ale jak přesné jsou formáty úložiště s plovoucí desetinnou čárkou používané našimi počítači?
-
IEEE754 jednoduchá přesnost (binární32) s plovoucí desetinnou čárkou číslo má 24 bitů, neboli
."log10(2)
(více než 7) číslic, důležitých – tzn. má toleranci menší než±0.000006%
. Jinými slovy, je to přesnější než říkat „86.20000
". -
IEEE754 dvojitá přesnost (binary64) s plovoucí desetinnou čárkou číslo má 53 bitů, neboli
."log10(2)
(téměř 16) číslic, významných — tzn. má toleranci těsně nad±0.00000000000001%
. Jinými slovy, je to přesnější než říkat „86.2000000000000
".
Nejdůležitější je si uvědomit, že těchto formátů je přes deset tisíc a více než jeden bilion krát přesnější než říkat „86,2“ – i když přesné převody binárního kódu zpět na desítkové náhodou obsahují chybnou falešnou přesnost (kterou musíme ignorovat:více o tom brzy)!
-
Všimněte si také, že obě opraveno a Formáty s plovoucí desetinnou čárkou budou mít za následek ztrátu přesnosti, pokud je hodnota známa přesněji, než formát podporuje. Takové chyby zaokrouhlování
se může šířit v aritmetických operacích a přinášet zjevně chybné výsledky (což nepochybně vysvětluje váš odkaz na „vlastní nepřesnosti“ čísel s plovoucí desetinnou čárkou):například ⁄3 × 3000
v 5místném pevném bodu by bylo dosaženo 999.99000
spíše než 1000.00000
; a ⁄7 − ⁄50
v 5 významných číslicích s plovoucí desetinnou čárkou by dalo 0.0028600
spíše než 0.0028571
.
Oblast numerická analýza se věnuje pochopení těchto efektů, ale je důležité si uvědomit, že jakýkoli použitelný systém (dokonce i provádění výpočtů ve vaší hlavě) je vůči takovým problémům zranitelný, protože žádná metoda výpočtu, která se zaručeně ukončí, nemůže nikdy nabídnout nekonečnou přesnost :zvažte například, jak vypočítat plochu kruhu – nezbytně dojde ke ztrátě přesnosti v hodnotě použité pro π, která se promítne do výsledku.
Závěr
-
Měření v reálném světě by mělo používat binární pohyblivou řádovou čárku :je to rychlé, kompaktní, extrémně přesné a o nic horší než cokoli jiného (včetně desetinné verze, ze které jste začínali). Protože datové typy MySQL s pohyblivou řádovou čárkou jsou IEEE754, to je přesně to, co nabízejí.
-
Aplikace měn by měly používat denáry s pevným bodem :i když je pomalý a plýtvá pamětí, zajišťuje, že hodnoty nebudou zaokrouhleny na nepřesná množství a že se při velkých peněžních částkách neztratí ani haléře. Protože datové typy MySQL s pevným bodem jsou řetězce kódované BCD, to je přesně to, co nabízejí.
A konečně mějte na paměti, že programovací jazyky obvykle představují zlomkové hodnoty pomocí binárních čísel s pohyblivou řádovou čárkou typy:takže pokud vaše databáze ukládá hodnoty v jiném formátu, musíte být opatrní, jak jsou přeneseny do vaší aplikace, jinak mohou být převedeny (se všemi z toho vyplývajícími problémy) v rozhraní.
Která možnost je v tomto případě nejlepší?
Doufám, že jsem vás přesvědčil, že vaše hodnoty mohou bezpečně (a měly by ) být uloženy v plovoucí řádové čárce, aniž byste se příliš obávali o nějaké "nepřesnosti"? Pamatujte, že jich je více přesnější, než kdy bylo vaše chatrné 3-platné desetinné zastoupení:stačí ignorovat falešnou přesnost (ale musíte vždy udělejte to přesto, i když používáte formát s pevnou desetinnou čárkou).
Pokud jde o vaši otázku:vyberte možnost 1 nebo 2 před možností 3 – usnadňuje to porovnávání (například pro nalezení maximální hmotnosti stačí použít MAX(mass)
, zatímco k efektivnímu provedení ve dvou sloupcích by bylo zapotřebí určité vnoření).
Mezi těmito dvěma nezáleží na tom, který z nich si vybere – čísla s pohyblivou řádovou čárkou jsou uložena s konstantním počtem platných bitů bez ohledu na jejich měřítko .
Kromě toho, zatímco v obecném případě by se mohlo stát, že některé hodnoty jsou zaokrouhleny na binární čísla, která jsou blíže jejich původnímu desítkovému vyjádření pomocí možnosti 1, zatímco jiné jsou současně zaokrouhlena na binární čísla, která jsou blíže jejich původnímu desítkovému vyjádření pomocí možnosti 2, jako zakrátko uvidíme takové chyby reprezentace, které se projeví pouze v rámci falešné přesnosti, která by měla být vždy ignorována.
Nicméně v tomto v případě, protože se stává, že existuje 16 uncí na 1 libru (a 16 je mocnina 2), relativní rozdíly mezi původními desetinnými hodnotami a uloženými binárními čísly pomocí těchto dvou přístupů jsou identické :
-
5.387510
(nikoli5.3367187510
jak je uvedeno ve vaší otázce) bude uloženo v binárním 32 float jako101.0110001100110011001102
(což je5.3874998092651367187510
):toto je0.0000036%
z původní hodnoty (ale, jak bylo diskutováno výše, "původní hodnota" už byla dost mizerná reprezentace fyzikální veličiny, kterou představuje).Vzhledem k tomu, že binární 32 float uchovává pouze 7 desetinných míst s přesností, náš kompilátor to ví s jistotou že vše od 8. číslice výše je určitě falešná přesnost, a proto musí být ignorován v každém case – tedy za předpokladu, že naše vstupní hodnota nevyžadovala větší přesnost (a pokud ano, binary32 byla zjevně špatná volba formátu), toto zaručuje návrat k desetinné hodnotě, která vypadá stejně kulatě jako ta, ze které jsme začali:
5.38750010
. Měli bychom však skutečně použít znalosti domény v tomto bodě (jako bychom měli u jakéhokoli formátu úložiště) zahodit jakoukoli další falešnou přesnost, která by mohla existovat, jako jsou tyto dvě koncové nuly. -
86.210
bude uloženo v binárním32 float jako1010110.001100110011001102
(což je86.199996948242187510
):toto je také0.0000036%
z původní hodnoty. Stejně jako předtím pak ignorujeme falešnou přesnost, abychom se vrátili k původnímu zadání.
Všimněte si, že binární reprezentace čísel jsou totožné, kromě umístění radixového bodu (což je čtyři bity od sebe):
101.0110 00110011001100110 101 0110.00110011001100110
Je to proto, že 5,3875 × 2 =86,2.