2011-03-19 62 views
3

浮點精度受限於C++以及新手程序員在舍入值時經常會造成麻煩。如何重現C++雙舍入問題

在教學生時,通常會演示浮點精度數舍入問題。您知道在所有C++編譯器上一致證明這種舍入問題的可能方法是什麼?

+3

'1.5'將被表示爲正好'1.5'。一個100%肯定會關閉的數字不需要二進制表示,比如'1.1'。 – mingos 2011-03-19 22:32:19

+0

在你使用的任何編譯器上製作你自己的工作示例時有什麼問題,並向你的學生展示並解釋:「不同的編譯器以不同的方式工作,有些將會等等等等」? – quasiverse 2011-03-19 22:35:26

+0

@quasiverse如果可以在所有編譯器上重現它,那麼它是基於'C++標準'而不是某個特定的編譯器。我相信這個例子比僅有一個編譯器的例子更有力。 – Leonid 2011-03-19 22:38:31

回答

4

首先,我們應該注意到,在IEEE754浮點中,1.5,0.52.0都是完全表示的。因此,在此特定示例中,1.5將永遠不會是1.499999999999

話雖如此,我認爲要做的事情是揭露你的學生號碼是而不是完全可以代表。說,1.1

下面是一個簡單的程序:

#include <iostream> 
#include <iomanip> 

int main() { 
    std::cout << std::setprecision(30); 
    double d1(1.1); 
    std::cout << d1 << "\n"; 
    double d2(11); 
    double eps = d2/10 - d1; 
    std::cout << d2 << "\n"; 
    std::cout << eps << "\n"; 
    bool equal = (d1 == d2); 
    std::cout << equal << "\n"; 
} 

也許你可以走他們通過這個節目,小心地說,d1d2大約等於1.1。

對於高級學生,你可以通過派系二進制算術,看看爲什麼1/2是可表示的,但1/10不是。

編輯:我認爲這一點的方法是將比較重複的小數與重複的二進制分數。以十進制形式顯示你的學生1/7。在董事會做長期的分工。指出你不能完全使用有限資源編寫1/7。然後,向他們展示如何將1/10寫成二進制分數,或者告訴他們不能使用有限資源記下它。

指出浮點數是有限的(32位),雙精度是有限的(64位)。也許介紹一下鴿子的主體,並說你不能用一個有限的詞長來表示一個無限的集合(就像所有的理性)。

無論您嘗試什麼,請回到此處並讓我們知道它是如何工作的。

1
printf("%.20f\n",0.1f); 

cout << fixed << setprecision(20) << 0.1f << endl; 

:)

5

你可以用這個例子:

#include <iostream> 
using namespace std; 

int main() { 
    for (double d = 0.0; d != 1.0; d += 0.1) 
    cout << d << "\n"; 
} 

程序將永遠不會終止爲D總是不等於1.

+0

有人可以詳細說明嗎? – snoofkin 2011-03-20 00:52:52

+1

@ soulSurfer2010你可以試試看看。當你給0.1加d時,它只能保持近似值。因此,d等於_approximately_0.1,大致等於0.2等等。它絕對不會等於1.0 – quasiverse 2011-03-20 02:11:30

2

我如下面的例子E:

double sum = 0; 
for (int i = 0; i < 10; i++, sum += 0.1); 
cout << "sum = " << sum << endl; 
cout << "(sum == 1.) is " << boolalpha << (sum == 1.) << endl; 

輸出如下:

sum = 1 
(sum == 1.) is false 

矛盾的原因是浮點計算。

1

試試這個例子:

#include <cstdio> 
int main() { 
    printf("%.20lf rounded to two decimal places is %.2lf\n", 0.075, 0.075); 
    return 0; 
} 

它打印

0.07499999999999999722 rounded to two decimal places is 0.07 

注意,0.075四捨五入至小數點後兩位應爲0.08,而不是0.07正如我們在輸出中看到。這個例子清楚地表明瞭雙舍入問題

+1

這也可能會打印出'0.075000000000000011'並舍入到'0.08'。在所有C++編譯器上一致提及的問題_ – MSalters 2011-03-21 11:58:21

+0

質量實現(使用Dybvig或Grisu)將打印0.075。 – ybungalobill 2012-05-09 20:36:30