[英]Implement Sine in Java without Math.sin function
I'm trying to implement the sine function in Java without using Math.sin(x)
. 我正在尝试在Java中实现正弦函数而不使用
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?
你呢?
Your issue is that you are using the value that is to be evaluated for the sine function as the limit for the denominator. 您的问题是您将正弦函数要评估的值用作分母的极限。 A Taylor series is evaluated as the limit of the function approaches infinity.
当函数的极限接近无穷大时,将评估泰勒级数。 You are only evaluating it in this case to the size of the input value, which doesn't really make sense.
在这种情况下,您仅根据输入值的大小对其进行评估,这实际上没有任何意义。 You should replace your
for
loop comparison with i < x
where x is a constant representing however precise you wish to make it (the function will be fairly accurate for a value as low as 20 or so). 您应该将
i < x
for
循环比较替换for
i < x
,其中x是一个常数,表示您希望实现的精度(该函数对于值低至20左右的值都是相当准确的)。
There are two main issues in your code. 您的代码中有两个主要问题。 First issue is that you are looping
i
from 0
to a
. 第一个问题是,你是循环
i
从0
到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
. 这意味着,如果
a
为负值,则for
循环甚至不会启动,并且结果始终为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. 而如果
a
为正,则循环开始,但在(int) a
迭代后停止,这没有多大意义,因为当n趋于无穷大时,泰勒逼近效果很好。
Second major issue is you are not making enough controls on the input value a
. 第二个主要问题是您没有对输入值
a
进行足够的控制。 As I already said in Python: Calculate sine/cosine with a precision of up to 1 million digits 正如我在Python中已经说过的:计算正弦/余弦的精度高达一百万个数字
The real Taylor expansion centered in x 0 is:
以x 0为中心的实际泰勒展开式是:
where Rn is the Lagrange Remainder
Rn是拉格朗日余数
Note that Rn grows fast as soon as x moves away from the center x0 .
请注意,一旦x远离中心x0 , Rn就会快速增长。
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 .
既然你正在实施麦克劳林系列 (泰勒级数0为中心),而不是一般的泰勒级数 ,你的函数将试图计算x的值大的sin(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. 因此,在
for
循环之前,必须将域至少减小到[-pi,pi] ...如果将其减小到[0,pi]并利用正弦奇偶校验,则更好。
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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.