在没有 Math.sin 函数的 Java 中实现正弦 [英] Implement Sine in Java without Math.sin function
问题描述
我试图在不使用 Math.sin(x)
的情况下在 Java 中实现正弦函数.所以我试图通过泰勒级数来实现这一点.不幸的是,这段代码给出了错误的结果.
如果你不知道泰勒级数是什么,看看:
这是我创建的代码片段:
public static double sin(double a) {双温度 = 1;int 分母 = -1;if(a == Double.NEGATIVE_INFINITY || !(a < Double.POSITIVE_INFINITY)) {返回 Double.NaN;}如果(一个!= 0){for (int i = 0; i <= a; i++) {分母 += 2;如果(我%2 == 0){temp = temp + (Math.pow(a, denominator)/Factorial.factorial(denominator));} 别的 {temp = temp - (Math.pow(a, denominator)/Factorial.factorial(denominator));}}}返回温度;}
我找不到我犯的错误.你呢?
您的代码中有两个主要问题.第一个问题是您将 i
从 0
循环到 a
.这意味着,如果 a
是负值,for
循环甚至不会开始,您的结果将始终是 1.0
.而如果 a
为正,则循环开始,但在 (int) a
迭代后停止,这没有多大意义,因为泰勒近似在以下情况下工作正常迭代 n 趋于无穷大.
第二个主要问题是您没有对输入值 a
进行足够的控制.正如我在
其中 Rn 是 拉格朗日余数
注意 Rn 一旦 x 远离中心就会快速增长x0.
由于您正在实施麦克劳林级数(泰勒级数以 0 为中心)而不是一般的泰勒级数,你的函数尝试计算 sin(x) 时会给出非常错误的结果x 的大值.
因此,在 for
循环之前,您必须将域减少到至少 [-pi, pi]... 如果将其减少到 [0, pi] 并利用正弦的奇偶校验.
工作代码:
public static double sin(double a) {if (a == Double.NEGATIVE_INFINITY || !(a < Double.POSITIVE_INFINITY)) {返回 Double.NaN;}//如果你也不能使用 Math.PI,//你必须创建你自己的 PI最终双 PI = 3.14159265358979323846;//修复一个域...//正弦是一个周期函数,周期 = 2*PI%= 2 * PI;//任何负角都可以带回来//到它的等效正角如果 (a <0) {a = 2 * PI - a;}//正弦也是一个奇函数...//让我们利用它.整数符号 = 1;如果 (a > PI) {一-= PI;符号 = -1;}//现在 a 在 [0, pi] 范围内.//计算 sin(a)//设置精度以满足您的需要.//注意 171!>Double.MAX_VALUE,所以//不要将 PRECISION 设置为更大的值//比 84 大,除非你确定你的//Factorial.factorial() 可以处理最终整数精度 = 50;双温度 = 0;for (int i = 0; i <= PRECISION; i++) {temp += Math.pow(-1, i) * (Math.pow(a, 2 * i + 1)/Factorial.factorial(2 * i + 1));}返回符号 * 温度;}
I'm trying to implement the sine function in Java without using Math.sin(x)
. So I'm trying to realize this with the Taylor series. Unfortunately, this code gives the wrong result(s).
If you don't know what the Taylor series is, have a look:
Here's the code snippet I created:
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;
}
I can't find the mistake I did. Do you?
There are two main issues in your code. First issue is that you are looping i
from 0
to a
. This means that, if a
is a negative value, the for
loop does not even start and your result will always be 1.0
. Whereas if a
is positive, the loop starts, but it stops after (int) a
iterations, and it doesn't make much sense, since the Taylor apporximation works fine when iterations n tends to infinity.
Second major issue is you are not making enough controls on the input value a
.
As I already said in Python: Calculate sine/cosine with a precision of up to 1 million digits
The real Taylor expansion centered in x0 is:
where Rn is the Lagrange Remainder
Note that Rn grows fast as soon as x moves away from the center x0.
Since you are implementing the Maclaurin series (Taylor series centered in 0) and not the general Taylor series, your function will give really wrong results when trying to calculate sin(x) for big values of x.
So before the for
loop you must reduce the domain to at least [-pi, pi]... better if you reduce it to [0, pi] and take advantage of sine's parity.
Working code:
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;
}
这篇关于在没有 Math.sin 函数的 Java 中实现正弦的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!