用Java更好地逼近e

时间:2009-09-26 18:06:54

标签: java math precision

我想将e的值近似为任何所需的精度。做这个的最好方式是什么?我能得到的最多是e = 2.7182818284590455。有关修改以下代码的任何示例都将不胜感激。

public static long fact(int x){
    long prod = 1;
    for(int i = 1; i <= x; i++)
        prod = prod * i;
    return prod;
}//fact

public static void main(String[] args) {
    double e = 1;
    for(int i = 1; i < 50; i++)
        e = e + 1/(double)(fact(i));
    System.out.print("e = " + e);
}//main

8 个答案:

答案 0 :(得分:13)

使用BigDecimal代替双倍。

BigDecimal e = BigDecimal.ONE;
BigDecimal fact = BigDecimal.ONE;

for(int i=1;i<100;i++) {
  fact = fact.multiply(new BigDecimal(i));

  e = e.add(BigDecimal.ONE.divide(fact, new MathContext(10000, RoundingMode.HALF_UP)));
}

答案 1 :(得分:6)

您的主要问题是double的精确度非常有限。如果您想要任意精度,则必须使用BigDecimal。您将遇到的下一个问题是long的有限范围,您可以使用阶乘法快速超过该范围 - 您可以使用BigInteger

答案 2 :(得分:4)

您是否看过java.util.BigDecimal中的任意精度算术?

import java.math.BigDecimal;
import java.math.MathContext;
public class BigExp {
  public static void main(String[] args) {
BigDecimal FIFTY =new BigDecimal("50");
BigDecimal e = BigDecimal.ZERO;
BigDecimal f = BigDecimal.ONE;
MathContext context = new MathContext(1000);

for (BigDecimal i=BigDecimal.ONE; i.compareTo(FIFTY)<0; i=i.add(BigDecimal.ONE)) {
  f = f.multiply(i, context);
  e = e.add(i.divide(f,context),context);

  System.out.println("e = " + e);
}
  }
}

答案 3 :(得分:3)

如果从现在开始计算从49到1而不是1到49,您将获得更好的结果。

答案 4 :(得分:1)

使用了Zed和mobrule代码的变体。工作得很好,谢谢!任何人都有更多的表现建议吗?

public static BigDecimal factorial(int x){
    BigDecimal prod = new BigDecimal("1");
    for(int i = x; i > 1; i--)
        prod = prod.multiply(new BigDecimal(i));
    return prod;
}//fact

public static void main(String[] args) {
    MathContext mc = new MathContext(1000);
    BigDecimal e = new BigDecimal("1", mc);
    for(int i = 1; i < 1000; i++)
        e = e.add(BigDecimal.ONE.divide(factorial(i), mc));
    System.out.print("e = " + e);
}//main 

答案 5 :(得分:1)

  

更多性能建议吗?

是的,你对factorial的计算效率低得多。最好将它移到你正在总结术语的循环中。你正在做事的方式将O(N)问题转化为O(N ^ 2)问题。

如果这是一个需要阶乘的真实计算,我建议使用表格查找或不完整的伽马函数作为正确的方法。

从性能的角度来看,唯一可以做得更糟的是递归因子计算。然后你会遇到额外的堆叠问题。

答案 6 :(得分:0)

要了解为什么无法使用double获得“任何所需的精确度”,请阅读此经典论文:

What Every Computer Scientist Should Know About Floating-Point Arithmetic

请注意,这是一篇非常技术性的论文。有关浮点数如何工作的更多基本细节,请参阅此维基百科文章:Double precision floating-point format

答案 7 :(得分:0)

使用BigDecimal类可以获得e的最佳近似值。

这是用于计算给定的BigDecimal值的代码

import java.math.BigDecimal;
import java.math.MathContext;


public class ApproximateE {

    public static void main(String[] args) {
        System.out.println("e~ "+e(new BigDecimal(50)));//the value to approximate

    }

    static BigDecimal e(BigDecimal n) {
        BigDecimal num = new BigDecimal(n + "");
        BigDecimal e = BigDecimal.ZERO;
        BigDecimal f = BigDecimal.ONE;
        MathContext context = new MathContext(25);//digits of precision

       /************************************************************************
        The formula for approximating e ~
        e = 1+(1/1!+1/2!+1/3!...1/i!)
       ************************************************************************/
        for (BigDecimal i = BigDecimal.ONE; i.compareTo(num) < 0; i = i.add(BigDecimal.ONE)) {

            f = f.multiply(i, context);
            e = e.add(i.divide(f, context), context);

        }
        return e;
    }

}

返回:

e~ 2.718281828459045235360289

f的值为

1
2
6
24
120
720
5040
40320
362880
3628800
39916800
479001600
6227020800
87178291200
1307674368000
20922789888000
355687428096000
6402373705728000
121645100408832000
2432902008176640000
51090942171709440000
1124000727777607680000
25852016738884976640000
620448401733239439360000
1.551121004333098598400000E+25
4.032914611266056355840000E+26
1.088886945041835216076800E+28
3.048883446117138605015040E+29
8.841761993739701954543616E+30
2.652528598121910586363085E+32
8.222838654177922817725564E+33
2.631308369336935301672180E+35
8.683317618811886495518194E+36
2.952327990396041408476186E+38
1.033314796638614492966665E+40
3.719933267899012174679994E+41
1.376375309122634504631598E+43
5.230226174666011117600072E+44
2.039788208119744335864028E+46
8.159152832478977343456112E+47
3.345252661316380710817006E+49
1.405006117752879898543143E+51
6.041526306337383563735515E+52
2.658271574788448768043627E+54
1.196222208654801945619632E+56
5.502622159812088949850307E+57
2.586232415111681806429644E+59
1.241391559253607267086229E+61
6.082818640342675608722522E+62

e的值为

1
2
2.5
2.666666666666666666666667
2.708333333333333333333334
2.716666666666666666666667
2.718055555555555555555556
2.718253968253968253968254
2.718278769841269841269841
2.718281525573192239858906
2.718281801146384479717813
2.718281826198492865159532
2.718281828286168563946342
2.718281828446759002314558
2.718281828458229747912288
2.718281828458994464285470
2.718281828459042259058794
2.718281828459045070516048
2.718281828459045226708118
2.718281828459045234928753
2.718281828459045235339785
2.718281828459045235359358
2.718281828459045235360248
2.718281828459045235360287
2.718281828459045235360289
2.718281828459045235360289
...