2013-05-16 5 views
8

最近、私は記事を読んでいた。 理解:ダブルまたはナッシング

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

は、このコードが実行されることを想定します Double or Nothing from GOTW by Herb Sutter 私は、次のプログラムの説明と少し混乱しています一部のマシンでは1秒です。私はこのようなコードがばかげているという点に同意します。

xfloatからdoubleに変更すると、問題の説明によれば、一部のコンパイラではコンピュータの動作が永久に維持されます。説明は、標準からの次の引用に基づいています。

ある3つの浮動小数点型:ダブルフロート、ダブル長いセクション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が0から1e8までのすべての整数値を正確に表すことができない場合はどうなりますか?次いで、修飾されたプログラムがダウンカウントを開始しますが、最終的には表現できない値Nに達するとのためにN-1 == N(不足浮動小数点精度まで)...と

私の質問は:

floatが1e8を表すことさえできない場合は、float x = 1e8を初期化するときにすでにオーバーフローしているはずです。どうすればコンピュータを永遠に稼働させることができますか?

これは、コンパイラがintタイプで与えられた数を表すことができない場合、それはオーバーフローをもたらすであろうことを意味

#include <iostream> 

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

(ないdoubleしかしintが)私はここに簡単な例を試してみました。

私は誤解しましたか?私が見逃した点は何ですか? xdoubleからfloatに変更されていますか?

ありがとうございました!

答えて

9

キーワードは「正確に」です。

floatは、あなたがフリークを持っていない限り、floatタイプである場合を除き、正確にも1e8を表すことができます。しかし、正確には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ビットの精度しかない場合でもループが終了する可能性があることに注意してください。これにより、浮動小数点演算はその型よりも高い精度で実行できます。十分に高い精度(例えば、52 + 1ビットの通常のdouble)で実行されると、すべての減算がxに変更されます。

+0

すてきな情報ありがとう、私の質問はなぜ初期化時にオーバーフローがある場合は、whileループも開始されますか? – taocp

+2

@taocp初期化時にオーバーフローが発生していません。浮動小数点形式は、+ 1に達するまで、より高い値に行くにつれて*精度*が連続的に低くなります。無限の&#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はすべての可能な10進値を表すことはできません(また、ビット制限表現もできません)。したがって、floatで非常に大きな値を処理する場合、本質的には小数点以下を持ち、ある程度の電力になります。まあ、この10進値が最後のビットが消える値で終わるならば、それは切り上げられることを意味します。あなたが終結するのは、それ自体を減少させてから元に戻す価値です。

関連する問題