在没有 Math.sin 函数的 Java 中实现正弦 [英] Implement Sine in Java without Math.sin function

查看:38
本文介绍了在没有 Math.sin 函数的 Java 中实现正弦的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在不使用 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));}}}返回温度;}

我找不到我犯的错误.你呢?

解决方案

您的代码中有两个主要问题.第一个问题是您将 i0 循环到 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