2016-04-06 13 views
9

サンプルコードM32とM64のコンパイラオプションは、異なる出力に

#include "stdio.h" 
#include <stdint.h> 

int main() 
{ 
    double d1 = 210.01; 
    uint32_t m = 1000; 
    uint32_t v1 = (uint32_t) (d1 * m); 

    printf("%d",v1); 
    return 0; 
} 

出力
1を提供

/test 174 # ./a.out 
210009 

2 。-m64オプションでコンパイルする場合(例:gcc -g3 -m64 test.c)

test 176 # ./a.out 
210010 

なぜ異なるのですかそれとも?
私が理解していたのは、mは倍に昇格され、乗算はunit32_tに下がります。また、標準型の整数を使用しているため、アーキテクチャなどに関連する曖昧さをさらに取り除くことになります。

ここでは何かが怪しいと知っていますが、それを固定することはできません。

更新:
gccとg ++の両方で上記の動作が確認できます(コメントの1つとして)。

+2

にあなたがそのようにGCCを呼び出す場合は、 C++ではなくC言語のコードとしてコンパイルされています。無関係の言語にタグを追加しないでください。 – Olaf

+0

@Olaf:Ok。私は質問を更新します。 gccとg ++コンパイラの両方で発生します。したがって、c/C++に固有のものではありません。ありがとう! –

+0

1)これをC++の質問にしないでください! CとC++は**異なる**言語です。 1a)C++では、iostreamとC++のキャスト演算子を使用して異なるコードを使用する必要があります。 2)書式文字列に間違った型指定子を使用しています。 'inttypes.h'マクロを使って固定幅の整数を出力します。 – Olaf

答えて

9

gcc(Ubuntu 5.2.1-22ubuntu2)で結果を確認できます。起こりそうなのは、32ビットのの最適化されていないコードは、FMULオペコードの387 FPUを使用しますが、64ビットはopcode MULSオペコードを使用します。 (異なるパラメータでgcc -S test.cを実行し、アセンブラの出力を参照してください)。よく知られているようにと、FMULを実行387 FPUは、高精度の64ビットより多くを持っている(80!)ので、ここでは異なる丸めるようです。当然の理由は、64ビットのIEEEダブル210.01の正確な値ではないことが、

210.009999999999990905052982270717620849609375 

、あなたは1000年を掛けたとき、あなたは実際には小数点をシフトしていないことを - 結局そこ小数点はありませんが、バイナリポイントの浮動小数点値です。その値は丸められなければなりません。 64ビットの倍精度では切り上げられます。 80ビットの387 FPUレジスタでは、計算がより正確になり、の末尾がに丸められます。

もう少しこのことについて読んだ後、私は32ビットのアーチ上のgccによって生成された結果は、標準準拠ではないと信じています。あなたはC99やC11の標準を強制したくない場合はこのようにあなたは、-std=c99とC99やC11に-std=c11を標準を強制するならば、あなたは正しい結果を得るでしょう

% gcc -m32 -std=c11 test.c; ./a.out 
210010 

することは、あなたも-fexcess-precision=standardスイッチを使用することができます。


ここでも楽しいことはありません。

% gcc -m32 test.c; ./a.out 
210009 
% gcc -m32 -O3 test.c; ./a.out 
210010 

-O3でコンパイルすると「正しい」結果が得られます。これはもちろん、コンパイラのコンパイラが64ビットSSE演算を使用して計算を一定にフォールドするためです。


、余分な精度がそれに影響を与え確認するために、あなたはlong doubleを使用することができます。

#include "stdio.h" 
#include <stdint.h> 

int main() 
{ 
    long double d1 = 210.01; // double constant to long double! 
    uint32_t m = 1000; 
    uint32_t v1 = (uint32_t) (d1 * m); 

    printf("%d",v1); 
    return 0; 
} 

今でも-m64ラウンドそれが210009.

% gcc -m64 test.c; ./a.out 
210009 
関連する問題