sre*_*sad 3 floating-point ios4
我想在ios4中实现一个正弦和余弦计算器:
if([operation isEqual:@"sin"]){
operand = (operand*M_PI/180.0);
operand=sin(operand);
}
Run Code Online (Sandbox Code Playgroud)
代码为我提供了从0到90的正确答案.
当我给出180的价值时,我会得到1.22465e-16答案.我期待零.
这个小差异来自哪里?
为了清楚起见,您的程序正在给您正确的答案.也就是说,它正在完成你在代码中告诉它要做的事情.
180*M_PI 正确舍入(根据IEEE-754),并给出值:
565.4866776461627750904881395399570465087890625
Run Code Online (Sandbox Code Playgroud)
除以180也正确舍入,并给出结果:
3.141592653589793115997963468544185161590576171875
Run Code Online (Sandbox Code Playgroud)
这不完全是π的数学值.实际上,它是:
? - 0.0000000000000001224646799147...
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
还请提交一个错误请求将sinpi其作为扩展名添加到数学库中.
这是由二进制数系统无法准确表示PI引起的.
一种可能的解决方案是使用sin的对称性:
sindeg(x) = sindeg(180 - x)
Run Code Online (Sandbox Code Playgroud)
(或者):
sin(x) = sin(M_PI - x)
Run Code Online (Sandbox Code Playgroud)
将角度转换为范围(-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);
}
Run Code Online (Sandbox Code Playgroud)