如何用 C 语言正确构建 sin 查找表?

use*_*248 3 c trigonometry lookup-tables

为了节省调用性能sin,并处理整数角度(更便于操作和保存),而不是使用浮点作为角度,我正在构建一个sin查找函数,其中 4096 个单位等于 2pi 弧度。为了节省内存,我只存储前 1024 个 sin 值,它们相当于sin( [0, pi/2) ).

static const float SinTable[1024] = {0, 0.00153398, ..., 0.999995, 0.999999};
Run Code Online (Sandbox Code Playgroud)

为了处理第三象限​​和第四象限的角度,我简单地有条件地否定:

return Angle&2048 ? -UnsignedSin : UnsignedSin;
Run Code Online (Sandbox Code Playgroud)

UnsignedSin查找到的 sin 值位于 之间的位置[0, 2048)。但我该如何处理第二象限和第四象限呢?如何通过检查角度是否位于第二或第四象限(例如 )[0, 1)来有条件地正确映射 存储的 sin 值?我尝试了这个,但这不太正确,因为角度的结果是 0.999999 而不是它应该是的 1。[1, 0)Angle&10241024

const float UnsignedSin = SinTable[(Angle&1024 ? ~A : A)&1023];
Run Code Online (Sandbox Code Playgroud)

1 的值永远不会存储在 sin 表中,所以我假设 a1-SinTable[...]是必需的?但我不能完全正确地理解它。

Bre*_*dan 5

这会是这样的:

float getSine(unsigned int angle) {
    angle &= 4095;        // Reduce angle to the range of 1 circle

    if( (angle & 2048) == 0) {
        if( (angle & 1024) == 0) {
            // Angle is from 0 to 1023
            return SinTable[angle];
        } else {
            // Angle is from 1024 to 2047
            return SinTable[2048-angle];
        }
    } else {
        if( (angle & 1024) == 0) {
            // Angle is from 2048 to 3071
            return -SinTable[angle-2048];
        } else {
            // Angle is from 3072 to 4095
            return -SinTable[4096-angle];
        }
    }
Run Code Online (Sandbox Code Playgroud)

请注意,此代码SinTable需要 1025 个条目,因此SinTable[1024]有效并包含值 1.0。仅当原始角度为 1024 或 3072(其中SinTable[2048-1024];SinTable[4096-3072]; 变为SinTable[1024];)时才会发生这种情况。这些角度可以作为特殊情况处理(例如if( (angle == 1024) || (angle == 3072) ) return 1.0;),但这可能会更慢(由于分支预测错误等)。

另请注意,可以通过使用线性插值来提高精度。例如,您可以说它angle是 20 位,范围从 0 到 1048575;然后使用位 8 到 19 作为表的索引(如SinTable[angle >> 8])来确定较低的值和下一个值;然后int factions = angle & 0xFF; result = ( lower_value * (0x100 - factions) + upper * fractions ) / 0x100;进行估计。