用JAVA BigDecimal计算sin函数-monomial会变大?

问题描述

我正在用JAVA中的sin使BigDecimal起作用,这是我所能做到的:

package taylorSeries;

import java.math.BigDecimal;

public class Sin {

    private static final int cutOff = 20;
    
    public static void main(String[] args) {

        System.out.println(getSin(new BigDecimal(3.14159265358979323846264),100));
        
    }

    public static BigDecimal getSin(BigDecimal x,int scale) {
        
        BigDecimal sign = new BigDecimal("-1");
        BigDecimal divisor = BigDecimal.ONE;
        BigDecimal i = BigDecimal.ONE;
        BigDecimal num = null;
        
        BigDecimal result = x;
        //System.err.println(x);
        do {
            
            x = x.abs().multiply(x.abs()).multiply(x).multiply(sign);
            
            i = i.add(BigDecimal.ONE);
            divisor = divisor.multiply(i);
            i = i.add(BigDecimal.ONE);
            divisor = divisor.multiply(i);
            
            num = x.divide(divisor,scale + cutOff,BigDecimal.ROUND_HALF_UP);
            
            result = result.add(num);
            //System.out.println("d : " + divisor);
            //System.out.println(divisor.compareto(x.abs()));
            System.out.println(num.setScale(9,BigDecimal.ROUND_HALF_UP));
        } while(num.abs().compareto(new BigDecimal("0.1").pow(scale + cutOff)) > 0);
        
        System.err.println(num);
        System.err.println(new BigDecimal("0.1").pow(scale + cutOff));
        return result.setScale(scale,BigDecimal.ROUND_HALF_UP);
        
    }

}

它使用泰勒级数: picture of the fomular

每次迭代都会添加单项式x,并且始终为负数。 问题是x的绝对值越来越大,所以迭代永远不会结束。

是否存在找到它们的方法,或者是更好的方法来实现它?

编辑:
我对三角函数很感兴趣,从头开始编写了这段代码,现在我看到了很多幼稚的错误

我的初衷是这样的:
numx^(2k+1) / (2k+1)!
divisor(2k+1)!
i2k+1
dividendx^(2k+1)

因此,我用divisor更新dividendi并通过num计算sign * dividend / divisor并通过{{1}将其添加result }

因此,新的有效代码是:

result = result.add(num)

解决方法

  1. new BigDecimal(double)构造函数通常不是您要使用的东西;首先出现BigDecimal的全部原因是double很奇怪:双精度数可以表示几乎2 ^ 64个唯一值,仅此而已-(几乎)2 ^ 64个不同的值以对数形式涂抹了,在0到1之间的所有可用数字中,约有四分之一从1到无穷大之间为四分之一,而另一半则相同,但为负数。 3.14159265358979323846264不是被祝福的数字之一。改用字符串构造函数-只需将"符号抛在其周围即可。

  2. 每个循环,sign应该切换,好吧,签名。你不是那样做的。

  3. 在第一个循环中,您用x = x.abs().multiply(x.abs()).multiply(x).multiply(sign);覆盖了x,所以现在'x'的值实际上是-x^3,而原始x的值是 gone 。在下一个循环中,您将重复此过程,因此,您肯定离预期的效果还差得远。解决方案-不要覆盖x。在整个计算中,您需要x。 最终确定getSin(final BigDecimal x),以帮助自己。

制作另一个BigDecimal值,然后将其称为累加器或不累加器。它以x的副本开始。

每个循环都将x乘以两次,然后切换符号。这样,循环中的累加器第一次为-x^3。第二次是x^5。第三次是-x^7,依此类推。

  1. 还有更多错误,但有时我只是用金汤匙为您提供功课。

我强烈建议您学习调试。调试很简单!您真正要做的就是跟着计算机一起走。您需要手工计算并仔细检查您所得到的(无论是表达式的结果还是while循环是否循环)与计算机所获得的相匹配。通过使用调试器进行检查,或者如果您不知道如何进行操作,请学习,如果不想,请添加大量System.out.println语句作为调试辅助。您的期望值与计算机的运行状况不符吗?您发现了一个错误。可能是其中之一。

然后考虑将代码的一部分拼接起来,以便您可以更轻松地检查计算机的工作。

例如,在这里num应该反映:

  • 在第一个循环之前:x
  • 第一循环:x - x^3/3!
  • 第二个循环:x - x^3/3! + x^5/5!

等。但是,如果您将这些部分分开,则调试起来会非常简单。您最好要:

  • 第一个循环:3个独立的概念:-1x^33!
  • 第二个循环:+1x^55!

调试非常简单。

通常,它还会导致更清晰的代码,因此,我建议您将这些单独的概念作为变量,进行描述,编写循环并测试它们是否在执行所需的操作(例如,使用sysouts或调试器来实际观察蓄能器值从x跳到x^3跳到x^5-这很容易检查),最后将它们放在一起。

与仅“全部编写,运行它,意识到它不起作用,耸耸肩,扬起眉毛,过头去堆满溢出并祈祷某人的水晶球正在摇晃”相比,这是一种更好的代码编写方法。美好的一天,他们看到了我的问题。

,

这些术语全为否定的事实不是 问题(尽管您必须使其交替出现才能获得正确的序列)。

术语幅度为x^(2k+1) / (2k+1)!。分子确实在增长,但分母也在增长,并且经过k = x之后,分母开始“获胜”,并且序列总是收敛。

无论如何,您应该将自己限制在较小的x范围内,否则对于非常大的乘积,计算将非常漫长。

对于正弦的计算,总是从将参数减小到范围[0,π]开始。更好的是,如果您共同开发余弦函数,则可以简化为[0,π/2]