为什么我从sin(x)和sinf(x)获得与下面(8)和(9)中相同的值?为什么我从两个不同的实现中得到[x-sinf(x)]的不同值,下面的(2)和(3)?为什么(6)给出与(5)相同的结果?
我正在使用g ++(Ubuntu / Linaro 4.6.3-1ubuntu5)4.6.3。我使用-O0来禁用优化。
背景:我正在追踪程序中的一个错误,我需要在整个程序中使用float,因为它将被移植到嵌入式系统中。但是,我目前正在PC上调试Ubuntu,因为它很方便。当x很小时,我发现像(x-s)这样的操作导致了不准确。这让我认为必定是由于灾难性的取消导致有效数字丢失。但是,当我用sinf(x)替换变量s时,不会出现不准确的问题(如(2)vs(3)所示)。我猜猜sinf()可能和sin()一样实现。如果是这样,为什么显式转换为浮动没有效果,如(4)和(5)。现在我很困惑。
int main()
{
unsigned long int xx(0x3d65c2f2);
float x(*reinterpret_cast<float*>(&xx));
float s(sinf(x));
printf("( 1) x = %.10e\n", x);
printf("( 2) x - s = %.10e\n", x-s);
printf("( 3) x - sinf(x) = %.10e\n", x-sinf(x)); // Why is it different from (2)?
printf("( 4) x - float(sinf(x)) = %.10e\n", x-float(sinf(x))); // Compare with (3). Why casting has no effect?
printf("( 5) float(x) - float(sinf(x)) = %.10e\n", float(x)-float(sinf(x))); // Compare with (3). Why casting has no effect?
printf("( 6) x - sin(x) = %.10e\n", x - sin(x));
printf("( 7) s = %.10e\n", s);
printf("( 8) sinf(x) = %.10e\n", sinf(x));
printf("( 9) sin(x) = %.10e\n", sin(x)); // Compare with (8). Is sinf() identical to sin()?
printf("(10) float(sinf(x)) = %.10e\n", float(sinf(x))); // Compare with (8). Why casting has no effect?
double s_df(sinf(x));
double s_dd(sin(x));
float s_fd(sin(x));
float s_ff(sinf(x));
printf("(20) s_df = %.10e\n", s_df);
printf("(21) s_dd = %.10e\n", s_dd); // Compare with (20). Is sinf() identical to sin()?
printf("(22) s_fd = %.10e\n", s_fd);
printf("(23) s_ff = %.10e\n", s_ff);
return 0;
}
这是输出:
$ make && ./main
g++ main.cc -Wall -c -o main.o -O0
g++ -o main main.o
( 1) x = 5.6094117463e-02
( 2) x - s = 2.9411166906e-05
( 3) x - sinf(x) = 2.9412529899e-05
( 4) x - float(sinf(x)) = 2.9412529899e-05
( 5) float(x) - float(sinf(x)) = 2.9412529899e-05
( 6) x - sin(x) = 2.9412529899e-05
( 7) s = 5.6064706296e-02
( 8) sinf(x) = 5.6064704933e-02
( 9) sin(x) = 5.6064704933e-02
(10) float(sinf(x)) = 5.6064704933e-02
(20) s_df = 5.6064704933e-02
(21) s_dd = 5.6064704933e-02
(22) s_fd = 5.6064706296e-02
(23) s_ff = 5.6064706296e-02
答案 0 :(得分:3)
在C ++中,sin
有一个重载float sin(float f)
。并且对参数类型执行重载解析,而不是返回类型。要强制使用double sin(double d)
,您需要转换参数:sin(static_cast<double>(x))
。
(2)vs(3):FP标准允许实现以比最终结果更高的准确度存储中间结果。因此,s
的值不必与(3)中sin(f)
的中间结果完全相同。
这很大程度上取决于您的编译器,编译器设置和硬件。例如,如果我在我的系统上运行代码,我会得到:
( 1) x = 5.6094117463e-02
( 2) x - s = 2.9411166906e-05
( 3) x - sinf(x) = 2.9411166906e-05
( 4) x - float(sinf(x)) = 2.9411166906e-05
( 5) float(x) - float(sinf(x)) = 2.9411166906e-05
( 6) x - sin(x) = 2.9412529899e-05
( 7) s = 5.6064706296e-02
( 8) sinf(x) = 5.6064706296e-02
( 9) sin(x) = 5.6064704933e-02
(10) float(sinf(x)) = 5.6064706296e-02
(20) s_df = 5.6064706296e-02
(21) s_dd = 5.6064704933e-02
(22) s_fd = 5.6064706296e-02
(23) s_ff = 5.6064706296e-02