Reputation: 101
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
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
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
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
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
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
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
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
Reputation: 9244
You will get better results if you count from 49 to 1 instead of 1 to 49 as now.
Upvotes: 3