3

Visual C ++では、C++プログラムで次のサンプルを作成しました。

float f1 = 42.48f;
double d1 = 42.48;
double d2 = f1;

Visual Studio2005を使用してプログラムをコンパイルしました。デバッガーに次の値が表示されます。

f1  42.480000   float
d1  42.479999999999997  double
d2  42.479999542236328  double

私の知識によるd1は問題ありませんが、d2は間違っています。

この問題は、/ fp=fastの場合と同様に/fp=strictの場合にも発生します。

ここで問題は何ですか?この問題を回避するためのヒントはありますか?これは深刻な数値問題につながります。

4

3 に答える 3

4

これはVC++などの問題ではありません。これは、浮動小数点数がコンピューターにどのように格納されるかに関する基本的な問題です。詳細については、IEEE-754を参照してください。

問題は、floatからdoubleへの変換が行われ、doubleからfloatに変換し直すと、最初に使用したのとまったく同じfloat値になることです。より長い精度が必要な場合に2倍のみを使用することを除いて、精度の低下を回避する方法を私は知りません。round変換されたfloatを小数点以下2桁にしようとすると、正しい値に設定される可能性がありますが、それはわかりません。

于 2010-04-07T09:08:06.067 に答える
3

の値f1との値はd2両方ともまったく同じ数値を表します。その数は正確には42.480000ではなく、正確には42.479999542236328でもありませんが、終了する10進表現があります。floatを表示する場合、デバッグビューはfloatの精度で適切に丸められ、doubleを表示する場合はdoubleの精度で丸められます。したがって、変換してdoubleとして表示すると、ミステリー値の約2倍の有効数字が表示されます。

d1には、ミステリー値よりも4.48に近い近似値がd1含まれています。これは、4.48に最も近いdoubleが含まれているのに対しf1、 4.48にd2最も近いfloat値のみが含まれているためです。何がd2含まれると思いましたか?f1は、それが「実際にあるはず」4.48であることを「記憶」できないため、doubleに変換すると、「より正確」になります。

それを回避する方法は、あなたが意味する深刻な数値問題によって異なります。問題がd1とd2が等しく比較されないことであり、それらが等しくなるはずだと思う場合、答えは、比較に小さな許容値を含めることです。たとえば、次のように置き換えd1 == d2ます。

fabs(d1 - d2) <= (d2 * FLT_EPSILON)

これはほんの一例ですが、このケースを扱っているかどうかは確認していません。自分に合った許容誤差を選択する必要があります。また、多くのエッジケースについても心配する必要があります。d2はゼロである可能性があり、値は無限大またはNaNである可能性があり、その他の場合もあります。

問題が、d2が正確な結果を生成するためのアルゴリズムにとって十分に正確な値ではないことである場合は、float値を回避するか、より数値的に安定したアルゴリズムを使用する必要があります。

于 2010-04-07T10:59:02.293 に答える
2

ここで起こっていることに何も問題はありません。

浮動小数点数がメモリで表される方法のため、42.479999999999997は、doubleが持つことができる42.48の最も近い表現です。

このペーパーを読む:http: //docs.sun.com/source/806-3568/ncg_goldberg.html

そこで何が起こっているのかを説明しています。残念ながら、その保管については何もできません。

于 2010-04-07T09:08:47.577 に答える