2015-07-20 376 views
1

这是我没有想到的。我知道这些数字是不准确100%,但我没想到余角给人sin不同的结果和cos为什么sin(45)和cos(45)给出不同的结果?

这下面的函数返回0.70710678118654746000000...

sin(45 * PI/180.0); 

而这follwing函数返回0.70710678118654757000000...

cos(45 * PI/180.0); 

所以,它的:

0.707106781186547**46**000000... vs 
0.707106781186547**57**000000... 

而不仅仅是... sin(1 * PI/180.0)也返回比cos(89 * PI/180.0)略有不同数量虽然他们应该是相同的。

而且这不仅是一个sin VS cos问题,它也是一个sin VS sin问题:sin(1 * PI/180.0)sin(179 * PI/180.0)返回不同的值,他们又应该是相同的。

我试图用弧度,而不是学位,并有完全一样的区别,我试图用一个小的PI值,一个巨大的PI值(约100个小数和更多),他们还在不同的,我试过使用cmath而不是math.h,我试图使用M_PI而不是我自己定义的PI

其差值总是相同的,大约在小数点后16位。不要误解我的意思,我知道我永远不会得到这些数字的100%精确值,但至少我期望得到相互补充角度的sincos相同的“不精确”值。这一切到底是什么错误?


我需要他们一样,因为我的工作(重力模拟器我被要求做)的程序使用具有double(我也试过float)对象它们基本上角度变量(度或弧度,我都试过)。这些是物体移动的方向,也需要角度来计算物体之间的相互作用。

在程序的每一次迭代中角度都会改变,并且在每次迭代中,角度都会根据前一次迭代角度的计算而改变,所以如果在任何一点上有任何最小错误的角度值,该误差会被放大得更多并在每一次迭代中更多。

该程序运行数千甚至数百万次的迭代,所以该值的错误变得荒谬可笑!说得清楚,行星最终得到了他们的平衡,一切都变得一场灾难,我真的疯了:(

附言:我在Windows 7中,32位。

+2

这里只有约16的精度十进制数字在编译双倍。 – ooga

+0

嗯,我知道我永远不会为罪(45)获得完美的价值,这样的价值不存在,完美的圆形PI值也不存在,但我至少期待互补的角度出错以相同的方式:/ – Dimakhaerus

+1

您可能想要查找(或实现)符号计算库。当然,你会为了精确而牺牲性能。 –

回答

3

我知道我会从来没有得到这些数字的100%的精确值,但 至少我是期望得到互补角度的正弦和余弦 的相同的“unprecise”值。

为什么?计算方式不同,因此会发生不同的浮点错误(并累计)。你看到的不是一个错误;数学规律并不能预测FP算术。

顺便说一句,提供例如。如果您的类型不能保持30位数字,则30或100位数字的PI不会有任何不同

+0

我知道关于PI的事情,这是一个绝望的尝试,使其正常工作。 那么,这显然是一个巨大的错误,无论他们如何计算,他们应该返回相同的值:/ 感谢您的回答! – Dimakhaerus

+0

@Dimakhaerus如果你认为它是一个错误,那么提出解决方案怎么样?对,不可能达到这样的期望,因为有这样的无限特殊情况。例如'sin(60)== sqrt(3)/ 2'是另一个。 ......如果没有足够的内存,就会出现错误,而且没有任何东西可以阻止这种情况发生。 – deviantfan

+0

即使提供30位数字对于大多数用途来说都是过度杀伤,从内存来看,“355/113”足以在地球表面定位汽车。 '3.141592653589'(我可以记住我的头顶)可能(但我没有检查)在太阳系中找到豌豆:-) – paxdiablo

2

不管它们是如何计算出来的,他们应该返回相同的值

您的期望是不正确的。在IEEE-754中,只有基本操作员(+-*/)和sqrt需要正确舍入。 Trancendental功能,如sincosexp ...不是必需的,因为它是非常复杂的

没有标准,需要超越函数忠实四舍五入。 IEEE-754(2008)建议,但不要求,这些函数被正确舍入。


现在,如果你看一下你的价值观

         ↓ 
0.70710678118654746 = 0x1.6a09e667f3bccp-1 
0.70710678118654757 = 0x1.6a09e667f3bcdp-1 
             ↑ 

因此,他们是彼此的1ulp内,并且足够精确的双精度为

不要误会我的意思,我知道我将永远不会得到这些数字的100%的精确值,但至少我期待得到同样的“unprecise”罪的余角

的价值和cos

不仅有一个算法来计算sincos。对于某些输入集合,每个输入都是正确的,但对其他输入不正确。他们也有不同的内存和时间要求,所以有些人可能会有更快的错误,有些需要更多的时间和内存,但他们可以达到更高的准确度。

编译器实现可能对这些函数使用不同的算法,所以如果您需要一致的结果,请使用跨平台的精心设计的单个库。例如,GCC使用MPFR来实现正确舍入的结果,而不管平台如何。

GCC中端已经与MPFR库集成。这使得GCC可以在编译时调用内置的数学函数来评估和替换具有恒定参数的内置数学函数以及它们的数学等价结果。在使用MPFR时,无论数学库实现或主机平台的浮点精度如何,GCC都可以生成正确的结果。这也允许GCC以产生相同的结果而不管中的一个是否在天然或交叉编译配置到特定目标

https://gcc.gnu.org/gcc-4.3/changes.html#mpfropts

How does C compute sin() and other math functions?

+0

谢谢!它给了我一个更好的想法,说明为什么我的程序失败了,当我的cos和sin值应该是相同的时候,我会试着强迫他们实际上是相同的,如果这不起作用,我会尝试像你说的一个不同的图书馆! :) – Dimakhaerus

+1

只是一个小小的附录:即使你对'sin'和'cos'有一个'确切'的实现(即一个从不错过0的错误)。5ulp),因为输入参数不完全是PI/4(取决于这个输入值如何舍入,正弦或余弦将变大),所以在这里你不会得到相同的正弦和余弦值。在计算'sin(M_PI)'时(这不是0.0),你实际上可以观察到类似的问题。 – chtz

相关问题