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
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)));
}
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
.
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);
}
}
}
You will get better results if you count from 49 to 1 instead of 1 to 49 as now.
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
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.
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