「Epsilon」は、フローティングポイント計算の何かを本当に保証していますか?
-
02-10-2019 - |
質問
問題を短くするために、私が式を計算したいとしましょう a / (b - c)
の上 float
s。
結果が意味があることを確認するために、私は b
と c
平等です:
float EPS = std::numeric_limits<float>::epsilon();
if ((b - c) > EPS || (c - b) > EPS)
{
return a / (b - c);
}
しかし、私のテストでは、意味のある結果を保証するだけでは不十分であり、可能であれば結果を提供することもできないことを示しています。
ケース1:
a = 1.0f;
b = 0.00000003f;
c = 0.00000002f;
結果: 条件は満たされていませんが、式は正しい結果100000008を生成します(フロートの精度に関して)。
ケース2:
a = 1e33f;
b = 0.000003;
c = 0.000002;
結果: 条件が満たされているが、表現は意味のある結果ではない +1.#INF00
.
私は、議論ではなく、結果をチェックするためにはるかに信頼できると感じました。
const float INF = numeric_limits<float>::infinity();
float x = a / (b - c);
if (-INF < x && x < INF)
{
return x;
}
しかし、当時のイプシロンはどうですか、そしてなぜ誰もがイプシロンを使用するのが良いと言っているのですか?
解決
「フロートを扱うときは、エプシロンを使用する必要があります」は、一般的な比較(ゼロだけでなく)のために、フロートをフロートポイント計算の表面的な理解で理解したプログラマーの膝の反応です。
これは通常、丸めエラーの伝播を最小限に抑える方法を教えていないため、キャンセルや吸収の問題を回避する方法を教えておらず、問題が実際に2つのフロートの比較に関連している場合でも、 それはあなたがしていることに正しいエプシロンの価値をあなたに伝えません.
読んでいない場合 すべてのコンピューター科学者が浮動小数点算術について知っておくべきこと, 、それは良い出発点です。それ以上に、あなたがあなたの例の分裂の結果の正確さに興味があるなら、あなたは不正確な方法を推定する必要があります b-c
によって作られました 前 実際、丸めエラー b-c
小さく、小さな絶対誤差は結果の大きな絶対誤差に対応します。あなたの懸念が部門がオーバーフローしてはならないということだけである場合、あなたのテスト(結果について)が正しいです。浮動小数点数のヌル除数をテストする理由はありません。結果のオーバーフローをテストするだけです。これは、除数がnullである場合と、除数が非常に小さく、結果を表現できない場合の両方のケースをキャプチャします。精度。
丸めエラーの伝播に関しては、存在します 専門分析装置 それはあなたがそれを推定するのに役立ちます。なぜなら、それは手でやるべき退屈なことだからです。
他のヒント
Epsilonは、丸めエラーの対象となる2つの数値が「等しい」と見なされるほど十分に近いかどうかを判断するために使用されます。テストする方が良いことに注意してください fabs(b/c - 1) < EPS
よりも fabs(b-c) < EPS
, 、そしてさらに良い - IEEEフロートのデザインのおかげで - テストする abs(*(int*)&b - *(int*)&c) < EPSI
(ここで、Epsiは小整数です)。
あなたの問題は異なる性質であり、おそらく入力ではなく結果をテストする必要があります。