[英]Strange behavior of float point
我了解random.Float()帶回介於0.0到0.999之間的浮點數...
但是由於未知的原因,幾乎相同的代碼會帶回2個不同的答案。
我想了解為什么t1可以隨機1.0,而t2不能隨機。
我試圖檢查類似的問題,但找不到類似的問題
Random rand = new Random();
for (int i = 0; i < 1000000000; i++) {
float t1 = 0.9f + rand.nextFloat() * 0.1f;
float t2 = 0.1f + rand.nextFloat() * 0.9f;
if (t1 == 1.0f) {
System.out.println("t1 " + t1);
}
if (t2 == 1.0f) {
System.out.println("t2 " + t2);
}
}
沒有錯誤消息,我只是不明白為什么t1有時會帶回1.0號而t2沒有。
編輯:t1生成最大值為0.999 ... * 0.1,即0.0999 ... + 0.9 = 0.9999 ... t2生成最大值為0.999 ... * 0.9,即0.8999 ... + 0.1 = 0.9999 ...兩者都應一樣嗎?
造成這種差異的主要原因是,對於任何x <1,.9 + x •.1大於.1 + x •.9,並且Random.nextFloat
返回的值小於1。對於返回的最大值,前者表達式非常接近1以至於將其四舍五入為float
會產生1,但后者的表達式離1更遠,而將其四舍五入為float
會產生下一個小於1的float
。
Random.nextFloat
返回的Random.nextfloat
是Random.nextfloat
16777215/16777216。 令M為該最大值,令d = 1 − M = 1/16777216。
如果我們使用實數計算t1
,則其最大值將為.9 + M •.1。 = .9 +(1- d )•.1 = 1-.1• d 。 同樣, t2
將為.1 + M •.9 = .1 +(1- d )•.9 = 1-.9• d 。
現在,我們可以很容易地看到,最大的t1
(如果與實數計算)為0.1•d遠離1,但t2
有0.9•從1 天的路程。
Random.nextFloat
返回的最大值是16777215/16777216的原因是它是小於1的最大float
。 float
格式的精度是導致可表示的值之間的步長為1/16777216。 這意味着此鄰域中的兩個可表示值分別是16777215/16777216和1, d是它們之間的距離。 上面的計算顯示t1
的最大值與t1
僅相差0.1• d 。因此,將其四舍五入為float
,1是最近的float
。
相比之下,最大值t2
有0.9•d離1。這意味着它僅僅是0.1•從一千六百七十七萬七千二百十六分之一千六百七十七萬七千二百十五ð路程。 因此,將其四舍五入為float
,16777215/16777216是最近的float
。
那就是使用實數算法。 下面,我將展示浮點算法。 它具有舍入誤差,但是事實證明這些誤差足夠小,不會改變結果。
在Java
,源文本.1f
和.9f
轉換為float
,其結果為0.100000001490116119384765625和0.89999997615814208984375。 表達式中的算術是使用double
執行的,然后將結果舍入為float
以分配給t1
或t2
。
可以計算出t1
的最大值:
nextFloat
的最大返回值將產生0.9f + 16777215./16777216 * 0.1f;
。 double
算術評估得出0.999999971687793642871611154987476766109109466552734375。 float
產生1,因為該double
float
值介於0.999999940395355355224609375(下一個較低的float
值)和1(下一個較高的float
值)之間,並且比前者更接近后者。 可以計算出t2
的最大值:
nextFloat
返回值替換為0.1f + 16777215./16777216 * 0.9f;
。 double
算術評估得出0.99999992400407933246242464520037174224853515625。 float
產生0.999999940395355224609375。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.