我目前正在研究余弦的近似值。由于最终的目标设备是使用 32 位浮点 ALU / LU 自行开发的设备,并且有专门的 C 编译器,因此我无法使用 c 库数学函数(cosf,...)。我的目标是编写在准确性和指令/周期数方面不同的各种方法。
我已经尝试了很多不同的逼近算法,从 fdlibm、taylor 展开、pade 逼近、remez 算法使用 maple 等等......
但是,一旦我只使用浮点精度来实现它们,精度就会大大降低。并且可以肯定:我知道使用双精度,更高的精度完全没有问题......
现在,我有一些近似值,精确到 pi/2 附近的几千 ulp(发生最大误差的范围),我觉得我受到单精度转换的限制。
为了解决主题参数减少:输入以弧度为单位。我假设参数减少会由于除法/乘法而导致更多的精度损失......因为我的整体输入范围只有 0..pi,我决定将参数减少到 0..pi/2。
因此我的问题是:有没有人知道高精度的余弦函数的单精度近似(并且在最好的情况下是高效率的)?是否有任何算法可以优化单精度近似值?你知道内置的 cosf 函数是否在内部以单精度或双精度计算值?~
float ua_cos_v2(float x)
{
float output;
float myPi = 3.1415927410125732421875f;
if (x < 0) x = -x;
int quad = (int32_t)(x*0.63661977236f);//quad = x/(pi/2) = x*2/pi
if (x<1.58f && x> 1.57f) //exclude approximation around pi/2
{
output = -(x - 1.57079637050628662109375f) - 2.0e-12f*(x - 1.57079637050628662109375f)*(x - 1.57079637050628662109375f) + 0.16666667163372039794921875f*(x - 1.57079637050628662109375f)*(x - 1.57079637050628662109375f)*(x - 1.57079637050628662109375f) + 2.0e-13f*(x - 1.57079637050628662109375f)*(x - 1.57079637050628662109375f)*(x - 1.57079637050628662109375f)*(x - 1.57079637050628662109375f)+ 0.000198412701138295233249664306640625f*(x - 1.57079637050628662109375f)*(x - 1.57079637050628662109375f)*(x - 1.57079637050628662109375f)*(x - 1.57079637050628662109375f)*(x - 1.57079637050628662109375f)*(x - 1.57079637050628662109375f)*(x - 1.57079637050628662109375f);
output -= 4.37E-08f;
}
else {
float param_x;
int param_quad = -1;
switch (quad)
{
case 0:
param_x = x;
break;
case 1:
param_x = myPi - x;
param_quad = 1;
break;
case 2:
param_x = x - myPi;
break;
case 3:
param_x = 2 * myPi - x;
break;
}
float c1 = 1.0f,
c2 = -0.5f,
c3 = 0.0416666679084300994873046875f,
c4 = -0.001388888922519981861114501953125f,
c5 = 0.00002480158218531869351863861083984375f,
c6 = -2.75569362884198199026286602020263671875E-7f,
c7 = 2.08583283978214240050874650478363037109375E-9f,
c8 = -1.10807162057025010426514199934899806976318359375E-11f;
float _x2 = param_x * param_x;
output = c1 + _x2*(c2 + _x2*(c3 + _x2*(c4 + _x2*(c5 + _x2*(c6 + _x2*(c7
+ _x2* c8))))));
if (param_quad == 1 || param_quad == 0)
output = -output;
}
return output;
}
~
如果我忘记了任何信息,请随时询问!
提前致谢