我必须编写一个泰勒级数,直到第 16 个元素来计算 sin 并将返回值与 Math.sin 进行比较。好吧,一切都工作正常,直到最后一次我得到 0.006941 而不是 0.00000。我的错误在哪里,如果有人知道如何以更专业的方式编写它,我会非常高兴。
import java.text.NumberFormat;
import java.text.DecimalFormat;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
NumberFormat formatter = new DecimalFormat("#0.000000");
double val[] = {0, Math.PI / 3, Math.PI / 4, Math.PI / 6, Math.PI / 2, Math.PI};
for (int i = 0; i < val.length; i++) {
System.out.println("With Taylor method: " + formatter.format(Taylor(val[i])));
System.out.println("With Math.sin method: " + formatter.format(Math.sin(val[i])));
}
}
public static double Taylor ( double val){
ArrayList<Double> memory = new ArrayList<Double>();
double row = val;
for (int i = 0, s = 3; i < 16; i++, s = s + 2) {
double mth = Math.pow(val, s);
double result = mth / factorial(s);
memory.add(result);
}
for (int i = 0; i < 16; i++) {
if (i % 2 == 0) {
double d = memory.get(i);
row = row - d;
} else {
double d = memory.get(i);
row = row + d;
}
}
return row;
}
public static long factorial ( double n){
long fact = 1;
for (int i = 2; i <= n; i++) {
fact = fact * i;
}
return fact;
}
}
最佳答案
你的数学是正确的,但是一旦你开始计算 21!,你的阶乘就溢出了。我打印出了计算出的阶乘。
factorial(3) = 6
factorial(5) = 120
factorial(7) = 5040
factorial(9) = 362880
factorial(11) = 39916800
factorial(13) = 6227020800
factorial(15) = 1307674368000
factorial(17) = 355687428096000
factorial(19) = 121645100408832000
factorial(21) = -4249290049419214848 // Overflow starting here!
factorial(23) = 8128291617894825984
factorial(25) = 7034535277573963776
factorial(27) = -5483646897237262336
factorial(29) = -7055958792655077376
factorial(31) = 4999213071378415616
factorial(33) = 3400198294675128320
看来您的筹款val
直到达到数组中的最高值 Math.PI
为止,直到更高的幂都不足以对溢出产生影响。本身。由于溢出而导致的错误非常严重。
相反,使用最后一项作为起点来计算每一项。如果您有输入 memory
的最后一个值,然后乘以 val * val
乘以该值,然后按顺序除以接下来的两个数字以获得阶乘部分。
那是因为memory.get(i)
等于memory.get(i - 1) * (val * val) / ((s - 1) * s)
。这也使您的计算更加高效。它避免了计算分子(幂部分)和分母(阶乘计算)时的乘法重复。这也将避免因单独计算分母而导致的溢出。
我对这个想法的实现用它代替了第一个 for 循环:
double mth = val;
for (int i = 0, s = 3; i < 16; i++, s = s + 2) {
mth = mth * val * val;
mth = mth / ((s - 1) * s);
memory.add(mth);
}
和地点
double row = val;
for
之间循环,以确保第一项是之前的初始总和。那么你甚至不需要 factorial
方法。
这个我得到0.000000
对于 Math.PI
.
关于java - 如何将泰勒级数写为函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57484538/