Sharon
Sharon

Reputation: 101

Better approximation of e with Java

I would like to approximate the value of e to any desired precision. What is the best way to do this? The most I've been able to get is e = 2.7182818284590455. Any examples on a modification of the following code would be appreciated.

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

Upvotes: 6

Views: 9207

Answers (8)

Vmir
Vmir

Reputation: 79

The best approximation of e can be got by using BigDecimal class.

Here is the code for computing the given BigDecimal Value

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;
    }

}

Returns :

e~ 2.718281828459045235360289

The value of f is

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

The value of e is

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
...

Upvotes: 0

duffymo
duffymo

Reputation: 308763

More performance advice anyone?

Yes, your calculation of factorial is as inefficient as it gets. It would be better to move that inside the loop where you're summing the terms. The way you're doing things turns a O(N) problem into a O(N^2) problem.

And if this was a real calculation that needed factorials, I'd recommend a table lookup or the incomplete gamma function as the correct way to do it.

The only thing you could have done worse from a performance point of view is a recursive factorial calculation. Then you'd have the additional problem of a huge stack.

Upvotes: 1

Sharon
Sharon

Reputation: 101

Went with a variation of Zed and mobrule's code. Works great, thanks! More performance advice anyone?

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 

Upvotes: 1

Zed
Zed

Reputation: 57658

Use a BigDecimal instead of a double.

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)));
}

Upvotes: 13

Jesper
Jesper

Reputation: 206816

To understand why you cannot get "any desired precision" with double, read this classic paper:

What Every Computer Scientist Should Know About Floating-Point Arithmetic

Note that that's a quite technical paper. For more basic details of how floating-point numbers work, see this Wikipedia article: Double precision floating-point format

Upvotes: 0

mob
mob

Reputation: 118605

Have you taken a look at the arbitrary-precision arithmetic in 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);
}
  }
}

Upvotes: 4

Michael Borgwardt
Michael Borgwardt

Reputation: 346309

Your main problem is that double has very limited precision. If you want arbitrary precision, you'll have to use BigDecimal. The next problem you're going to run into is the limited range of long which you're going to exceed very quickly with the factorial - there you can use BigInteger.

Upvotes: 6

Dan Bystr&#246;m
Dan Bystr&#246;m

Reputation: 9244

You will get better results if you count from 49 to 1 instead of 1 to 49 as now.

Upvotes: 3

Related Questions