正弦180的值为1.22465e-16

时间:2011-07-04 01:03:50

标签: ios4 floating-point

我想在ios4中实现正弦和余弦计算器:

if([operation isEqual:@"sin"]){
    operand = (operand*M_PI/180.0);
    operand=sin(operand);
}

代码为我提供了从0到90的正确答案。

当我给出180的值时,我得到1.22465e-16作为答案。我期待零。

这个小小的差异来自哪里?

4 个答案:

答案 0 :(得分:7)

为了清楚起见,您的程序 为您提供正确答案。也就是说,它完全按照你在代码中告诉它做的那样。

180*M_PI被正确舍入(根据IEEE-754),并给出值:

565.4866776461627750904881395399570465087890625

将其除以180也正确舍入,并给出结果:

3.141592653589793115997963468544185161590576171875

不是完全π的数学值。事实上,它是:

π - 0.0000000000000001224646799147...

围绕π的sin(x)的泰勒级数的一阶项是(π-x),因此sin(π - x)对于小x几乎完全是-x。实际上,您得到的结果是正确舍入的结果。图书馆无法提供更准确的答案。

正如 Ben Voigt 建议的那样,如果这实际上是一个问题,你可以通过在将度数从度数转换为弧度之前将参数减少到范围[-90,90]来解决它。更好的建议是 njuffa 使用sinpi函数来完成这项工作。 iOS没有这样的功能,但它确实有vvsinpi,它实现了向量的sin(π* x),并且可以做你想做的事情:

double result;
int vectorLength = 1;
vvsinpi(&result, &operand, &vectorLength);

请同时提交一个错误请求sinpi作为扩展名添加到数学库。

答案 1 :(得分:5)

这是由于二进制数系统无法准确表示PI。

一种可能的解决方案是使用sin的对称性:

sindeg(x) = sindeg(180 - x)

(或者):

sin(x) = sin(M_PI - x)

将角度转换为范围(-pi / 2:pi / 2)可以减少近似误差。

基本上:

if([operation isEqual:@"sin"]){
  operand = fmod(operand, 360);
  if (operand > 270) operand -= 360;
  else if (operand > 90) operand = 180 - operand;
  operand=sin(operand*M_PI/180.0);
}

答案 2 :(得分:3)

您可能想要检查此平台上的数学库是否提供函数sinpi()作为C / C ++标准数学库函数的扩展。这样可以避免与pi的近似值(即M_PI)显式相乘,并提高精度。

operand = sinpi (operand / 180.0)

答案 3 :(得分:-1)

您依赖处理器中的浮点数据类型。通过(非常可观)更多的努力,您可以实现任意精度数据类型。看看MPFR http://www.mpfr.org/sample.html它包含的函数定义(如sin)将提供更多的数字。