我对我在Java中编写的近似正弦函数的方法感到有些恼火。这是它,它基于泰勒的系列。
static double PI = 3.14159265358979323846;
static double eps = 0.0000000000000000001;
static void sin(double x) {
x = x % (2 * PI);
double term = 1.0;
double res = 0.0;
for (int i = 1; term > eps; i++) {
term = term * (x / i);
if (i % 4 == 1) res += term;
if (i % 4 == 3) res -= term;
}
System.out.println(sum);
}
对于小值,我得到了非常好的正弦近似值,但对于较大的值(例如pow(10,22)),结果似乎非常错误。
结果如下:
sin(pow(10,22)) // 0.8740280612007599
Math.sin(pow(10,22)) // -0.8522008497671888
有人有想法吗?谢谢!
致以最诚挚的问候,
答案 0 :(得分:3)
请放心,Java sin
功能也将关闭。
你的问题是,sin
的泰勒展开具有较小的收敛半径,即使你在该半径范围内,收敛也很慢。
也存在浮点因素:浮点double
为您提供了大约15个有效精确度。
因此,对于sin
的大型参数,如果sin
是周期性函数,则准确度会显着下降:
sin(x + 2 * pi * n) = sin(x)
表示任何整数n
。
答案 1 :(得分:1)
对于大数字,你的答案是不正确的,因为你会因double
演示而累积很多舍入错误。当数字很大时,for
循环将在term
变得小于epsilon之前迭代很多次。在每次迭代中,累积舍入误差。结果是最终值出现了很大的误差。阅读"数值分析"的一些很好的参考。无论如何,根据定义,Tylor的系列在{0}附近接近sin
。因此,对于非常大的数字来说,这是正常的。
答案 2 :(得分:0)
这种差异实际上与泰勒级数的收敛半径无关,并且与双精度不足以保持这种大数所需的精度有关。正弦函数的泰勒级数的半径是无穷大。
10 ^ 22约为2 ^ 73。由于双精度数的尾数是52位,因此可以以双精度格式存储的连续值彼此相差2 ^ 21。由于对正弦函数的评估需要更高的分辨率,因此您无法可靠地得到答案。