使用例は、デジタル合成用の正弦波を生成することです。そのため、sin(dt) のすべての値を計算する必要があります。
tはサンプル番号を表す整数です。これは可変です。CD 品質の 1 時間のサウンドの範囲は 0 ~ 158,760,000 です。
dは double で、角度のデルタを表します。これは一定です。範囲は次のとおりです: 0 より大きい、pi より小さい。
目標は、従来のintおよびdoubleデータ型で高い精度を達成することです。パフォーマンスは重要ではありません。
単純な実装は次のとおりです。
double next()
{
t++;
return sin( ((double) t) * (d) );
}
しかし、問題は、tが増加すると、"sin" 関数に大きな数値が提供されるため、精度が低下することです。
改善されたバージョンは次のとおりです。
double next()
{
d_sum += d;
if (d_sum >= (M_PI*2)) d_sum -= (M_PI*2);
return sin(d_sum);
}
ここでは、「sin」関数に 0 から 2*pi の範囲の数値を指定するようにします。
しかし、問題は、dが小さい場合、小さな追加が多くなり、毎回精度が低下することです。
ここで問題となるのは、精度を向上させる方法です。
付録1
「「sin」関数に大きな数値が提供されるため、精度が低下します」:
#include <stdio.h>
#include <math.h>
#define TEST (300000006.7846112)
#define TEST_MOD (0.0463259891528704262050786960234519968548937998410258872449766)
#define SIN_TEST (0.0463094209176730795999323058165987662490610492247070175523420)
int main()
{
double a = sin(TEST);
double b = sin(TEST_MOD);
printf("a=%0.20f \n" , a);
printf("diff=%0.20f \n" , a - SIN_TEST);
printf("b=%0.20f \n" , b);
printf("diff=%0.20f \n" , b - SIN_TEST);
return 0;
}
出力:
a=0.04630944601888796475
diff=0.00000002510121488442
b=0.04630942091767308033
diff=0.00000000000000000000