19

a / (b - c)問題を簡潔にするために、s の式を計算したいとしましょうfloat

結果が意味のあるものであることを確認するために、bcが等しいかどうかを確認できます。

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;

結果: if 条件は満たされませんが、式は正しい結果 100000008 を生成します (float の精度に関して)。

ケース 2:

a = 1e33f;
b = 0.000003;
c = 0.000002;

結果: if 条件は満たされていますが、式は意味のある結果を生成しません+1.#INF00

引数ではなく、結果を確認する方がはるかに信頼性が高いことがわかりました。

const float INF = numeric_limits<float>::infinity();
float x = a / (b - c);
if (-INF < x && x < INF)
{
     return x;
}

しかし、イプシロンは何のためにあり、イプシロンが使いやすいと誰もが言っているのはなぜですか?

4

2 に答える 2

23

"you must use an epsilon when dealing with floats" is a knee-jerk reaction of programmers with a superficial understanding of floating-point computations, for comparisons in general (not only to zero).

This is usually unhelpful because it doesn't tell you how to minimize the propagation of rounding errors, it doesn't tell you how to avoid cancellation or absorption problems, and even when your problem is indeed related to the comparison of two floats, it doesn't tell you what value of epsilon is right for what you are doing.

If you have not read What Every Computer Scientist Should Know About Floating-Point Arithmetic, it's a good starting point. Further than that, if you are interested in the precision of the result of the division in your example, you have to estimate how imprecise b-c was made by previous rounding errors, because indeed if b-c is small, a small absolute error corresponds to a large absolute error on the result. If your concern is only that the division should not overflow, then your test (on the result) is right. There is no reason to test for a null divisor with floating-point numbers, you just test for overflow of the result, which captures both the cases where the divisor is null and where the divisor is so small as to make the result not representable with any precision.

Regarding the propagation of rounding errors, there exists specialized analyzers that can help you estimate it, because it is a tedious thing to do by hand.

于 2010-04-28T13:21:49.710 に答える
3

Epsilon は、丸め誤差の対象となる 2 つの数値が「等しい」と見なされるほど近いかどうかを判断するために使用されます。fabs(b/c - 1) < EPSよりもテストする方が良いことに注意してくださいfabs(b-c) < EPS.IEEEフロートの設計のおかげで、テストする方がさらに良いですabs(*(int*)&b - *(int*)&c) < EPSI(EPSIは小さな整数です)。

あなたの問題は性質が異なり、おそらく入力ではなく結果をテストする必要があります。

于 2010-04-28T13:21:07.127 に答える