決定論的であり、異なるプラットフォーム (コンパイラ) で同じ結果を提供する必要があるプログラムの場合、組み込みの三角関数は使用できません。これは、それを計算するアルゴリズムがシステムによって異なるためです。結果値が異なることがテストされました。
(編集: すべてのクライアントで実行されるゲーム シミュレーションで使用されるため、結果は最後のビットまでまったく同じである必要があります。これらのクライアントは、シミュレーションを機能させるために、シミュレーションの状態がまったく同じである必要があります。エラーは、時間の経過とともにますます大きなエラーになる可能性があり、ゲーム状態の crc も同期のチェックとして使用されます)。
したがって、私が思いついた唯一の解決策は、独自のカスタム コードを使用してこれらの値を計算することでした。問題は、(驚くべきことに) 三角関数のすべてのセットの使いやすいソース コードを見つけるのが非常に難しいことです。
これは、sin 関数用に取得したコード ( https://codereview.stackexchange.com/questions/5211/sine-function-in-cc ) を変更したものです。これはすべてのプラットフォームで決定論的であり、値は標準の sin の値とほぼ同じです (両方ともテスト済み)。
#define M_1_2_PI 0.159154943091895335769 // 1 / (2 * pi)
double Math::sin(double x)
{
// Normalize the x to be in [-pi, pi]
x += M_PI;
x *= M_1_2_PI;
double notUsed;
x = modf(modf(x, ¬Used) + 1, ¬Used);
x *= M_PI * 2;
x -= M_PI;
// the algorithm works for [-pi/2, pi/2], so we change the values of x, to fit in the interval,
// while having the same value of sin(x)
if (x < -M_PI_2)
x = -M_PI - x;
else if (x > M_PI_2)
x = M_PI - x;
// useful to pre-calculate
double x2 = x*x;
double x4 = x2*x2;
// Calculate the terms
// As long as abs(x) < sqrt(6), which is 2.45, all terms will be positive.
// Values outside this range should be reduced to [-pi/2, pi/2] anyway for accuracy.
// Some care has to be given to the factorials.
// They can be pre-calculated by the compiler,
// but the value for the higher ones will exceed the storage capacity of int.
// so force the compiler to use unsigned long longs (if available) or doubles.
double t1 = x * (1.0 - x2 / (2*3));
double x5 = x * x4;
double t2 = x5 * (1.0 - x2 / (6*7)) / (1.0* 2*3*4*5);
double x9 = x5 * x4;
double t3 = x9 * (1.0 - x2 / (10*11)) / (1.0* 2*3*4*5*6*7*8*9);
double x13 = x9 * x4;
double t4 = x13 * (1.0 - x2 / (14*15)) / (1.0* 2*3*4*5*6*7*8*9*10*11*12*13);
// add some more if your accuracy requires them.
// But remember that x is smaller than 2, and the factorial grows very fast
// so I doubt that 2^17 / 17! will add anything.
// Even t4 might already be too small to matter when compared with t1.
// Sum backwards
double result = t4;
result += t3;
result += t2;
result += t1;
return result;
}
しかし、asin、atan、tan (sin/cos 以外) など、他の関数に適したものは見つかりませんでした。
これらの関数は、標準のものほど正確ではありませんが、少なくとも 8 つの数字があればよいでしょう。