我正在尝试在不使用Math.sin(x)
的情况下在Java中实现sine函数。所以我试图通过泰勒系列来实现这一点。不幸的是,这段代码给出了错误的结果。
如果您不知道泰勒系列是什么,请看一下:
以下是我创建的代码段:
public static double sin(double a) {
double temp = 1;
int denominator = -1;
if(a == Double.NEGATIVE_INFINITY || !(a < Double.POSITIVE_INFINITY)) {
return Double.NaN;
}
if(a != 0) {
for (int i = 0; i <= a; i++) {
denominator += 2;
if(i % 2 == 0) {
temp = temp + (Math.pow(a, denominator) / Factorial.factorial(denominator));
} else {
temp = temp - (Math.pow(a, denominator) / Factorial.factorial(denominator));
}
}
}
return temp;
}
我找不到我做的错误。你呢?
答案 0 :(得分:1)
您的问题是您正在使用要为正弦函数计算的值作为分母的限制。泰勒级数被评估为函数接近无穷大的极限。在这种情况下,您只是根据输入值的大小来评估它,这实际上没有意义。你应该将你的for
循环比较替换为i < x
,其中x是一个常数,表示你想做的精确(对于低至20左右的值,该函数相当准确)。
答案 1 :(得分:0)
您的代码中存在两个主要问题。第一个问题是您将i
从0
循环到a
。这意味着,如果a
为负值,则for
循环甚至不会启动,您的结果将始终为1.0
。然而,如果a
为正,则循环开始,但它在(int) a
次迭代后停止,并且它没有多大意义,因为当迭代n趋于无穷大时,泰勒拟合工作正常。 / p>
第二个主要问题是您没有对输入值a
进行足够的控制。
正如我在Python: Calculate sine/cosine with a precision of up to 1 million digits
以 x 0 为中心的真实泰勒展开是:
其中 Rn 是拉格朗日剩余
请注意,只要 x 离开中心, Rn 就会快速增长 X0
由于您正在实施 Maclaurin系列(泰勒系列 以0)为中心而不是一般的泰勒系列,你的功能 在尝试计算 sin(x)时会给出非常错误的结果 x 的重要值。
所以在for
循环之前,你必须将域名减少到至少 [ - pi,pi] ...如果你把它减少到 [0,pi]会更好并利用正弦的奇偶校验。
工作代码:
public static double sin(double a) {
if (a == Double.NEGATIVE_INFINITY || !(a < Double.POSITIVE_INFINITY)) {
return Double.NaN;
}
// If you can't use Math.PI neither,
// you'll have to create your own PI
final double PI = 3.14159265358979323846;
// Fix the domain for a...
// Sine is a periodic function with period = 2*PI
a %= 2 * PI;
// Any negative angle can be brought back
// to it's equivalent positive angle
if (a < 0) {
a = 2 * PI - a;
}
// Also sine is an odd function...
// let's take advantage of it.
int sign = 1;
if (a > PI) {
a -= PI;
sign = -1;
}
// Now a is in range [0, pi].
// Calculate sin(a)
// Set precision to fit your needs.
// Note that 171! > Double.MAX_VALUE, so
// don't set PRECISION to anything greater
// than 84 unless you are sure your
// Factorial.factorial() can handle it
final int PRECISION = 50;
double temp = 0;
for (int i = 0; i <= PRECISION; i++) {
temp += Math.pow(-1, i) * (Math.pow(a, 2 * i + 1) / Factorial.factorial(2 * i + 1));
}
return sign * temp;
}