我在Java中编写了一个正弦函数,它应该计算x的正弦值,如
我的功能看起来像
public static double sine(int x) {
double result = 0;
for(int n = 0; n <= 8; n++) {
double temp = 2 * n + 1;
result += Math.pow(-1, n) * Math.pow(x, temp) / fact(temp); // fact() calculates faculty
}
return result;
}
只有几个小数位匹配Math.sin(),但只有当x小于6且n的极限等于8时
有时,如果x大于6,则sine()返回甚至4.106,或者如果n的限制大于32,则返回NaN或-Infinity ...
我做错了什么?
希望你能帮助我,并提前致谢!
答案 0 :(得分:2)
如果n值很低,则对于高数,泰勒级数是正弦的差近似值。对于8度,任何高于4的角度都会产生明显不准确的结果。
因为正弦是周期性的,所以一个简单的解决方案是将角度(以弧度表示)的模数除以2 * pi。 Java中的StrictMath
类以不同的方式减小角度,但想法是相同的。在这种情况下,他们将角度减小到[-pi/4, pi/4]
之间以提高准确度。 This tool演示了随着泰勒级数的增加,准确度如何提高。
答案 1 :(得分:2)
退后一步,令人惊讶的事实是,正弦系列首先评估为有界函数。毕竟,它是一个与指数函数密切相关的幂级数。作为部分和出现的多项式对于大参数具有大的值是多项式的一般属性,因此根本不令人惊讶。
避免重新计算递归函数,例如相同参数和阶乘的幂,总是一个好主意。因此,减少到(最小量)基本算术运算看起来像这样:
public static double sine(int terms, double x) {
double result = 1;
double mxx = -x*x;
double addens = 1;
double temp = 2;
for(int n = 2; n <= terms; n++) {
addens *= mxx/temp++/temp++;
result += addens;
}
return x*result;
}
请注意,x的类型现在是双倍的。
循环的另一个破坏条件是
while(1+addens != 1)
使用灵活数量的术语,直到addens的贡献变得可以忽略不计。这为更大范围的参数提供了准确的结果,但是对于大型参数,成本将显着增加。
然后人们可以通过同时计算sin和cos来探索减半和平方策略。
答案 2 :(得分:1)
正如monolyth421已经提到的,你的问题是泰勒展开对x的小(接近零)值有效。 如果要获得良好的准确度,则应考虑将参数减少到区间[-pi / 2,pi / 2](使用trigonometric identities),然后使用泰勒展开。那么只有少数术语足以获得良好的准确性。