2012-03-07 6 views
3
int main(int argc, char *argv[]) 
{ 
    uint64_t length = 0x4f56aa5d4b2d8a80; 
    uint64_t new_length = 0; 

    new_length = length + 119.000000; 

    printf("new length 0x%"PRIx64"\n",new_length); 

    new_length = length + 238.000000; 

    printf("new length 0x%"PRIx64"\n",new_length); 

    return 0; 
} 

上記のコードを使用してください。私はプログラムのcases.The出力の両方で正確に同じ結果を取得しています符号なし64ビットinteger.Iに二つの異なる二重の値を追加していている私は2つの異なる結果が、それを期待符号なし64ビット値にdouble値を追加すると、奇妙な結果になります。

$./a.out 
new length 0x4f56aa5d4b2d8c00 
new length 0x4f56aa5d4b2d8c00 

下回っショーcase.Iもdouble

のように
new_length = (double)length + 119.000000; 

からuint64_t値型キャストを試してみましたが、されていません。しかし、これはあまりにも問題になるかもしれないものにhelp.Anyの考えに思えないのですか?

+0

[なぜこれは本当ですか?](http://stackoverflow.com/questions/4094117/why-is-this-true) –

答えて

3

浮動小数点演算は正確ではありません。数字が大きくなると、数字の精度が下がります。

0x4f56aa5d4b2d8a80は非常に大きな数値です。

new_length = length + 119.000000; 

で何が起こっている

length + 119.000000が加算を行うために、二重にキャストなっていることです。その倍数は非常に大きいので、かなり劇的に丸められます。 new_lengthに代入されると、整数型uint64_tに再び変換されます。あなたは

new_length = length + 238.000000; 

を呼び出すと

丸い結果は同じされて終わることが起こります。あなたが本当に何をしたいのか

は、あなたが望む答えを与える

new_length = length + (uint64_t)238.0; 

です。最初は、ダブルを完全型にキャストします。これは正確に追加されます。

+0

浮動小数点*は正確です。あなたは何度も同じ実験を繰り返して、同じ結果を得ることができます。これらの結果は、実数でのあなたの経験に基づくあなたの期待に沿わないかもしれませんが、確かに正確です。 –

7

浮動小数点オペランドを追加するので、両方のオペランドは暗黙的にdoubleにキャストされ、加算は浮動小数点演算を使用して行われます。

しかし、doubleが正確に次の値のいずれかを保持するのに十分な精度を持っていない。

0x4f56aa5d4b2d8a80 + 119.0 (requires 63 bits of precision) 

0100111101010110101010100101110101001011001011011000101011110111 
<-------------------63 bits of precision----------------------> 


0x4f56aa5d4b2d8a80 + 238.0 (requires 62 bits of precision) 

0100111101010110101010100101110101001011001011011000101101101110 
<-------------------62 bits of precision---------------------> 

標準IEEE倍精度のみ精度の53ビットを有します。

結果は、それらの両方が同じ最終的な値に丸められ得るということです:あなたはこの丸めを回避したい場合

0x4f56aa5d4b2d8c00 (53 bits of precision) 

0100111101010110101010100101110101001011001011011000110000000000 
<-----------------53 bits of precision--------------> 

、あなたはオペランドをキャストすることによって、完全に浮動小数点演算を避ける必要があります整数にする。 (または代わりに119238を代わりに使用)

関連する問題