TP: Implementing the Exponential Function (4/5)

TP: Implementing the Exponential Function (4/5)#

Attention

This exercise is marked with a ♣ and is therefore of a more advanced level; do not hesitate to skip it if it seems difficult to you in order to not waste too much time, and to come back to it later.

Part 4: Calculating the exponential with a fixed relative precision ♣#

In Part 2, you implemented an expRang function that calculates an approximation

of the exponential by truncating the sum at a certain rank decided in advance. However,

the rank required to obtain good precision depends on the real number \(x\) for which

we want to calculate \(e^x\). We now seek to calculate an approximation of

the exponential by fixing the precision and no longer the rank. To do this, we will write a

new function to approximate the exponential, in which the rank at which we

stop the sum will not be decided in advance, but will depend on the evolution of the calculation

that we are doing.

Begin by copying and pasting your puissance

and factorielle functions from part 1 and egal from

part 3 into the following four cells:

### BEGIN SOLUTION
def puissance( x, n):
    r = 1
    for i in range(n):
        r *= x
    return r
### END SOLUTION
### BEGIN SOLUTION
def factorielle(n):
    r = 1
    for i in range(1, n+1):
        r *= i
    return r
### END SOLUTION
### BEGIN SOLUTION
def egal(x, y, epsilon):
    v = abs(x-y)
    return ((v < epsilon * abs(x)) and (v < epsilon * abs(y)))
### END SOLUTION

Implement a new exponential approximation function that sums the terms

\(\frac{x^i}{i!}\) until the next term to be added does not change the value of

the sum, according to the given precision:

def expPrecision(x, epsilon):
    """ Calcul de la fonction exponentielle à precision fixée
     * Parametre x : un nombre flottant
     * Parametre epsilon un nombre flottant
     * Retourne e^x avec précision epsilon
    """
    ### BEGIN SOLUTION
    e1 = 0
    e2 = 1
    i = 1
    while(not egal(e1,e2,epsilon)):
        e1 = e2
        e2 += puissance(x,i) / factorielle(i)
        i += 1
    return e2
    ### END SOLUTION
epsilon = 0.000000001
epsilon = 1e-9

The following calculation should return \(2.718 281 828...\):

expPrecision(1, epsilon)
2.7182818282861687

There are not necessarily enough significant figures displayed to verify this.

Instead, let’s do a test:

assert( abs( expPrecision(1, epsilon) - 2.718281828459 ) < epsilon )

Our stopping test does not actually guarantee obtaining an epsilon precision: even if

the next term is smaller than epsilon, the accumulation of all the following terms

could largely exceed epsilon, as in the following examples:

assert( abs(expPrecision(3, epsilon) - 20.085536923 ) < 5*epsilon )
assert( abs( expPrecision(5, epsilon) - 148.413159102 ) < 50*epsilon )

Compare your results with the exp function in Python:

import math

math.exp(5)
148.4131591025766
math.exp(3)
20.085536923187668

Review of Part 4#

Very good, you have implemented the calculation of the exponential function with fixed precision.

Now let’s study its performance by calculating its execution time:

import time
start = time.time()
expPrecision(10, 0.00000001)
print(time.time() - start)
0.000164031982421875

In part 5, you will attempt to optimize this implementation.