Reputation: 2901
I am writing a function to approximate the mathematical value of e.
We are told to use the factorial
function and the inverse
function above. It is also suggested to use map
.
I have this so far, but it gives me an error saying: ValueError: factorial() only accepts integral values
.
def inverse(n):
"""Returns the inverse of n"""
return 1 / n
def e(n):
"""Approximates the mathematical value e"""
lst = range(1, n+1)
lst2 = map(inverse, lst)
lst3 = map(math.factorial, lst2)
return sum(lst3)
Could someone point me in the right direction please?
Upvotes: 0
Views: 3434
Reputation: 1669
I has some fun with that question, using generators and decorators. First, you can create a generator to yield
consecutively more precise values of e
:
def compute_e():
currentFactorial = 1
currentSum = 1
for i in itertools.count(start=1):
currentFactorial *= i
currentSum += 1/currentFactorial
yield currentSum
And, after that, I create a decorator to find a fixed point (with a maximum number of iterations, and wanted precision) :
def getFixedPoint(gen, maxiter=10000, precision=0):
def mywrap(*args, **kwargs):
instanceGen = gen(*args, **kwargs)
prevValue = next(instanceGen)
for n, value in enumerate(instanceGen):
if (value - prevValue < precision) or (n > maxiter):
return value
else:
prevValue = value
return mywrap
which gives me stuff like this:
In [83]: getFixedPoint(compute_e)()
Out[83]: 2.7182818284590455
In [84]: getFixedPoint(compute_e, maxiter=5)()
Out[84]: 2.71827876984127
In [85]: getFixedPoint(compute_e, precision = 0.001)()
Out[85]: 2.7182539682539684
Of cours, now I can change my way of computing each successive value of e
, for example by using from decimal import Decimal
:
@getFixedPoint
def compute_e():
currentFactorial = Decimal(1)
currentSum = Decimal(1)
for i in itertools.count(start=1):
currentFactorial *= i
currentSum += 1/currentFactorial
yield currentSum
compute_e()
Out[95]: Decimal('2.718281828459045235360287474')
Upvotes: 0
Reputation: 6710
As everyone else pointed out:
1/2 == 0
.You need something like this:
def inverse(n):
"""Returns the inverse of n"""
# Using 1 as a float makes the division return a float value.
return 1. / n
def e(n):
"""Approximates the mathematical value e"""
lst = range(1, n+1) # k=1...n
lst2 = map(math.factorial, lst)
return 1 + sum(map(inverse, lst2))
You can compare your approximation against math.exp
:
>>> abs(math.exp(1) - e(20)) < 1e-10
True
Upvotes: 0
Reputation: 2901
This is now working for me. I needed to change the range from (1, n+1)
to (0, n+1)
and reverse the order of doing the factorial
first and then doing the inverse
.
def inverse(n):
"""Returns the inverse of n"""
return 1 / n
def e(n):
"""Approximates the mathematical value e"""
lst = map(math.factorial, range(0, n+1))
return sum(map(inverse, lst))
Upvotes: 1
Reputation: 1396
e can be defined by Σ(1/k!), where k = 0 .. ∞.
So, for each k,
It looks like you're doing the inversion before the factorial instead of after, and starting from 1 instead of 0.
Note that this is not the most efficient way of doing this computation, as the factorial is unnecessarily being computed from scratch for each k.
Upvotes: 1