11

グラフでパスを見つけて累積重みを出力するプログラムがあります。グラフのすべてのエッジは、小数点以下2桁までのフロート形式で、0〜100の個別の重みを持ちます。

Windows / Visual Studio 2010では、重みが0のエッジで構成される特定のパスに対して、正しい合計重み0が出力されます。ただし、Linux / GCCでは、プログラムはパスの重みが。であると言っています2.35503e-38。私はフロートによって引き起こされたクレイジーなバグについて多くの経験をしましたが、0 + 0が0以外のものと等しくなるのはいつですか?

私が考えることができる唯一のことは、これを引き起こしているのは、プログラムが重みの一部を整数として扱い、暗黙の強制を使用してそれらを合計に追加することです。しかし、0 + 0.0fはまだ0.0fに等しいです!簡単な修正として、0.00001未満の場合は合計を0に減らします。今のところ、これで十分です。しかし、どのvodooがこれを引き起こしますか?

注:グラフ内のどの重みも前述の範囲を超えておらず、この特定のパスのすべての重みがすべて0であると100%確信しています。

編集:詳しく説明するために、ファイルから重みを読み取ることと、コードで重みを0.0fに設定することの両方を手動で試しました。合計に追加する以外に、他の操作は実行されていません。

4

3 に答える 3

11

これはIEEE浮動小数点数であり、ゼロと正確に等しくないためです。

http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm

于 2012-04-24T18:28:45.890 に答える
5

[...]小数点以下2桁までのフロート形式。

小数点以下2桁までのフロートなどはありません。浮動小数点数は、ほとんどの場合、2進数の浮動小数点数(2進数の仮数と整数の指数)として表されます。小数点以下2桁の非常に多くの(ほとんどの)数値を正確に表すことはできません。

たとえば0.20f、無実で丸い分数のように見えるかもしれませんが、

printf("%.40f\n", 0.20f);

印刷されます:0.2000000029802322387695312500000000000000。

ほら、小数点以下2桁ではなく、26桁です!!!

当然のことながら、ほとんどの実用的な用途では、違いはごくわずかです。ただし、いくつかの計算を行うと、丸め誤差が大きくなり、特に0付近で表示される可能性があります。

于 2012-04-24T18:33:35.173 に答える
3

「0.0f」の値を含むフロートは実際には0.0f(ビット表現0x00000000)ではなく、約0.0と評価される非常に小さな数値である可能性があります。IEEE754仕様が浮動小数点表現を定義する方法のため、たとえば、仮数が非常に小さく、指数が0の場合、絶対零度に等しくない場合は0に丸められます。ただし、これらの数値を十分に足し合わせると、何度も、ごくわずかな量が値に蓄積され、最終的にはゼロ以外になります。

これは、0がゼロ以外であるという錯覚を与えるケースの例です。

float f = 0.1f / 1000000000;
printf("%f, %08x\n", f, *(unsigned int *)&f);
float f2 = f * 10000;
printf("%f, %08x\n", f2, *(unsigned int *)&f2);

ただし、変数にリテラルを割り当てて追加する場合は、コンパイラがメモリ内に変換0されていない可能性があります。0x0そうであり、これがまだ発生している場合は、検証作業によってきしむ可能性のあるALU演算を実行するときに、CPUハードウェアに0をゼロ以外に変換することに関連するバグがある可能性もあります。

ただし、IEEE浮動小数点は単なる概算であり、特定の浮動小数点値の正確な表現ではないことを覚えておくとよいでしょう。したがって、浮動小数点演算にはある程度のエラーが発生します。

于 2012-04-24T18:32:55.967 に答える