2012-03-26 10 views
3

私はこの単純なコードを試しています。それはDFに等しくなければならないので、私ジ二重可変であるが、私は(フロート)に設定(float)キャストが動作しません

int main(){ 
    int i, cont=0; 
    float f; 
    double di, df; 
    for(i=10000000, f=i; i<INT_MAX; i++, f=i, df=f, di=((float)i)){ 
    if(i!=f){ 
     printf("i=%d f=%.2f df=%.2lf di=%.2lf\n", i, f, df, di); 
     if(cont++==10) return 0; 
    } 
    } 
    return 1; 
} 

、しかし:それはフロートで表現できない最初の10の整数を示しますそうではない。

例えば、番号16777217を F によって16777216とDFとして表されているが、(フロート)キャスティングを無視し、依然として16777217です。

これはどのように可能ですか?

**私はこの使用しています:あなたの質問に関連するGCC(Ubuntuの4.4.3-4ubuntu5)4.4.3

+1

プラットフォームとコンパイラのバージョンは何ですか? – sarnold

+3

なぜカンマ演算子を使用していますか?このような不要な複雑さの問題を追加する必要は全くありません。 – Joe

+0

あなたは '%lf'を言う必要はありません。ただ '%f'はうまく、' double'を意味します。 –

答えて

2

the C99 standardで6.3.1.8:2です:

浮動の値をオペランドおよび浮動小数点結果の 式は、型によって必要とされるよりも高い精度と範囲で表現されることがあります( )。それによってタイプは変更されない。

特に脚注52で:

キャスト及び割当演算子は依然として6.3.1.4および6.3.1.5に記載されるように、それらの指定された変換を実行するために必要とされます。

脚注を読み、私はあなたのコンパイラにバグを発見したと言います。

i!=fの比較は浮動小数点数の間で行われます(標準と同じページの宣伝規則を参照してください)ので、常にfalseにする必要があります。この後者のケースでは、6.3.1.8:2で比較するためにコンパイラがより大きな型を使用することを許可されていると思われますが、おそらく比較が(double)i!=(double)fと等しくなり、時には真となることがあります。パラグラフ6.3.1.8:2は私が最も嫌う標準のパラグラフですが、私はまだ厳密なエイリアシングを理解しようとしています。

+0

ありがとうございます。私は正しいと思いますが、コンパイラにはバグ(またはフィーチャ?)があります.i!= fは浮動小数点の代わりに倍精度の間で比較されます。 – salteador

+0

gccの既知の非常に長いバグです。開発者は、正しさを気にしない人のためにパフォーマンスを適度に損なうため、修正の余地はほとんどありません。あなたのプログラムを古いCPUと互換性を持たないように気にしないなら、問題を '-msse'で修正することができます(浮動小数点のためにFPUの代わりにSSEを使います)。 x86以外のプラットフォーム(おそらくm68k?)では、この問題は存在しないことに注意してください。 –

+0

@R ..:正確性に関係なくパフォーマンスを最大限にしたい場合、すべての浮動小数点計算が42.0を返すだけではいかがですか?彼らに数学を行こうとするよりも速くはないでしょうか?コンパイラが中間値に32ビットフォーマットではなく80ビット拡張フォーマットを使用している* f4 = f1 + f2 + f3;のようなものを実行するのは良いIMHOです*しかし、比較やキャストが適切なタイプで行われていないと意味がなく、「スピード」は無関係です。 – supercat

2

この投稿は、何が起こっているかを説明します。

http://www.exploringbinary.com/when-floats-dont-behave-like-floats/

基本的に余分な精度が等しくない等しい浮動小数点数であるもの作り、異なる式の評価のためのマシンに保存される可能性があります。

+0

ありがとうございました。私はそれを知らなかった;) – salteador

+0

標準では、余分な精度を捨てるためにキャストが必要です。この点でGCCは単純に壊れており、それは既知の問題です。この問題は '-ffloat-store'オプションで部分的に踏み込むことができますが、キャストではなく代入だけが修正されます。 –

関連する問題