用于计算嵌套基本常量的Java程序

时间:2016-05-07 04:21:01

标签: java recursion stack-overflow mathematical-optimization

[Image from MathWorld, WolframAlpha

使用下面的代码我可以估算它:1.7579327566180045

public class Sum {
static int count = 0;
static double a = 0;
public static void main(String[] args) {
    int x = 0;
    System.out.println(sum(x));
}

public static double sum(int x){
    count++;
    x++;
    if (count == 11000){
        return a;
    }
    return a = Math.sqrt(x+sum(x));
}

然而,我无法通过此处的递归更准确地得到答案。从11,000增加递归调用的数量可以得到StackOverflowError。我也查了解如何在这里使用java的BigDecimal,但是我无法在这里实现它,老实说不确定这是否会有所帮助。

  

问题: - 如何让这个程序计算常数到更多的小数位并且更准确?我不确定这是否可以迭代计算或不计算。我无法确定iterative定义。

此外,我也研究了Java 8 Streams,但那些对我来说没有多大意义(因为我是编程和Java的新手)并且不确定这是否适用于此。

感谢您的帮助!

3 个答案:

答案 0 :(得分:3)

如果您唯一的问题是堆栈:不要使用递归,只需使用普通迭代。

如果我们调用迭代限制n,则激进常量为:

sqrt(1 + sqrt(2 + sqrt(3 + sqrt(4 + ... sqrt(... + sqrt(n))...))))

与:

相同
sqrt(...(sqrt(sqrt(sqrt(n) + (n-1)) + (n-2)) + (n-3)) + ... )

所以,让我们使用它:

public class Test {
  public Test(int iterations) {
    int n = iterations;
    double sum = 0;
    while (n > 0) {
      sum = Math.sqrt(sum + n--);
    }
    System.out.printf("Precision using %d iterations: %1.50f\n", iterations, sum);
  }

  public static void main(String[] args) {
    new Test(1);
    new Test(10);
    new Test(100);
    new Test(1000);
    new Test(10000);
    new Test(100000);
    new Test(1000000);
    new Test(10000000);
    new Test(100000000);
  }
}

当然,既然你需要精确度,这对它没什么帮助:现在你不再遇到堆栈问题,你就会遇到IEEE浮点数这个事实不是用于数学上精确的计算:

Precision using 1 iterations: 1.00000000000000000000000000000000000000000000000000
Precision using 10 iterations: 1.75793261139383100000000000000000000000000000000000
Precision using 100 iterations: 1.75793275661800450000000000000000000000000000000000
Precision using 1000 iterations: 1.75793275661800450000000000000000000000000000000000
Precision using 10000 iterations: 1.75793275661800450000000000000000000000000000000000
Precision using 100000 iterations: 1.75793275661800450000000000000000000000000000000000
Precision using 1000000 iterations: 1.75793275661800450000000000000000000000000000000000
Precision using 10000000 iterations: 1.75793275661800450000000000000000000000000000000000
Precision using 100000000 iterations: 1.75793275661800450000000000000000000000000000000000

根据official documentation

  

此数据类型绝不能用于精确值,例如货币。为此,您需要使用java.math.BigDecimal类。 Numbers和Strings涵盖了Java平台提供的BigDecimal和其他有用的类。

答案 1 :(得分:2)

使用answer by Mike 'Pomax' Kamermans中的代码,使用answer by barwnikk中提供的comment by Tibrogargan中的算法将代码转换为使用compile org.springframework.security:spring-security-ldap,您可以获得以下代码:

BigDecimal

在1000次迭代中,您似乎获得了1596位精度。测试:

private static void nestedRadicalConstant(int iterations, int scale) {
    BigDecimal sum = BigDecimal.ZERO;
    for (int n = iterations; n > 0; n--)
        sum = sqrt(sum.add(BigDecimal.valueOf(n)), scale);
    System.out.printf("Precision using %9d iterations: %s\n", iterations, sum);
}
private static final BigDecimal TWO = BigDecimal.valueOf(2);
private static BigDecimal sqrt(BigDecimal a, int scale) {
    BigDecimal x0 = BigDecimal.ZERO;
    BigDecimal x1 = new BigDecimal(Math.sqrt(a.doubleValue()));
    while (! x0.equals(x1)) {
        x0 = x1;
        x1 = a.divide(x0, scale, BigDecimal.ROUND_HALF_UP);
        x1 = x1.add(x0);
        x1 = x1.divide(TWO, scale, BigDecimal.ROUND_HALF_UP);
    }
    return x1;
}

生成此输出:

nestedRadicalConstant(1, 2);
nestedRadicalConstant(10, 20);
nestedRadicalConstant(100, 120);
nestedRadicalConstant(1000, 1620);
nestedRadicalConstant(10000, 2000);

超过4600位数似乎无法打印,所以我就在那里停了下来。开始慢慢来。 ; - )

答案 2 :(得分:0)

如果正确实施算法,您将获得更高的准确性。

编辑:你的实现并不正确,但我不是这样做的...(总和的第5行可以返回x的sqrt而不是a,也可能只是0)

其次,迭代执行此操作的关键是倒退。

k = 11000
ans = 0
while k > 0:
    ans+=k
    ans**=0.5
    k-=1
return(ans)