views:

314

answers:

7

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
+10  A: 

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)));
}
Zed
Implementing this gave at runtime: Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result. Is something missing?
Sharon
Sorry. Division needs a RoundingMode, otherwise BigDecimal throws up when seeing 1/3. Fixed it.
Zed
How do I use this? I do System.out.println(e) after the loop and get 3
flybywire
@flybywire: precision wasn't set, fixed it as well. This time I also tried to ran the code before "publishing" it :).
Zed
+2  A: 

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

danbystrom
+5  A: 

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.

Michael Borgwardt
+3  A: 

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);
}
  }
}
mobrule
this works for me, but Zed's answer (accepted) doesn't
flybywire
A: 

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

Jesper
A: 

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
Sharon
Performance advise: stop recalculating the factorial. Use Zed's solution where you do "fact = fact.multiply(new BigDecimal(i))" in the loop, instead of calculating it again.
tulskiy
As a proof, mobrule's solution runs in 542ms, your version runs in 858ms for 1000 iterations.
tulskiy
+1  A: 

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.

duffymo