为什么sinl
在参数接近pi的非零倍数时会给出不正确的结果?为什么sinl
在参数很大时会给出错误的结果?以下代码说明了这一点。sin,cos,tan不准确
请注意,用于初始化变量pi的数字并不完全匹配任何64位长的double值。编译器选择最接近的值,即3.14159265358979323851280895940618620443274267017841339111328125
。预期的正弦值可以使用libquadmath,gnu MPFR lib或在线计算器(如http://www.ttmath.org/online_calculator)找到。
#include <stdio.h>
#include <math.h>
int main (int argc, char *argv [])
{
volatile long double pi = 3.14159265358979323846L;
volatile long double big = 9223372035086174241L;
volatile long double expected1 = -5.0165576126683320235E-20L;
volatile long double expected2 = -4.2053336735954077951E-10L;
double result;
double ex1 = expected1, ex2 = expected2;
result = sinl (pi);
printf("expected: %g, \nreturned: %g\n\n", ex1, result);
result = sinl (big);
printf("expected: %g, \nreturned: %g\n\n", ex2, result);
return 0;
}
我使用的是gcc 4.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
必需阅读:[每个计算机科学家应该了解的浮点运算_](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html)(特别是针对您的第二个测试)。此外,它将有助于使用pi值精确到最后一位,而不是代码中的近似值。 (不幸的是,'M_PI'是一个'double',而不是'long double',尝试使用'pi = acosl(-1.0L);')期望值来自哪里? PI的正弦应该为0. –
@TedHopp:看在上帝的份上,如果你打算链接到那个页面并称之为“必需的阅读”,至少要阅读它。 – tmyklebu
@tmyklebu - 我读过它了。它出什么问题了? –