与数学库 sin 相比,sin 函数不准确

Posted

技术标签:

【中文标题】与数学库 sin 相比,sin 函数不准确【英文标题】:sin function not accurate compared to math lib sin 【发布时间】:2014-11-01 23:13:03 【问题描述】:

我一直在尝试实现一个快速但更重要的是准确的自定义 sin 函数(我不能在我的项目中使用 math.h sin)。当涉及到这种数学时,我不是专家,所以和我一起工作 XD。在网上搜索了一下后,我发现了以下代码,该函数在某些情况下返回的结果不准确。

float SinF(float X)

    float Sine;

    if (X < -3.14159265F) X += 6.28318531F;
    else if (X >  3.14159265F) X -= 6.28318531F;

    if (X < 0)
    
        Sine = 1.27323954F * X + .405284735F * X * X;
        if (Sine < 0) Sine = .225F * (Sine *-Sine - Sine) + Sine;
        else Sine = .225F * (Sine * Sine - Sine) + Sine;
    
    else
    
        Sine = 1.27323954F * X - 0.405284735F * X * X;
        if (Sine < 0) Sine = .225F * (Sine *-Sine - Sine) + Sine;
        else Sine = .225F * (Sine * Sine - Sine) + Sine;
    

    return Sine;

例子:

Bad result example 1:
Value Passed: 1.57079637
Returned Value: 0.999999881
Correct Value: 1.00000000

Bad result example 2:
Value Passed: 1.76704633
Returned Value: 0.980933487
Correct Value: 0.980804682

Bad result example 3:
Value Passed: 1.96329641
Returned Value: 0.924392164
Correct Value: 0.923955679

任何帮助将不胜感激。

【问题讨论】:

docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html 这已经足够精确了。您可以用精度换取速度,所以就这样。 最好显示X 范围内的相对误差,并确定可接受的相对误差。 @iccthedral 实际上,我需要 sin 来处理图像格式,所以精度比速度更重要。 【参考方案1】:

sin 和 this SO question 中的朋友有很多潜在的实现,但通常归结为一些常用方法:

内置处理器代码 (fsin) Taylor series CORDIC 带有可选线性(或更好)插值的查找表(主要是为了速度,不太准确)

还有(很多)其他方法,但这些是我见过的更常见的方法。

还要注意浮点的固有精度限制(如 user657267 linked 到)。例如,1.57079637 不完全是 pi/2,因此它的 sin() 可能不完全是 1。事实上,您列出的所有“正确”值并不完全准确。您必须确定对于您的应用程序来说,准确度有多好。

【讨论】:

在 32 位编译模式下,我在 _asm 关键字中使用处理器代码 fsin,但 _asm 关键字在 64 位模式下不可用,所以我还需要一个函数来实现这一点。我发布的正确值来自 math.h sin 函数,所以这就是我需要的准确性。我试过泰勒级数的罪,因为这似乎是网络上最常见的。我试试 CORDIC。 float 只有大约 7 个有效数字,所以您只是看到了基本类型的准确度的限制。如果您需要更高的准确性,请考虑改用double 另请注意,您的原始代码看起来可能是泰勒级数,但可能为了优化而进行了修改。 double 可能具有更高的精度,但不使用 double 应该不是问题,因为 fsin 和 math.h sin 在我的情况下都使用浮点数并返回所需的值。如果我错了,请纠正我。 AFAIK,math.h 中通常的sin() 使用double(或long double)并从float 版本向下舍入。无论哪种方式,这取决于您需要多少精度的具体情况。如果 7 sig-figs 没问题,那么 float 版本可能会很好。

以上是关于与数学库 sin 相比,sin 函数不准确的主要内容,如果未能解决你的问题,请参考以下文章

事件命令信号函数方法

C 如何计算 sin() 和其他数学函数?

Lua中的一些库

C如何计算sin()和其他数学函数?

importjava.util.*打在哪

数学实验:通过Matlab软件操作,对函数性质有进一步了解 f(x)=sin^2(1.006)x