3 回答

TA貢獻(xiàn)1831條經(jīng)驗(yàn) 獲得超4個(gè)贊
這是我懷疑時(shí)發(fā)現(xiàn)的。
mysql> create table numbers (a decimal(10,2), b float);
mysql> insert into numbers values (100, 100);
mysql> select @a := (a/3), @b := (b/3), @a * 3, @b * 3 from numbers \G
*************************** 1. row ***************************
@a := (a/3): 33.333333333
@b := (b/3): 33.333333333333
@a + @a + @a: 99.999999999000000000000000000000
@b + @b + @b: 100
十進(jìn)制確實(shí)完成了對(duì)這種情況應(yīng)該做的事情,它截?cái)嗔似溆嗖糠?,從而失去?/3部分。
因此,對(duì)于總和,小數(shù)點(diǎn)更好,但對(duì)于除法,浮點(diǎn)數(shù)更好,當(dāng)然還有一些點(diǎn)。我的意思是,使用DECIMAL不會(huì)以任何方式為您提供“失敗證明算術(shù)”。
希望這可以幫助。

TA貢獻(xiàn)1813條經(jīng)驗(yàn) 獲得超2個(gè)贊
大多數(shù)環(huán)境中的“浮點(diǎn)”是二進(jìn)制浮點(diǎn)類型。它可以準(zhǔn)確地存儲(chǔ)base-2值(到某個(gè)點(diǎn)),但不能準(zhǔn)確存儲(chǔ)許多base-10(十進(jìn)制)值。浮子最適合科學(xué)計(jì)算。它們不適合大多數(shù)面向商業(yè)的數(shù)學(xué)運(yùn)算,不合適地使用花車會(huì)讓你感到困惑。許多十進(jìn)制值無法在base-2中精確表示。0.1
例如,你不能看到像這樣的奇怪結(jié)果1.0 - 0.1 = 0.8999999
。
小數(shù)存儲(chǔ)基數(shù)為10的數(shù)字。對(duì)于大多數(shù)商業(yè)數(shù)學(xué)而言,十進(jìn)制是一個(gè)很好的類型(但任何內(nèi)置的“貨幣”類型更適合于財(cái)務(wù)計(jì)算),其中值的范圍超過整數(shù)類型提供的值,并且需要小數(shù)值。顧名思義,小數(shù)是為基數(shù)10設(shè)計(jì)的 - 它們可以準(zhǔn)確地存儲(chǔ)十進(jìn)制值(再次,到某一點(diǎn))。

