2014-09-01 3051 views
3

我在如何正確地將C++中的計算結果(雙精度型)轉換爲n個小數位而掙扎。在嘗試標準方法(將數字乘以10^n後,使用'round'函數獲得最接近的長整數,然後將結果除以10^n並重復爲double,如此處所述:http://en.wikipedia.org/wiki/Rounding),我發現它應用於計算結果時會給出意想不到的結果(我認爲我的答案,但顯然計算機不同意)。對於n的一個例子= 2:如何四捨五入到小數點後n位C++

#include <iostream> 
#include "math.h" 

int main() 
{ 
    double x 177.95d; //original number 
    double y yr; 

    y = x*(1.0d-0.3d); //perform a calculation. Should be 124.565 
    yr = (double) round(y/.01)*0.01; //round up y for n=2 
    printf("rounded value of y = %.2f\n",yr); //prints out 124.56 
} 

要清楚,我知道,所有涉及到的數字沒有一個確切的二進制表示的,但我不會期望雙(我只要相信有大約15位十進制數字的精確度)在5個有效(十進制)數字內接近某個數字時遇到問題。由於許多程序以這種方式整數,我認爲這是可能的(對嗎?)即使電子表格也這樣做...

更新: 顯然,我可以通過簡單地提高舍入精度來得到這個工作。例如:yr =(double)round(y/.0001)* 0.0001;似乎會產生四捨五入到兩位十進制數字的正確結果。然而,我不能完全弄清楚小數舍入位數(n)和舍入函數中所需零數(我們稱之爲m)之間的關係。

UPDATE UPDATE: 我想我已經破解了它。首先,我注意到用於雙打的輸出流格式化程序已經按照您要求的任何格式(例如printf(「%。2f \ n」,12.345)將十進制表示進行了四捨五入)將生成輸出12.35)。這意味着一個float或double的十進制表示要四捨五入到第十個小數位必須首先轉換爲第(n + 1)十進制數是正確的表示。現在,假設y的十進制表示形式的累積誤差(e)爲1.0E-(n + 1)(對於64位雙精度的機器ε爲大約2.E-16),唯一一次循環函數如果y的第(n + 1)位數字爲5,但十進制近似值給出第4位的第(n + 1)位數字且第(n + 2)位數字≥5,則結果不好。事實上,在我給出的例子中,y到15位的十進制近似值是124.564999999999984 - 只是這樣的病態。輪迴功能必須簡單地說明這些情況。

因此,我得出以下結論:舍入函數(double)round(y/1.0Em)* 1.0Em中指數m的最小值保證始終給出雙倍可接受結果,並舍入到小數點後第十位等於兩個:m = n + 2。這解釋了我第一次更新中的積極結果...

+1

浮點數學不準確 – sbooth 2014-09-01 17:13:55

+0

計算'yr'時使用'100',而不是'0.01'。 – eduffy 2014-09-01 17:14:52

+0

http://stackoverflow.com/questions/4217510/how-to-cout-the-correct-number-of-decimal-places-of-a-double-value?rq=1 – 2014-09-01 17:16:51

回答

-2

使用雙舍入。第一次四捨五入將使最後一位數字接近你的預期。添加一個非常小的偏移量以抵消二進制浮點數低於實際期望值的趨勢,然後再次循環。

yr = round((round(y/0.001)+0.1)/10.0)*0.01; 

這不適用於所有情況,但它應該比樸素的方法更加一致。

相關問題