用C ++创建正弦查找表

时间:2010-09-10 21:57:09

标签: c++ lookup pseudocode sine

如何在C ++中重写以下伪代码?

real array sine_table[-1000..1000]
    for x from -1000 to 1000
        sine_table[x] := sine(pi * x / 1000)

我需要创建一个sine_table查找表。

6 个答案:

答案 0 :(得分:29)

通过仅存储第一象限的值,即[0,pi / 2]中的x,您可以将表的大小减小到原始值的25%。

为此,您的查找例程只需要使用简单的trig标识将x的所有值映射到第一象限:

  • sin(x)= - sin(-x),从象限IV映射到I
  • sin(x)= sin(pi - x),从象限II映射到I

要从象限III映射到I,请应用两个身份,即sin(x)= - sin(pi + x)

此策略是否有用取决于您的情况下内存使用量的重要性。但是,为了避免在查找期间进行比较和减法或两次,存储四倍的值似乎是浪费。

我第二个Jeremy建议测量构建表是否比使用std :: sin()更好。即使使用原始的大表,您也必须在每次表查找期间花费周期来将参数转换为最接近的pi / 1000增量,并且您将在此过程中失去一些准确性。

如果你真的试图以速度来换算准确度,你可以尝试仅使用泰勒级数展开的前几个项逼近sin()函数。

  • sin(x)= x - x ^ 3/3! + x ^ 5/5! ......,其中^表示提升到力量!代表阶乘。

当然,为了提高效率,您应该预先计算阶乘并利用x的较低幂来计算更高的幂,例如在计算x ^ 5时使用x ^ 3.

最后一点,上面截断的泰勒级数对于接近零的值更准确,因此在计算近似正弦之前仍然值得映射到第一或第四象限。

附录: 然而,基于两个观察结果还有一个潜在的改进: 1.如果你能在第一个八分圆[0,pi / 4]中计算正弦和余弦,你可以计算任何三角函数。 2.以零为中心的泰勒级数展开在零附近更准确

因此,如果您决定使用截断的泰勒级数,那么您可以通过映射到正弦或余弦来提高精度(或使用更少的术语以获得相似的精度),以获得[0,pi / 4]范围内的角度使用像sin(x)= cos(pi / 2-x)和cos(x)= sin(pi / 2-x)这样的标识以及上面的标识(例如,如果x> pi / 4,则为'已映射到第一象限。)

或者如果您决定对正弦和余弦使用表查找,您可以使用两个较小的表来覆盖范围[0,pi / 4],但代价是另一个可能的比较和减法查找映射到较小的范围。然后,您可以为表使用更少的内存,或使用相同的内存,但提供更精细的粒度和准确性。

答案 1 :(得分:5)

您需要std::sin()的{​​{1}}功能。

答案 2 :(得分:4)

long double sine_table[2001];
for (int index = 0; index < 2001; index++)
{
    sine_table[index] = std::sin(PI * (index - 1000) / 1000.0);
}

答案 3 :(得分:4)

还有一点:调用三角函数是昂贵的。如果你想用常数步骤为正弦值准备查找表 - 你可以节省计算时间,以牺牲一些潜在的精度损失。

考虑你的最小步骤是“a”。也就是说,你需要罪(a),罪(2a),罪(3a),......

然后你可以做以下技巧:首先计算sin(a)和cos(a)。然后对于每个连续步骤使用以下三角等式:

  • sin([n + 1] * a)= sin(n * a)* cos(a)+ cos(n * a)* sin(a)
  • cos([n + 1] * a)= cos(n * a)* cos(a) - sin(n * a)* sin(a)

此方法的缺点是在此过程中累积了舍入误差。

答案 4 :(得分:3)


double table[1000] = {0};
for (int i = 1; i <= 1000; i++)
{
    sine_table[i-1] = std::sin(PI * i/ 1000.0);
}

double getSineValue(int multipleOfPi){ if(multipleOfPi == 0) return 0.0; int sign = 1; if(multipleOfPi < 0){ sign = -1;
} return signsine_table[signmultipleOfPi - 1]; }

您可以通过技巧sin(pi / 2 +/- angle)= +/- cos(角度)将数组长度减少到500。 因此,将sin和cos存储在0到pi / 4之间。 我不记得我的头脑,但它提高了我的节目速度。

答案 5 :(得分:3)

书籍或其他内容的另一种近似

streamin ramp;
streamout sine;

float x,rect,k,i,j;

x = ramp -0.5;

rect = x * (1 - x < 0 & 2);
k = (rect + 0.42493299) *(rect -0.5) * (rect - 0.92493302) ;
i = 0.436501 + (rect * (rect + 1.05802));
j = 1.21551 + (rect * (rect - 2.0580201));
sine = i*j*k*60.252201*x;

在这里进行充分讨论: http://synthmaker.co.uk/forum/viewtopic.php?f=4&t=6457&st=0&sk=t&sd=a

我认为你知道,使用除法比乘以十进制数慢很多,/ 5总是慢于* 0.2

这只是一个近似值。

也:

streamin ramp;
streamin x;  // 1.5 = Saw   3.142 = Sin   4.5 = SawSin
streamout sine;
float saw,saw2;
saw = (ramp * 2 - 1) * x;
saw2 = saw * saw;

sine = -0.166667 + saw2 * (0.00833333 + saw2 * (-0.000198409 + saw2 * (2.7526e-006+saw2 * -2.39e-008)));
sine = saw * (1+ saw2 * sine);