TA貢獻(xiàn)1911條經(jīng)驗(yàn) 獲得超7個(gè)贊
MySQL最近改變了他們存儲(chǔ)DECIMAL類型的方式。在過去,他們?yōu)槊總€(gè)數(shù)字存儲(chǔ)字符(或nybbles),包括數(shù)字的ASCII(或nybble)表示 - vs - 二進(jìn)制補(bǔ)碼整數(shù)或其衍生物。
DECIMAL的當(dāng)前存儲(chǔ)格式是一系列1,2,3或4字節(jié)整數(shù),其位被連接以創(chuàng)建帶有隱含小數(shù)點(diǎn)的二進(jìn)制補(bǔ)碼數(shù),由您定義,并在您聲明時(shí)存儲(chǔ)在DB模式中列,并指定它的DECIMAL大小和小數(shù)點(diǎn)位置。
舉例來說,如果你采用32位int,你可以存儲(chǔ)0 - 4,294,967,295之間的任何數(shù)字。這只能可靠地覆蓋999,999,999,所以如果你扔出2位并使用(1 << 30 -1)你就什么也不放棄。僅使用4個(gè)字節(jié)覆蓋所有9位數(shù)字比使用4個(gè)ASCII字符或8個(gè)nybble數(shù)字覆蓋32位中的4位數(shù)字更有效。(一個(gè)nybble是4位,允許值0-15,超過0-9所需的值,但你不能通過轉(zhuǎn)到3位來消除這種浪費(fèi),因?yàn)樗缓w0-7的值)
MySQL在線文檔中使用的示例使用DECIMAL(18,9)作為示例。這比隱含小數(shù)點(diǎn)前面的9位數(shù)字和9位數(shù)字要短,如上所述,需要以下存儲(chǔ)空間。
18個(gè)8位字符:144位
作為18個(gè)4位nybbles:72位
作為2個(gè)32位整數(shù):64位
目前DECIMAL最多支持65位數(shù)字,如DECIMAL(M,D),其中M允許的最大值為65,D允許的最大值為30。
為了不一次要求9位數(shù)的塊,小于32位的整數(shù)用于使用1,2和3字節(jié)整數(shù)來添加數(shù)字。出于某種原因,無視邏輯,使用了簽名而不是無符號(hào)的int,并且這樣做,1位被拋出,從而產(chǎn)生以下存儲(chǔ)能力。對(duì)于1,2和4字節(jié)的整數(shù),丟失的位無關(guān)緊要,但對(duì)于3字節(jié)的int來說,這是一場(chǎng)災(zāi)難,因?yàn)檎麄€(gè)數(shù)字由于丟失了這一位而丟失。
使用7位int:0 - 99
使用15位int:0 - 9,999
使用23位int:0 - 999,999(0 - 9,999,999,帶有24位int)
1,2,3和4字節(jié)整數(shù)連接在一起形成“位池”DECIMAL用于將數(shù)字精確地表示為二進(jìn)制補(bǔ)碼整數(shù)。小數(shù)點(diǎn)未存儲(chǔ),暗示。
這意味著數(shù)據(jù)庫(kù)引擎不需要ASCII到int轉(zhuǎn)換就可以將“數(shù)字”轉(zhuǎn)換為CPU識(shí)別為數(shù)字的內(nèi)容。沒有舍入,沒有轉(zhuǎn)換錯(cuò)誤,它是CPU可以操作的實(shí)數(shù)。
對(duì)這個(gè)任意大整數(shù)的計(jì)算必須在軟件中完成,因?yàn)檫@種數(shù)字沒有硬件支持,但這些庫(kù)非常陳舊且經(jīng)過高度優(yōu)化,已在50年前編寫,以支持IBM 370 Fortran任意精度浮點(diǎn)數(shù)據(jù)。它們?nèi)匀槐仁褂肅PU整數(shù)硬件完成的固定大小整數(shù)代數(shù)慢,或者在FPU上進(jìn)行浮點(diǎn)計(jì)算。
就存儲(chǔ)效率而言,因?yàn)閒loat的指數(shù)附加到每個(gè)浮點(diǎn)數(shù),隱含地指定小數(shù)點(diǎn)的位置,所以它是大量冗余的,因此對(duì)DB工作來說效率低。在數(shù)據(jù)庫(kù)中,您已經(jīng)知道小數(shù)點(diǎn)的位置在前面,并且表中具有DECIMAL列值的每一行只需要查看該小數(shù)點(diǎn)的放置位置的唯一規(guī)范,存儲(chǔ)在模式中作為DECIMAL(M,D)的參數(shù)作為M和D值的含義。
這里發(fā)現(xiàn)的關(guān)于哪種格式用于各種應(yīng)用程序的許多評(píng)論是正確的,所以我不會(huì)強(qiáng)調(diào)這一點(diǎn)。我花時(shí)間在這里寫這篇文章,因?yàn)闊o論是誰維護(hù)鏈接的MySQL在線文檔都不理解上述任何內(nèi)容,并且經(jīng)過多次令人沮喪的嘗試向他們解釋它后,我放棄了。很好地表明他們對(duì)所寫內(nèi)容的理解程度有多差,這是對(duì)主題的非?;靵y和難以理解的表現(xiàn)。
最后,如果您需要高精度浮點(diǎn)計(jì)算,過去20年浮點(diǎn)代碼已經(jīng)取得了巨大進(jìn)步,96位和四倍精度浮點(diǎn)數(shù)的硬件支持即將到來,但是如果存儲(chǔ)值的操作很重要,那么有很好的任意精度庫(kù)。
添加回答
舉報(bào)