-4
\$\begingroup\$

I was trying to solve a problem which stated:

Calculate the first 10 digit prime found in consecutive digits of e.

I was able to solve the problem but I did it by using some 10k digits of e available online. So I tried to write a program which calculates digits of e. The problem is that it simply gives the incorrect answer.

The code and the formula I used are:

$$e = \sum\limits_{n=0}^{\infty}\frac{1}{n!} = \frac{1}{1} + \frac{1}{1} + \frac{1}{1 \cdot 2} + \frac{1}{1\cdot 2 \cdot 3} + \cdots$$

import math

e=0

x=int(input()) #larger this number, more will be the digits of e

for i in range(x):
    e+=(1/(math.factorial(i)))

print(e)

When the user inputs 10, the digits returned are 2.7182815255731922 which is not correct.

Can someone explain why my code does not produce the correct result?

\$\endgroup\$
8
  • 3
    \$\begingroup\$ If you want a really good aproximation of e, you could always use the beautiful (1+9^-(4^6*7))^3^2^85 which yields 18457734525360901453873570 digits of e (if you calculate with enough precision), and is a pan-digital formula to boot. \$\endgroup\$ Mar 25, 2019 at 3:49
  • 2
    \$\begingroup\$ This is being discussed on meta, twice. \$\endgroup\$
    – Peilonrayz
    Mar 25, 2019 at 11:04
  • \$\begingroup\$ What if the user inputs a bigger number, say 100, is the correct result produced then? \$\endgroup\$ Mar 28, 2019 at 19:43
  • \$\begingroup\$ @SimonForsberg: this question seems like it would be a better fit for Stack Overflow, I think with tags [floating-point] and [numerical-methods]. The existing answer would still fit the question on SO with those tags. \$\endgroup\$ Mar 31, 2019 at 5:02
  • 1
    \$\begingroup\$ @PeterCordes I just tried to migrate the question but unfortunately I was not able to. \$\endgroup\$ Mar 31, 2019 at 13:24

1 Answer 1

11
\$\begingroup\$

First of all, don't panic. 10 is just not enough (indeed, it only gives you 5 decimal places. Try 20, and obtain

2.71828182846

which is much closer.

Now, Python uses a native floating point, which may only give you that many digits of precision (say, 30). To get more, you need to work with another representations; fractions.Fraction looks like a good candidate.

Finally, calls to math.factorial waste too much computing power. It is better to compute factorials as you go, e.g.

    denom = 1
    for i in range(1, x):
        e += 1 / denom
        denom *= i
\$\endgroup\$
3
  • \$\begingroup\$ So is that the case with every module? For example, while calculating the square root of a number, is it better to use math.sqrt(x) or should we manually define a function to calculate it? \$\endgroup\$ Mar 26, 2019 at 6:29
  • \$\begingroup\$ Also, when is it preferable to use math.factorial(x) instead of the way which you provided? \$\endgroup\$ Mar 26, 2019 at 6:30
  • 1
    \$\begingroup\$ @AaryanDewan Think of it this way, math.factorial(x) computes one factorial, but if you want many consecutive factorials it is much slower to compute them one-by-one than computing them all, consecutively. If you have a use-case where you need just one or a few specific arbitrary factorials, then math.factorial(x) already does what you need to do so then it is preferable. \$\endgroup\$ Mar 28, 2019 at 19:58

Not the answer you're looking for? Browse other questions tagged or ask your own question.