3

range の値に基づいて 3D 間隔でポイントを計算する関数があります[0, 1]私が直面している問題は、2 進浮動小数点数が正確に 1 を表すことができないということです。

関数で評価される数式は の値を計算できますが、計算するt=1.0前に範囲がチェックされるため、値が関数によって受け入れられることはありません。

curves_error curves_bezier(curves_PointList* list, curves_Point* dest, curves_float t) {
    /* ... */
    if (t < 0 || t > 1)
        return curves_invalid_args;
    /* ... */
    return curves_no_error;
}

この関数を使用して、どのように の 3 次元点を計算できt=1.0ますか? 少し前に、そのような問題に関係していると思われることを聞いたことがありELLIPSISますが、よくわかりません。

ありがとう

編集:わかりました、ごめんなさい。私が直面している問題のため、フロートは正確に 1 を表すことができないと想定しました。問題は、次のような反復を行っていたことが原因である可能性があります。

for (t=0; t <= 1.0; t += 0.1) {
    curves_error error = curves_bezier(points, point, t);
    if (error != curves_no_error)
        printf("Error with t = %f.\n", t);
    else
        printf("t = %f is ok.\n", t);
}
4

3 に答える 3

8
for (t=0; t <= 1.0; t += 0.1) {

あなたの問題は、バイナリ浮動小数点数が を正確に表すことができないこと0.1です。

最も近い 32 ビットの単精度 IEEE754 浮動小数点数は 0.100000001490116119384765625 であり、最も近い 64 ビットの倍精度浮動小数点数は 0.10000000000000005551151231257827021181583404541015625 です。厳密に 32 ビット精度で演算すると、0.1f0 に 10 回足した結果は

1.00000011920928955078125

中間計算がより高い精度で実行される場合float、正確に1.0、またはわずかに小さい数値になる可能性があります。

問題を解決するには、この場合、使用できます

for(k = 0; k <= 10; ++k) {
    t = k*0.1;

ですので10 * 0.1fぴったり1.0です。

curves_bezier別のオプションは、関数で小さな許容誤差を使用することです。

if (t > 1 && t < 1 + epsilon) {
    t = 1;
}

適切に小さいイプシロンの場合、おそらくfloat epsilon = 1e-6;.

于 2012-11-22T12:56:13.223 に答える
4

2 進浮動小数点数は正確に 1 を表すことができません

それがここにあることの証明

最も正確な表現 = 1.0E0

問題がある可能性があります

  1. 2 を基数とする無限の小数桁を持つ小数
  2. 精度を失うことなく正確に表すには小さすぎる数値
  3. 精度を失うことなく表すには大きすぎる数値。

しかし1.0、それらのどれもありません!

ただし 0.1、問題のケースであり、ポイント番号 1 に違反しています。これを見てください

最も正確な表現 = 1.00000001490116119384765625E-1

したがって、0.1 を 10 回足すと、1.00000001490116119384765625E-0どちらが より大きいかがわかり1.0ます。

(例は IEEE754 単精度 32 ビット浮動小数点数)

考えられる解決策:

int i;
for (i=0; i <= 10; i++) {
    t=i/10.0;
    curves_error error = curves_bezier(points, point, t);
    if (error != curves_no_error) {
        printf("Error with t = %f.\n", t);
    }
    else {
        printf("t = %f is ok.\n", t);
    }
}

こうすれば、バイナリ形式のエラーが集計されません!

(注:if andステートメントには余分な中括弧を使用しましたelse。そうしてください。いつか感謝するでしょう。)

于 2012-11-22T12:55:09.273 に答える
2

浮動小数点数を比較するときは、他の回答で言及されている理由から、それらが完全に等しくないほど十分に近いかどうかを確認する必要があります。

#define EPSILON 0.000001f
#define FEQUAL(a,b) (fabs((a) - (b)) < EPSILON)
于 2012-11-22T13:00:01.690 に答える