1

私のコードは、タスクを解決するために(ゲームロジックティックで)二次方程式を解きます-空間内の可動オブジェクトの軌道に沿って衛星ティックオフセットを見つけます。また、判別式 (さらに遠いD) の計算でエラーが発生しました。思い出させます: D = b^2 - 4ac. 大きな天体の軌道なので、 my ab&cは次のような次数です。

1E+8 1E+12 1E+16

したがって、b^2注文数は約1E+24、 &4acも約1E+24です。しかし、この方程式の根ははるかに少ない数値です。なぜなら、それらはシーン上の座標にすぎないからです。だから根は約1E+3 ... 1E+4です。

問題(更新 - 具体化)b^2 float(およびdouble)の値が浮動し4acているため、十分に小さい不正確さがあります(これらの非常に大きな数に比べて[測定された絶対的な不正確さは約です1E+18])、しかしD==の違いとしてその中で、D(大きな値側から)が前述の不正確さである(1E+18)のオーダーの値になると、その値は約範囲で変動し始めます+1E+18 .. -1E+18(つまり、変動幅は実際の[-100%.. +100%]よりも広いです)価値!

明らかに、この変動は間違った (間違った方向の) ティック オフセットを引き起こします。そして、私の衛星はぐらつき始めます(そしてそれはひどいです))。

注:「いつDゼロに近づいているか」と言ったとき、実際にDはまだゼロから十分に離れているため、この範囲の値でゼロに割り当てることはできません。

固定小数点計算を使用することを検討しました (これにより、問題から救われる可能性があります)。ただし、tick ロジックでの使用は推奨されていません (最適化されておらず、おそらく非常に遅くなるからです)。

私の質問:どうすれば問題を解決できますか? 私の場合、いくつかの一般的な解決策があるでしょうか?アドバイスありがとうございます!

PS: すべての数式は適切です (コード内のフロートが失敗したときに、すべてを Excel で計算して適切な結果を得ました)。

PPS: float の代わりに double を試しました (すべての計算ではありませんが、私のa, b&cは現在 double です) & 問題は消えませんでした。

更新:a間違えました - 、b&の順序の混乱した順序c。では、「b^2は についての注文数1E+16、 &4acは について1E+28」 が間違っていました。これで両方に修正され1E+24ました。(私はすでに書かれたコメントにこれを書いたが理解できた)

更新#2:「問題」セクションが具体化されました。

更新#3:値の実際のケース(参照用):注:ここでは「正確な値」として、Excelで手動で計算された値をマークしています。

a == 1.43963872E+8
b == 3.24884062357827E+12
c == 1.83291898112689E+16

//floats:
b^2 == 1.05549641E+25
4ac == 1.05549641E+25
D == 0.0
root:
y = -1.12835273E+4

//doubles:
b^2 == 1.0554965397412443E+25
4ac == 1.0554964543412880E+25
D == 8.5399956328598733E+17
roots:
y1 == -1.1280317962726038E+4
y2 == -1.1286737079932651E+4

//accurate values:
b^2 == 1.05549653974124E+25
4ac == 1.05549645434129E+25
D == 8.53999563285987E+17
roots: 
y1 == -1.128031796E+4 
y2 == -1.128673708E+4

double で OK のように見えますが、そうではありません。ここでは計算の一部のみを示しています。ここでは、同じ a、b、c の値から開始しますが、コード内の実際の値も計算されます。また、不正確さが含まれているため、doubles でも​​問題が発生します。

4

3 に答える 3

1

C++ には、判別式 d = √(b 2 - 4ac)fma()の堅牢な計算を介して、特定の浮動小数点型内で二次方程式の根の計算を可能な限り正確にする簡単な方法を提供する標準数学ライブラリ関数があります。 :

/*
  Compute a*b-c*d with error < 1.5 ulp

  Claude-Pierre Jeannerod, Nicolas Louvet, and Jean-Michel Muller, 
  "Further Analysis of Kahan's Algorithm for the Accurate Computation of 2x2 Determinants". 
  Mathematics of Computation, Vol. 82, No. 284, Oct. 2013, pp. 2245-2264
*/
T diff_of_products (T a, T b, T c, T d)
{
    T w = d * c;
    T e = fma (-d, c, w);
    T f = fma (a, b, -w);
    return f + e;
}

/* George E. Forsythe, "How Do You Solve a Quadratic Equation"
   Stanford University Technical Report No. CS40 (June 16, 1966)
*/ 
T a, b, c;
T d = diff_of_products (b, b, 2*a, 2*c);
T x1 = 2*c / (-b - sqrt (d));
T x2 = 2*c / (-b + sqrt (d));

によって実装される融合乗加算演算 ( FMA ) はfma()、最新のプロセッサ アーキテクチャの単一のハードウェア命令にマップされます。FMA は、加算前に丸められていない倍幅の完全な積を計算するため、積の誤差を正確に計算するために使用されます。

サイモン・バーンが彼の答えでほのめかしたように、目前の特定の問題は悪条件であり、正確な計算ではこれを修正できず、基礎となる数学の再定式化のみが修正できます。

于 2016-12-12T17:49:15.083 に答える