【发布时间】:2016-10-08 05:02:06
【问题描述】:
用例是为数字合成生成正弦波,因此,我们需要计算 sin(d t) 的所有值,其中:
t是一个整数,代表样本数。这是可变的。一小时 CD 音质的范围是 0 到 158,760,000。
d 是双精度的,表示角度的增量。这是恒定的。范围是:大于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);
}
在这里,我确保将 0 到 2*pi 范围内的数字提供给“sin”函数。
但是,现在的问题是,当 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
【问题讨论】:
-
为什么不能先计算 (double) (t) * d 然后减去足够的 2*pi 使结果小于 2*pi。
-
请参阅Is it possible to make realistic n-body solar system simulation in matter of size and mass? 在该答案的底部(最后一次编辑)是您想要的一种简单技术。
-
正弦波的频率是整数赫兹吗?如果是这样,您可以每 44100 个样本将 d_sum 重置为零
-
你确定
accuracy gets reduced because big numbers provided to "sin" function?我的示例没有显示这一点(至少对于 x87 指令而言) -
这类问题的正确受众可能在dsp.stackexchange.com
标签: c algorithm audio trigonometry sound-synthesis