記錄數值計算中遇到的坑 - 舍入誤差
今天突然發現不同並行核數下的計算結果竟然有差異!這種不可復現的問題必然是不能允許的(某生物學院士論文居然不可復現。。。)。掐指一算,已經是第二次掉進舍入誤差這個坑裡了。
1。 舍入誤差的影響
由於計算機中用有限位數的浮點數儲存實數,導致儲存值與真實值存在差異,這便是舍入誤差。這將會帶來什麼影響呢?以一段程式碼為例
static void Main(string[] args)
{
float floatSum1 = 0, floatSum2 = 0;
for (int n = 1; n <= 10000; n++)//第一種順序:從1開始加到10000
{
floatSum1 += 1f / (n * n);//f表示數字1為float型
}
for (int n = 10000; n >= 1; n——)//第二種順序,從10000開始加到1
{
floatSum2 += 1f / (n * n);
}
Console。WriteLine(floatSum1);
Console。WriteLine(floatSum2);
//輸出結果為:
//1。6447253
//1。644834
}
這告訴我們,由於計算順序不一致,得到的結果可能有差異!
2。 消除舍入誤差
在平行計算中,有時很難控制計算順序,那麼只能提高精度了。
static void Main(string[] args)
{
double doubleSum1 = 0, doubleSum2 = 0;
for (int n = 1; n <= 10000; n++)//第一種順序:從1開始加到10000
{
doubleSum1 += 1。0 / (n * n);
}
for (int n = 10000; n >= 1; n——)//第二種順序,從10000開始加到1
{
doubleSum2 += 1。0 / (n * n);
}
Console。WriteLine((float)doubleSum1);
Console。WriteLine((float)doubleSum2);
//輸出結果為:
//1。644834
//1。644834
}
這樣做,並行中計算結果一致性也能保證了。
分割線——————-
更好的解決方法可以百度 Kahan演算法