2013-05-16 69 views
8

最近,我讀了一篇:Double or Nothing from GOTW by Herb Sutter 我有點困惑與以下程序的說明:瞭解周#67的宗師:雙人或沒有

int main() 
{ 
    double x = 1e8; 
    while(x > 0) 
    { 
     --x; 
    } 
} 

假設該代碼運行在某些機器上1秒鐘。我同意這樣的代碼是愚蠢的。

但是,如果我們將xfloat更改爲double,那麼在有些編譯器上,它會使計算機永遠運行。解釋基於以下標準引用。

從部分C++標準的3.9.1/8引用:

有三種浮點類型:浮點,雙精度和長一倍。 double類型至少提供與float相同的精度,long double類型的精度至少與double相當。 float類型的值的集合是類型double的值集合的子集;類型double的值集合是long double類型的值集合的子集。

的代碼的問題是:

多久你希望它如果你改變「雙」到「浮動」需要?爲什麼?

這裏給出的解釋:

它可能會採取或者約1秒(特定的實現浮動可能有點快,快,或增加了一倍略慢),或永遠取決於float是否可以精確地表示0到1e8之間的所有整數值。

標準的上述引用意味着可能存在可以用double表示的值,但不能用float表示。特別是在一些流行的平臺和編譯器中,double可以精確地表示[0,1e8]中的所有整數值,但float不能。

如果float不能準確表示從0到1e8的所有整數值?然後修改的程序將開始倒計時,但最終將達到不能被表示的值N和針對N-1 == N(由於浮點精度不足)...和

我的問題是:

如果float甚至不能代表1e8,那麼當我們初始化float x = 1e8時就已經溢出了;那麼我們如何才能讓電腦永久運行?

我想一個簡單的例子這裏(雖然不是doubleint

#include <iostream> 

int main() 
{ 
    int a = 4444444444444444444; 
    std::cout << "a " << a << std::endl; 
    return 0; 
} 
It outputs: a -1357789412 

這意味着,如果編譯器不能夠代表與int類型的給定數量,這將導致溢出。

那麼我誤讀了嗎?我錯過了什麼?正在將xdouble更改爲float未定義的行爲?

謝謝!

回答

9

關鍵詞是「完全」。

float可以代表1e8,甚至完全一樣,除非你有一個怪胎float類型。但這並不意味着它可以完全代表所有較小的值,例如,通常需要26位精度的2^25+1 = 33554433不能精確地表示爲float(通常具有23 + 1位精度),也不能精確地表示2^25-1 = 33554431,這需要25位精度。

這些數的兩者都然後表示爲2^25 = 33554432,然後

33554432.0f - 1 == 33554432.0f 

將循環。 (您將盡早點擊一個循環,但該點有一個很好的十進制表示;)

在整數算術中,所有的x都有x - 1 != x,但在浮點算術中沒有。

請注意,即使float只有通常的23 + 1位精度,循環也可能會完成,因爲該標準允許以比該類型更高的精度執行浮點計算,並且如果計算是以足夠高的精度執行(例如通常的double與52 + 1位),每次減法將改變x

+0

感謝您的好信息,但我的問題是,如果我們在初始化時溢出,while循環甚至會啓動? – taocp

+2

@taocp您在初始化時沒有溢出。浮點格式會隨着您達到更高值而持續降低*精度*,直到達到+ 1。#INF。對無限&#NAN的操作是合法的,而不是未定義的。他們可能會有意想不到的結果。看看[IEEE-754標準](https://en.wikipedia.org/wiki/IEEE_floating_point) –

+0

@indeterminatelysequenced啊,非常感謝。 – taocp

0

試試這個簡單的修改,它會關閉連續x值的值。

#include <iostream> 
using namespace std; 

int main() 
{ 
    float x = 1e8; 
    while(x > 0) 
    { 
     cout << x << endl; 
     --x; 
    } 
} 

在float的一些實現中,您將看到float的值被卡在1e8或該區域。這是因爲float存儲數字的方式。浮點數不能(也不能有限制的表示)表示所有可能的十進制數值,所以當你用浮點數處理非常大的數值時,你基本上會有一個小數點,這個數值就是一些權力。那麼,如果這個十進制值以最後一位丟棄的值結束,則意味着它被取整。最終結果是一個減少(然後備份)自身的值。