2011-11-09 7 views
7

私はウィキペディア(http://en.wikipedia.org/wiki/Type_conversion#Implicit_type_conversion)の次の例を見つけました。Cでの暗黙の型変換

#include <stdio.h> 

int main() 
{ 
    int i_value = 16777217; 
    float f_value = 16777217.0; 
    printf("The integer is: %i\n", i_value); // 16777217 
    printf("The float is: %f\n", f_value); // 16777216.000000 
    printf("Their equality: %i\n", i_value == f_value); // result is 0 
} 

その説明:「この奇妙な挙動は、それがf_valueと比較されたときに浮動するi_valueの暗黙的なキャストによって引き起こされ、精度を失うキャスト、値が異なる比較対象となっています。」

これは間違っていませんか? i_valueがfloatにキャストされていれば、両方とも精度が同じになり、等しくなります。 したがって、i_valueはdoubleにキャストする必要があります。

+0

g ++(GCC 4.6.2)では、私は同等のために '1'を取得します。 –

+0

@Kerrek:そして私。 VSでは、私は0を取得します。 –

+0

@OliCharlesworth:リテラルを 'f'型または' double'型に変更することに興味があります - すべての場合に '1'を返します... –

答えて

7

なし、等価演算子、「通常の算術変換」の場合に始めた、発生:

  • まず、いずれかのオペランドの対応する実数型がlong doubleであれば、他のオペランドは、タイプ のドメインの変更なしに、対応する実タイプがlong doubleのタイプに変換されます。
  • いずれのオペランドの対応する実タイプがdoubleである場合、他方のオペランドは、タイプ の変更なしに、対応する実タイプがdoubleであるタイプに変換されます。
  • いずれのオペランドの対応する実タイプがfloatである場合、他方のオペランドは、タイプ の変更なしに、対応する実タイプがfloatのタイプに変換されます。

この最後の場合は、ここで適用されます。i_valuefloatに変換されます。フローティングオペランドの

値と浮動の結果の:

このにもかかわらず、比較からが奇数の結果を見ることができる理由は、通常の算術変換にこの警告であります 式は、型によって必要とされる精度よりも高い精度と範囲で表すことができます( )。それによってタイプは変更されない。

これは何が起こっているかである:変換i_valueの種類はまだfloatですが、この表現では、あなたのコンパイラは、この緯度の利点を取っているとfloatより高い精度でそれを表現します。これはコンパイラが浮動小数点数を80ビットの拡張精度形式で格納する浮動小数点スタックに一時的な値を残すため、コンパイラが387互換の浮動小数点用にコンパイルするときの典型的なコンパイラ動作です。

コンパイラがgccの場合、-ffloat-storeコマンドラインオプションを指定すると、この精度が無効になります。

+0

x64ではgccはintegerをfloatに変換する明示的なcvtsi2ssl命令を使用します。しかし、x86では、これは正確に起こるものであり、実際の精度は倍以上にもなります。 –

+0

@ konrad.kruczynski:はい、また、 '-mfpmath = sse'オプション(' -msse'またはそれを意味するオプションが必要です)を指定することで、x86で同じ結果を得ることができます。 – caf

-1

私は、32ビットIEEE浮動小数点が保持できる最大の整数値は1048576で、これは上記の数よりも小さいと考えています。したがって、浮動小数点値が正確に16777217を保持しないことは間違いありません。

コンパイラが2つの異なるタイプの数値(つまり浮動小数点数)を比較する方法はわかりませんが、 。 「フロート」の両方の値(これは値が同じにする必要がありますので、これは、コンパイラが何をするか、おそらくではありません)

2)に変換)

1:私はこれが行われるかもしれない3つの異なる方法を考えることができます両方の値を "int"に変換します(intに変換するとintが変換されることがあります)。浮動小数点の値が16777216.99999の場合、 "int"への変換は切り捨てられます。

3)両方の値を「double」に変換します。私の推測では、これはコンパイラがやることだろう。これがコンパイラの処理であれば、2つの値はまったく違うはずです。 doubleは16777217を正確に保持することができ、16777217.0が変換する浮動小数点数を正確に表すことができます(正確には16777217.0ではありません)。

+3

1048576は2^20なので、これは間違っています。 –

0

ここでいくつかの良い答えがあります。さまざまな整数とさまざまな浮動小数点表現の間の変換には非常に注意する必要があります。

私は一般的に浮動小数点数が等しいかどうかをテストしません。特に浮動小数点数が整数型からの暗黙的または明示的なキャストに由来する場合は、テストしません。私は幾何学的計算がいっぱいのアプリケーションで作業します。可能な限り、正規化された整数を使用します(入力データで受け入れる最大精度を強制することによって)。浮動小数点を使用する必要がある場合は、比較が必要な場合は差の絶対値を適用します。