剖析金額不能用浮點數表示的原因

2021-09-19 11:37:59 字數 2731 閱讀 1361

近期參與到了乙個金融專案,開發十分的謹慎。先丟擲我有問題的**,作用是把以分為單位的金額轉成以元為單位的字串。

long adjustfee;string.valueof(adjustfee / 100.0);
很自信的以為這行**簡潔明瞭的完成了使命。同事review了我的**後,指出這段**會造成精度丟失的問題。先演示乙個demo,構造乙個浮點數丟失精度的場景。

@test    public

void

addtest()         system.out.println(clone);        system.out.println(clone == d);    }

程式輸出結果

9.223372036854776e189.223372036854776e18true
輸出結果足以顛覆三觀。乙個雙精度浮點數,加了10億之後,居然沒有發生任何變化!如果在金融專案裡發生這種事,何止是直接被fire掉,蹲監獄都是可能的。這類 問題其根本原因在於浮點數在計算機內部的表示方法。這種ieee標準表示法兼顧了資料的精度和大小。

摘自網上。學過《計算機組成原理》的同學都知道,32位的浮點數由3部分組成:1位元的符號位,8位元的階碼(exponent,指數),23位元的尾數(mantissa,尾數)。這個結構會表示成乙個小數點左邊為1,以底數為2的科學計數法表示的二進位制小數。浮點數的能表示的資料大小範圍由階碼決定,但是能夠表示的精度完全取決於尾數的長度。long的最大值是2的64次方減1,需要63個二進位制位表示,即便是double,52位的尾數也無法完整的表示long的最大值。不能表示的部分也就只能被捨去了。對於金額,捨去不能表示的部分,損失也就產生了。

了解了浮點數表示機制後,丟失精度的現象也就不難理解了。但是,這只是浮點數不能表示金額的原因之一。還有乙個深刻的原因與進製轉換有關。十進位制的0.1在二進位制下將是乙個無線迴圈小數。同樣,給出乙個能體現這個問題的demo。

public

class mytest           if (expected == sum) else       }  }

程式輸出結果:

0.1

0.20.3

0.40.5

0.60.70000005

0.8000001

0.9000001

1.0000001

notequal

近期參與到了乙個金融專案,開發十分的謹慎。先丟擲我有問題的**,作用是把以分為單位的金額轉成以元為單位的字串。

long adjustfee;string.valueof(adjustfee / 100.0);
很自信的以為這行**簡潔明瞭的完成了使命。同事review了我的**後,指出這段**會造成精度丟失的問題。先演示乙個demo,構造乙個浮點數丟失精度的場景。

@test    public

void

addtest()         system.out.println(clone);        system.out.println(clone == d);    }

程式輸出結果

9.223372036854776e189.223372036854776e18true
輸出結果足以顛覆三觀。乙個雙精度浮點數,加了10億之後,居然沒有發生任何變化!如果在金融專案裡發生這種事,何止是直接被fire掉,蹲監獄都是可能的。這類 問題其根本原因在於浮點數在計算機內部的表示方法。這種ieee標準表示法兼顧了資料的精度和大小。

摘自網上。學過《計算機組成原理》的同學都知道,32位的浮點數由3部分組成:1位元的符號位,8位元的階碼(exponent,指數),23位元的尾數(mantissa,尾數)。這個結構會表示成乙個小數點左邊為1,以底數為2的科學計數法表示的二進位制小數。浮點數的能表示的資料大小範圍由階碼決定,但是能夠表示的精度完全取決於尾數的長度。long的最大值是2的64次方減1,需要63個二進位制位表示,即便是double,52位的尾數也無法完整的表示long的最大值。不能表示的部分也就只能被捨去了。對於金額,捨去不能表示的部分,損失也就產生了。

了解了浮點數表示機制後,丟失精度的現象也就不難理解了。但是,這只是浮點數不能表示金額的原因之一。還有乙個深刻的原因與進製轉換有關。十進位制的0.1在二進位制下將是乙個無線迴圈小數。同樣,給出乙個能體現這個問題的demo。

public

class mytest           if (expected == sum) else       }  }

程式輸出結果:

0.1

0.20.3

0.40.5

0.60.70000005

0.8000001

0.9000001

1.0000001

notequal

浮點數表示

之前的一些工作當中碰到了很多有關浮點數的問題,比如浮點數的表達範圍 表達精度 浮點數的儲存方式 浮點數的強制型別轉換等等,因此感覺有必要系統了解一下有關浮點數的問題。浮點數是一種公式化的表達方式,用來近似表示實數,並且可以在表達範圍和表示精度之間進行權衡 因此被稱為浮點數 浮點數通常被表示為 n m...

IEEE的浮點數表示

ieee浮點標準用v 1 s m 2 e 由符號,尾數,階碼表示 32位單精度 單精度二進位制小數,使用32位儲存。1 8 23 位長 s exp fraction 31 30 23 22 0 位編號 從右邊開始為0 偏正值 127 64位雙精度 雙精度 二進位制小數,使用64位儲存。1 11 52...

C51浮點數顯示 浮點數表示方法

c51中的浮點數儲存方式 n年前曾在c51bbs論壇中發布過 float 浮點形,它是符合ieee 754標準的單精度浮點形資料,在十進位制中具有7位有效數字。float型據占用四個位元組 32位二進位制數 在記憶體中的存放格式如下 位元組位址 由低到高 0 1 2 3 浮點數內容 mmmmmmmm...