TP I20, semaine 3

Exponentielle

Exemple de programme à réaliser

#include <math.h>

double exponentielle1 (double x, double epsilon) {
  int n;
  double s = 1, u = 1;
  
  for (n = 1; fabs (u) > epsilon; n++) {
    u = u * x / n;
    s = s + u;
  }
  return s;
}

double exponentielle (double x, double epsilon) {
  int n;
  double s = 1, u = 1;
  
  if (x < 0)
    return 1 / exponentielle (-x, epsilon);
    
  for (n = 1; fabs (u) > epsilon; n++) {
    u = u * x / n;
    s = s + u;
  }
  return s;
}

void main (void) {
  double x;

  while (1) {
    printf ("Entrer un réel : ");
    scanf ("%lf", &x);
    if (x < 0)
      printf ("%g %g %g\n",
              exponentielle1 (x, 1e-15),
              exponentielle  (x, 1e-15),
              exp (x) );
    else
      break;
  }
}

Exécution sur Sparc

Entrer un réel : -10
4.53999e-05 4.53999e-05 4.53999e-05
Entrer un réel : -20
5.62188e-09 2.06115e-09 2.06115e-09
Entrer un réel : -30
-3.06681e-05 9.35762e-14 9.35762e-14
Entrer un réel : -50
11072.9 1.92875e-22 1.92875e-22
Entrer un réel : -100
-2.91376e+25 3.72008e-44 3.72008e-44
Entrer un réel : 0

Commentaire

Les premiers termes de la série sont grands en valeur absolue, alors que le résultat est très petit en valeur absolue. La précision relative est fixe, de l'ordre de 10-15, donc si les sommes partielles intermédiaires atteignent 10n, le résultat n'est exact qu'à 10n-15 près.

On peut faire calculer la valeur maximale de |s| ; on trouve :

x -20 -30 -40 -50 -100
Max (|s|) 2.2e+07 3.9e+11 7.4e+15 1.4e+20 5.4e+41
Erreur finale 3.6e-09 3.1e-05 3.2 11073 2.9e+25

ce qui confirme l'analyse ci-dessus.

1 + epsilon = 1

Programme

void main (void) {
  double q, e;

  for (e = 1e-10 ; e > 1e-18 ; e = e /10 ) {
    q = 1 + e;
    q = q - 1;
    q = q / e;
    printf("%g %g\n", e, q);
  }
}

Exécution sur Sparc

1e-10 1
1e-11 1
1e-12 1.00009
1e-13 0.999201
1e-14 0.999201
1e-15 1.11022
1e-16 0
1e-17 0

Commentaire

Dès que epsilon est inférieur à 10-15, 1 + epsilon = 1.

Remarque : on a décomposé les calculs: q=1+e; q=q-1; q=q/e au lieu d'écrire simplement : q=((1+e)-1)/e pour éviter qu'un bon compilateur ne simplifie le numérateur.

Suite instable

Programme

void main (void) {
  int i;
  double x = 1;

  for (i = 1 ; i < 20 ; i++ ) {
    x = 5 * ( 4 * (x - 1 / 5.0) - 3);
    printf("%g\n", x);
  }
}

Exécution sur Sparc

1
1
1
1
1
1
1
1
1.00002
1.00048
1.00957
1.19147
4.82945
77.589
1532.78
30636.6
612713
1.22542e+07
2.45085e+08

Commentaire

On calcule en fait la suite récurrente définie par : autrement dit : xn+1 - 1 = 20 (xn - 1). Cette suite est fortement instable, et 1/5 ne peut être représenté exactement en numération binaire ; on a donc une erreur initiale de l'ordre de 10-15, multipliée par 20 à chaque itération.

Suite de Fibonacci

Programme

#include <math.h>

long fibonacci (int n) {
  int i;
  long a = 0, b = 1, c;
  
  for (i = 1 ; i < n; i++) {
    c = a + b;
    a = b;
    b = c;
  }
  return b;
}

double u (int n) {
  double
    rac5 = sqrt (5),
    phi  = (1 + rac5) / 2,
    x = 1;
  int k;
  
  for (k = 0; k < n; k++)
    x = x * phi;
  return x / rac5;
}

long arrondi (double x) {
  return (long) (x + 0.5);
}

void main (void) {
  double x;
  int n;
  
  for (n = 1; n <= 50; n++) {
    x = u (n);
    printf ("%2d : %12ld %12g %12ld %12ld\n",
            n, fibonacci (n), x, (long) x, arrondi (x) );
  }
}

Exécution sur Sparc

1 : 1 0.723607 0 1
2 : 1 1.17082 1 1
3 : 2 1.89443 1 2
4 : 3 3.06525 3 3
5 : 5 4.95967 4 5
6 : 8 8.02492 8 8
7 : 13 12.9846 12 13
8 : 21 21.0095 21 21
9 : 34 33.9941 33 34
10 : 55 55.0036 55 55
11 : 89 88.9978 88 89
12 : 144 144.001 144 144
13 : 233 232.999 232 233
14 : 377 377.001 377 377
15 : 610 610 609 610
16 : 987 987 987 987
17 : 1597 1597 1596 1597
18 : 2584 2584 2584 2584
19 : 4181 4181 4180 4181
20 : 6765 6765 6765 6765
... ... ... ... ...
30 : 832040 832040 832040 832040
31 : 1346269 1.34627e+06 1346268 1346269
32 : 2178309 2.17831e+06 2178309 2178309
33 : 3524578 3.52458e+06 3524577 3524578
34 : 5702887 5.70289e+06 5702887 5702887
35 : 9227465 9.22746e+06 9227464 9227465
36 : 14930352 1.49304e+07 14930352 14930352
37 : 24157817 2.41578e+07 24157817 24157817
38 : 39088169 3.90882e+07 39088169 39088169
39 : 63245986 6.3246e+07 63245986 63245986
40 : 102334155 1.02334e+08 102334155 102334155
41 : 165580141 1.6558e+08 165580141 165580141
42 : 267914296 2.67914e+08 267914296 267914296
43 : 433494437 4.33494e+08 433494437 433494437
44 : 701408733 7.01409e+08 701408733 701408733
45 : 1134903170 1.1349e+09 1134903170 1134903170
46 : 1836311903 1.83631e+09 1836311903 1836311903
47 : -1323752223 2.97122e+09 2147483647 2147483647
48 : 512559680 4.80753e+09 2147483647 2147483647
49 : -811192543 7.77874e+09 2147483647 2147483647
50 : -298632863 1.25863e+10 2147483647 2147483647

Commentaire