Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/powerbi/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Floating point 罪,因,因不准确_Floating Point_Trigonometry_Floating Accuracy - Fatal编程技术网

Floating point 罪,因,因不准确

Floating point 罪,因,因不准确,floating-point,trigonometry,floating-accuracy,Floating Point,Trigonometry,Floating Accuracy,当参数接近pi的非零倍数时,sinl为什么给出不正确的结果?当参数较大时,sinl为什么给出不正确的结果?下面的代码说明了这一点 请注意,用于初始化变量pi的数字与任何64位长的双精度值都不完全匹配。编译器选择最接近的值,即3.14159265358979323851280895940618620443274267017841339111328125。可以使用libquadmath、gnu-MPFR-lib或在线计算器(例如)找到期望的正弦值 #包括 #包括 int main(int argc,

当参数接近pi的非零倍数时,
sinl
为什么给出不正确的结果?当参数较大时,
sinl
为什么给出不正确的结果?下面的代码说明了这一点

请注意,用于初始化变量pi的数字与任何64位长的双精度值都不完全匹配。编译器选择最接近的值,即
3.14159265358979323851280895940618620443274267017841339111328125
。可以使用libquadmath、gnu-MPFR-lib或在线计算器(例如)找到期望的正弦值

#包括
#包括
int main(int argc,char*argv[])
{
挥发性长双pi=3.14159265358979323846L;
挥发性长双大=9223372035086174241L;
挥发性长双预期值1=-5.0165576126683320235E-20L;
挥发性长双预期值2=-4.205336735954077951E-10L;
双重结果;
双ex1=expected1,ex2=expected2;
结果=sinl(pi);
printf(“预期的:%g,\n返回的:%g\n\n”,ex1,结果);
结果=sinl(大);
printf(“预期的:%g,\n返回的:%g\n\n”,ex2,结果);
返回0;
}
我使用的是GCC4.7.3。使用volatile可以防止编译器用硬编码结果替换
sinl()
调用。我的电脑有一个Intel Core i7处理器,运行Windows。我将结果打印为double而不是long double,因为我使用的gcc的mingw端口不支持打印long double。以下是程序输出:

expected: -5.01656e-020,
returned: -5.42101e-020

expected: -4.20533e-010,
returned: -0.011874

误差可以追溯到sinl库代码使用的fsin处理器指令。fsin、fcos和fptan指令不符合英特尔声称的1.0 ulp:

GNU libc的文档(通过运行
info libc math errors
可访问)列出了x86和“x86_64/fpu”上
cosl的1 ulp“已知错误”。它不记录
sinl
的任何内容。在我的x86_64机器上,我可以在pi/2附近为cosl重现类似的巨大错误

也许您应该将此作为一个文档错误报告给glibc和Linux手册页人员;我无法想象实施“正确”的修复是否值得


如果你真的想要一个快速准确的
sinl
,我不太确定该去哪里找。不执行
sin
(双精度
s的变体)。将处理它,但它将比fsin慢很多倍。为了实现1 ULP精度的pi倍数,内部常数M_pi应具有约106位精度(或128位长倍精度)

在缩减阶段,一个完美的实现必须在减去
(x-M_PI)
后以某种方式生成丢失的53或64位精度,因为一个简单的实现会将这个中间值计算为零。当参数是非零的大整数倍时,问题当然会越来越大


M_PI的66位内部精度不足以达到1 ULP精度。然后,可以再次阅读声明,并检查1 ULP相对于结果或参数的准确性。

要求阅读:(特别是对于第二次测试)。此外,使用精确到最后一位的pi值,而不是代码中的近似值,也会有所帮助。(不幸的是,
M_PI
是一个
double
,而不是
long double
。请尝试使用
PI=acosl(-1.0L);
)预期值来自何处?圆周率的正弦值应该是0。@TedHopp:看在上帝的份上,如果你要链接到那个页面并称之为“必读”,至少要读一读。@TedHopp:Nothing;这是一个很好的介绍。但你显然从未阅读或理解过你链接的页面。代码中使用的
pi
值足够精确。最接近π的浮点数的正弦值不会是零。@ThomasPadron McCarthy:他在问为什么他从库函数中得到了非常不正确的结果。他正在大声而清晰地做这件事。我不确定我是否看到了问题。@TedHopp
3.14159265358979323846L
是最接近π的
long double
,或者OP有编译器问题(注意:OP有编译器问题,可能不是这个问题)。有一个近似值,但该值“精确到最后一位”,即需要更多位才能获得更好的近似值。π的正弦应该是零,但是sinl(3.14159265358979323846L)
可以预期到离零的ULP_longdouble(3)/2。因此,如果我正确地阅读了这些图,一个,至少部分的补救方法是使用模来限制值为Yes。但我认为以所需的精度进行模运算不会是直接的。一个挑战是长双精度不能很好地逼近pi。除非有聪明的方法,否则我认为需要远远超过128位的pi来对trig函数进行参数缩减。计算精度为64位的mod pi时,似乎需要pi到大约16450位。如果有一个整数倍的π,它被一个长双精度
非常好地近似。是的,一旦你超过了长长双精度的范围,你需要每个指数增加一个比特。我只是从问题的上下文(x=2^63一些)假设人们并没有真正期望得到sin(10^6000)的精确结果。合理质量的三角函数的实现不使用
M_PI
进行简化。使用了类似Payne-Hanek算法的方法。本质上,执行1/π的乘法,但这是一种专门的乘法,只返回分数位,丢弃整数值。由于整数值被丢弃,因此不需要1/π的所有位。所需的最高位由输入操作数的大小决定,最低位由一些数论公式决定