對於這個代碼段浮點加法和除法
double count = 0.0;
while(count != 1.0)
{count += 1.0/3;}
我想知道什麼部分(IEEE 754)將導致計數3:爲1.0,而不是0.9999999999999999。我意識到一般原因會由於二進制數字的數目無限而變爲四捨五入,但如果有人可以更詳細地解釋(IEEE 754)背後的細節,我將不勝感激。
對於這個代碼段浮點加法和除法
double count = 0.0;
while(count != 1.0)
{count += 1.0/3;}
我想知道什麼部分(IEEE 754)將導致計數3:爲1.0,而不是0.9999999999999999。我意識到一般原因會由於二進制數字的數目無限而變爲四捨五入,但如果有人可以更詳細地解釋(IEEE 754)背後的細節,我將不勝感激。
沒有一個通用規則確保添加n
副本1.0/n
將導致完全1.0
。這可以通過下面的程序改變n
探索:
import java.math.BigDecimal;
public class Test {
public static void main(String[] args) {
int n = 3;
double[] counts = new double[n+1];
for(int i=1; i<counts.length; i++){
counts[i] = counts[i-1]+1.0/n;
}
for(double count : counts){
System.out.println(new BigDecimal(count));
}
}
}
對於n=3
它打印:
0
0.333333333333333314829616256247390992939472198486328125
0.66666666666666662965923251249478198587894439697265625
1
第一加法增加了零。第二個加法是簡單的加倍,所以它也是精確的。第三次也是最後一次加法涉及四捨五入,但輪到1.0
。該相加確切的結果是:
0.999999999999999944488848768742172978818416595458984375
它是更接近1.0比它的下一個值下降:
0.99999999999999988897769753748434595763683319091796875
這麼圓到最近幾輪1.0。
然而,改變n
到7
結果:
0
0.142857142857142849212692681248881854116916656494140625
0.28571428571428569842538536249776370823383331298828125
0.428571428571428547638078043746645562350749969482421875
0.5714285714285713968507707249955274164676666259765625
0.7142857142857141905523121749865822494029998779296875
0.8571428571428569842538536249776370823383331298828125
0.9999999999999997779553950749686919152736663818359375
運行修改,添加1.0/7
原計劃將導致一個無限循環。 count
會增加,直到它變得如此之大以至於添加1.0/7
將舍入舊值,然後停留在該值。
它也不能保證乘法。試試'1.0/49 * 49'。 – dan04
@ dan04確實。通常最好假設舍入誤差,並注意幾個肯定是確切的特殊情況。 –
你在尋找什麼樣的細節?你似乎已經很好地總結了它。 –
我想我很想知道他們是否是這種事件的直接術語,因爲我不確定我的教授會接受我的推理,爲什麼事實證明這只是1.0,當我唯一的答案是「因爲四捨五入」。 – user3361646
我不相信IEEE-754保證這樣的代碼永遠都不會成功。第一次,在大多數現代平臺上,它可能不會(至少在一般情況下 - 它可能與某些特定的因數),但我想如果讓它運行足夠長的時間,幾次繞過無窮大後,它可能設法打出正確的位模式,儘管... – twalberg