root/misc/dl.c

Revision 11, 16.1 kB (checked in by haypo, 1 year ago)

Add dl.c

  • Property svn:eol-style set to native
Line 
1 /*
2   Renvoie la valeur approchée de fonctions mathématiques :
3   Exponentiel, cosinus, sinus hyperbolique, arctan, ...
4   grâce aux développement limités de ces fonctions.
5   ---
6   Si quelqu'un trouve comment calculer Tan, TanH, ArcCosH, qu'il
7   m'envoie un email.
8   ---
9   ---
10   Auteur: Victor Stinner aka haypo -- http://www.haypocalc.com
11   Date de creation: 28 avril 2001
12   Code source distribue sous licence GNU GPL
13 */
14
15 #include <stdio.h>   // printf
16 #include <math.h>    // fabsl
17 #include <float.h>   // DBL_DIG
18 #include <stdbool.h> // type boolean: bool
19
20 //=============== DEFINE =======================================================
21
22
23 /* typedef (long double) NombreReel;
24 #define Abs(a) fabsl(a) */
25
26 typedef long NombreEntier;  // Utilise long pour les nombres entiers
27 typedef double NombreReel;  // Utiise double pour les nombres rééls
28
29 // Valeur absolue d'un nombre réel
30 NombreReel Abs (NombreReel x)
31 {
32   return fabs(x);
33 }
34
35 #define Precision 12  // MAX = 20 en long double
36 #define PuissancePrecision 1e-12 // =1e-(Precision), MAX = -20 en long double
37 #define AfficheExemple(A,B) printf (A); printf ("(%.3g) = %.12g\n",x,B(x));
38
39 NombreReel Racine (NombreReel x)
40 {
41   // Racine(0) = 0 (évite de tourne en rond avec cette algorithme)
42   if (x==0) return 0;
43
44   // Racine(0) = 1 (évite de tourne en rond avec cette algorithme)
45   if (x==1) return 1;
46
47   // Racine(nombre négatif) = i * Racine(abs(nombre négatif)) : ERREUR !
48   // (ne supporte pas les nombres complexes)
49   if (x<0) {
50     printf ("ERREUR Racine : Résultat complexe ... ");
51     return -1;
52   }
53
54   // Avec la méthode de Newton (x(n+1) = x(n) - f(x)/f'(x)) et la fonction
55   // f(x)= x^2 - b (b étant le nombre dont on cherche la racine)
56   // -> f'(x) = 2x, on trouve la suite qui tend vers la racine de b :
57   // x(n+1) = x(n) - (x(n)^2 - b)/2x(n) = x(n) - x(n)/2 +b/2x(n)
58   //        = (x(n) + b/x(n))/2
59   NombreReel Racine,SauveX;
60
61   // Le nombre dont on cherche la racine
62   Racine = x;
63
64   // Cherche une valeur proche de la racine (x=racine du nombre)
65   // Pour 2<x, la racine est inférieure à x/2
66   if (2<x) x /= 2;
67
68   SauveX = x+1;
69   while (PuissancePrecision<Abs(SauveX-x)) {
70     SauveX = x;
71     x = (x + Racine/x)/2;
72   }
73
74   return x;
75 }
76
77 //=============== COSINUS-SINUS-TANGENTE =======================================
78 NombreReel Cos (NombreReel x)
79 {
80   NombreReel
81     ValCosinus,
82     Xpuissance,Factoriel,i,Quotient;
83
84   // COS(x) = 1 -x^3/3! +x^5/5! -x^7/7 +...
85
86   ValCosinus = 1;     // Premier terme de la suite
87   x = x*x;            // Eleve x au carre (pour acc‚l‚rer le calcul de
88                        // Xpuisscance)
89   Xpuissance = x;     // = x^2, x^4, x^6, x^8, ...
90   Factoriel = 2;      // = 2!,  4!,  6!,  8!,  ...
91   i = 2;              // Iteration (utilis‚e pour le calcul du Factoriel)
92   Quotient = Xpuissance/Factoriel;    // Calcule le quotient
93
94   do {
95     ValCosinus = ValCosinus -Quotient;                 // Soustrait un terme
96     Xpuissance = Xpuissance*x;      // Passe
97  la puissance suivante (* x^2)
98     i = i +1; Factoriel = Factoriel*i; // Passe au factoriel suivant
99     i = i +1; Factoriel = Factoriel*i; // (= *i*(i+1) ) et i=i+2
100
101     ValCosinus = ValCosinus +Xpuissance/Factoriel;        // Ajoute un terme
102     Xpuissance = Xpuissance*x;      // Passe
103  la puissance suivante (* x^2)
104     i = i +1; Factoriel = Factoriel*i; // Passe au factoriel suivant
105     i = i +1; Factoriel = Factoriel*i; // (= *i*(i+1) ) et i=i+2
106     Quotient = Xpuissance/Factoriel;    // Calcule le quotient
107   } while (PuissancePrecision<Abs(Quotient));
108
109   return ValCosinus;
110 }
111
112 NombreReel Sin (NombreReel x)
113 {
114   NombreReel
115     ValSin,
116     Xpuissance,Factoriel,i,Quotient;
117
118   // SIN(x) = x -x^3/3! +x^5/5! -x^7/7 +...
119
120   ValSin = x;         // Premier terme de la suite
121   Xpuissance = x*x*x; // = x, x^3, x^5, x^7, ...
122   x = x*x;            // Eleve x au carre (pour acc‚l‚rer le calcul de
123                        // Xpuisscance)
124   Factoriel = 6;      // = 1!,3!,  5!,  7!,  ...
125   i = 3;              // Iteration (utilis‚e pour le calcul du Factoriel)
126   Quotient = Xpuissance/Factoriel;    // Calcule le quotient
127
128   do {
129     ValSin = ValSin -Quotient;  // Soustrait un terme
130     Xpuissance = Xpuissance*x;      // Passe
131  la puissance suivante (* x^2)
132     i = i +1; Factoriel = Factoriel*i; // Passe au factoriel suivant
133     i = i +1; Factoriel = Factoriel*i; // (= *i*(i+1) ) et i=i+2
134
135     ValSin = ValSin +Xpuissance/Factoriel;        // Ajoute un terme
136     Xpuissance = Xpuissance*x;      // Passe
137  la puissance suivante (* x^2)
138     i = i +1; Factoriel = Factoriel*i; // Passe au factoriel suivant
139     i = i +1; Factoriel = Factoriel*i; // (= *i*(i+1) ) et i=i+2
140     Quotient = Xpuissance/Factoriel;    // Calcule le quotient
141   } while (PuissancePrecision<Abs(Quotient));
142   return ValSin;
143 }
144
145 NombreReel Tan (NombreReel x)
146 {
147   NombreReel
148     ValSin,ValCos,
149     Xpuissance,Factoriel,i,Quotient;
150
151   // TAN(x) = SIN(x)/COS(x)
152   //           x -x^3/3 +x^5/5 -x^7/7 +x^9/9 - ...
153   //        = -------------------------------------
154   //           1 -x^2/2 +x^4/4 -x^6/6 +x^8/8 - ...
155
156   ValCos = 1;         // Premier terme de la suite de cosinus
157   ValSin = x;         // Premier terme de la suite de sinus
158   Xpuissance = x*x;   // = x^2, x^3, x^4, x^5, ...
159   Factoriel = 2;      // = 2!, 3!, 4!, 5!,  ...
160   i = 2;              // Iteration : 2,3,4,5,6,...
161   Quotient = Xpuissance/Factoriel;    // Calcule le quotient
162
163   do {
164     ValCos = ValCos -Quotient;          // Soustrait un terme
165     Xpuissance = Xpuissance*x;      // Passe
166  la puissance suivante (* x^2)
167     i = i +1; Factoriel = Factoriel*i; // Passe au factoriel suivant
168
169     ValSin = ValSin -(Xpuissance/Factoriel);           // Soustrait un terme
170     Xpuissance = Xpuissance*x;      // Passe
171  la puissance suivante (* x^2)
172     i = i +1; Factoriel = Factoriel*i; // Passe au factoriel suivant
173
174     ValCos = ValCos +(Xpuissance/Factoriel);              // Ajoute un terme
175     Xpuissance = Xpuissance*x;      // Passe
176  la puissance suivante (* x^2)
177     i = i +1; Factoriel = Factoriel*i; // Passe au factoriel suivant
178
179     ValSin = ValSin +(Xpuissance/Factoriel);              // Ajoute un terme
180     Xpuissance = Xpuissance*x;      // Passe
181  la puissance suivante (* x^2)
182     i = i +1; Factoriel = Factoriel*i; // Passe au factoriel suivant
183
184     Quotient = Xpuissance/Factoriel;    // Calcule le quotient
185   } while (PuissancePrecision<Abs(Quotient));
186
187   return ValSin/ValCos;
188 }
189
190
191 //=============== EXPONENTIEL ==================================================
192 NombreReel Exp (NombreReel x)
193 {
194   NombreReel
195     ValExp,
196     Xpuissance,q,f,i;
197
198   // EXP(x) = x^0/0! +x^1/1! +x^2/2! +x^3/3! +... +x^i/i!
199
200   ValExp = 1; // Premier terme de la suite
201   Xpuissance = x;
202   f = 1;
203   i = 1;
204
205   q = Xpuissance/f;
206   do {
207     ValExp = ValExp +q;
208     Xpuissance = Xpuissance*x;
209     i = i +1;
210     f = f*i;
211     q = Xpuissance/f;
212   } while (PuissancePrecision<Abs(q));
213
214   return ValExp;
215 }
216
217 NombreReel Ln (NombreReel x)
218 {
219   NombreReel
220     ValLn,
221     Xpuissance,q,f,i;
222   bool
223     ResultatOppose;
224
225   // LN(1+x) =    (0<x<=1)
226   // x
227   // -x^2/2
228   // +x^3/3
229   // -x^4/4
230   // +x^5/5
231   // -...
232
233   // ln(1)=0 !
234   if (x==1) return 0;
235
236   // x<0 ?
237   if (x<=0) {
238     printf ("La fonction LN n'est pas definie sur ]-inf,0] !\n");
239     return 0;
240   }
241
242   // 1<x ? Calcule -ln(1/x) dans ce cas là
243   if (1<x) {
244     x = 1/x;
245     ResultatOppose = true;
246   } else ResultatOppose = false;
247
248   // On calcule Ln(1+x), donc on fait -1
249   x--;
250
251   // Initialise les variables
252   ValLn = 0;
253   Xpuissance = x;  // x,x^2,x^3,x^4,...
254   i = 1;
255
256   q = Xpuissance/i;
257   do {
258     ValLn += q;
259     Xpuissance *= x;
260     i++;
261
262     ValLn -= Xpuissance/i;
263     Xpuissance *= x;
264     i++;
265
266     q = Xpuissance/i;
267   } while (PuissancePrecision<Abs(q));
268
269   if (ResultatOppose)
270     return (-ValLn);
271   else
272     return ValLn;
273 //  return ResultatOppose? -ValLn:ValLn;
274 }
275
276 //=============== ARCSIN, ARCCOS, ARCTAN =======================================
277 NombreReel ArcSin (NombreReel x)
278 {
279   NombreReel
280     ValArcSin,k,xp,q;
281   NombreEntier si1,si2;
282
283   // ArcSin (x) =
284   //  x
285   // +x^3/3* (1/2)
286   // +x^5/5* (1*3)/(2*4)
287   // +x^7/7* (1*3*5)/(2*4*6)
288   // +...
289
290   ValArcSin = x;
291   k = 1;
292   xp = x;
293   si1 = 1;
294   si2 = 2;
295   x = x*x;      // Eleve x au carr‚
296   q = 1;
297
298   do {
299     k = k*si1/si2;
300     si1 += 2;
301     si2 += 2;
302     xp = xp*x;
303     q = xp*k/si1;
304     ValArcSin = ValArcSin +q;
305   } while (PuissancePrecision<Abs(q));
306
307   return ValArcSin;
308 }
309
310 NombreReel ArcCos (NombreReel x)
311 {
312   // ArcCos(x) = pi/2 -ArcSin(x)
313
314   return M_PI/2 -ArcSin(x);
315 }
316
317 NombreReel ArcTan (NombreReel x)
318 {
319   NombreReel
320     ValArcTan,
321     Xpuissance,Denominateur,Quotient;
322
323   // ARCTAN(x) = x -x^3/3 +x^5/5 -x^7/7 +...
324   // --> POUR 0 <= x < 1
325
326   if (1<=x) {
327     printf (" <-OVERFLOW-> ");
328     return 0;
329   }
330
331   // Initialise les variables
332   ValArcTan    = 0;  // Premier terme de la suite
333   Xpuissance   = x;  // = x, x^3, x^5, x^7, ...
334   Denominateur = 1;  // = 1, 3, 5, 7, ...
335   Quotient = Xpuissance/Denominateur;   // Quotient des deux
336   x = x*x;   // Eleve x au carre (pour optimiser le calcul de Xpuissance
337
338   // S'arrête quand on a atteind une précision suffisante
339   do {
340     ValArcTan = ValArcTan +Quotient;// Ajoute un terme
341     Xpuissance = Xpuissance*x;      // Passe
342  la puissance suivante (* x^2)
343     Denominateur = Denominateur+2;  // Passe au d‚nominateur suivant (+ 2)
344
345     ValArcTan = ValArcTan -Xpuissance/Denominateur; // Soustrait un terme
346     Xpuissance = Xpuissance*x;      // Passe
347  la puissance suivante (* x^2)
348     Denominateur = Denominateur+2;  // Passe au d‚nominateur suivant (+ 2)
349     Quotient = Xpuissance/Denominateur; // Calcule le quotient
350   } while (PuissancePrecision<Abs(Quotient));
351
352   // Renvoi la valeur de l'arctan(x)
353   return ValArcTan;
354 }
355 //=============== COSH, SINH, TANH =============================================
356 NombreReel CosH (NombreReel x)
357 {
358   NombreReel
359     ValCosH,
360     Xpuissance,Factoriel,i,Quotient;
361
362   // COSH(x) = 1/2*(exp(x)+exp(-x))
363   //         = 1 +x^2/2! +x^4/4! +...
364
365   ValCosH = 1;        // Premier terme de la suite
366   x = x*x;            // Eleve x au carre (pour acc‚l‚rer le calcul de
367                        // Xpuisscance)
368   Xpuissance = x;     // = x^2, x^4, x^6, x^8, ...
369   Factoriel = 2;      // = 2!,  4!,  6!,  8!,  ...
370   i = 3;              // Iteration = 3, 5, 7, 9, ...
371   Quotient = Xpuissance/Factoriel;    // Calcule le quotient
372
373   do {
374     ValCosH = ValCosH +Quotient;    // Ajoute un terme
375     Xpuissance = Xpuissance*x;      // Passe
376  la puissance suivante (* x^2)
377     Factoriel = Factoriel*i*(i+1);
378     i = i +2;                       // Passe au factoriel suivant
379
380     Quotient = Xpuissance/Factoriel;    // Calcule le quotient
381   } while (PuissancePrecision<Abs(Quotient));
382
383   return ValCosH;
384 }
385
386 NombreReel SinH (NombreReel x)
387 {
388   NombreReel
389     ValSinH,
390     Xpuissance,Factoriel,i,Quotient;
391
392   // SINH(x) = 1/2*(exp(x)-exp(-x))
393   //         = x +x^3/3! +x^5/5! +...
394
395   ValSinH = x;        // Premier terme de la suite
396   Xpuissance = x*x*x; // = x^3, x^5, x^7, x^9, ...
397   x = x*x;            // Eleve x au carre (pour acc‚l‚rer le calcul de
398                        // Xpuisscance)
399   Factoriel = 6;      // = 3!,  5!,  7!,  9!,  ...
400   i = 4;              // Iteration = 3, 5, 7, 9, ...
401   Quotient = Xpuissance/Factoriel;    // Calcule le quotient
402
403   do {
404     ValSinH = ValSinH +Quotient;    // Ajoute un terme
405     Xpuissance = Xpuissance*x;      // Passe
406  la puissance suivante (* x^2)
407     Factoriel = Factoriel*i*(i+1);
408     i = i +2;                       // Passe au factoriel suivant
409
410     Quotient = Xpuissance/Factoriel;    // Calcule le quotient
411   } while (PuissancePrecision<Abs(Quotient));
412
413   return ValSinH;
414 }
415
416 NombreReel TanH (NombreReel x)
417 {
418   // TanH(x) = SinH(x)/CosH(x)
419   // Désolé, j'ai pas trouvé mieux pour l'instant
420   return SinH(x)/CosH(x);
421 }
422
423
424 //=============== ARCCOSH, ARCSINH, ARCTANH ====================================
425 NombreReel ArcCosH (NombreReel x)
426 {
427   // ArcCosH(x) = Ln(x+Racine(x^2-1)), tout simplement !
428   x += Racine(x*x-1);
429   return Ln(x);
430 }
431
432 NombreReel ArcSinH (NombreReel x)
433 {
434   NombreReel
435     ValArcSinH,Rapport,XPuissance,Total;
436   NombreEntier
437     Impair,Pair;
438
439   // ArcSinH (x) =
440   //  x
441   // -x^3/3* (1/2)
442   // +x^5/5* (1*3)/(2*4)
443   // -x^7/7* (1*3*5)/(2*4*6)
444   // +...
445
446   XPuissance = x*x*x;
447   ValArcSinH = x-XPuissance/6;
448   Rapport = (NombreReel)(1*3)/(2*4); // = (1*3)/(2*4), (1*3*5)/(2*4*6), (1*3*5*7)/(2*4*6*8),...
449   Impair = 5;      // = 5, 7, 9, 11, ...
450   Pair = 6;        // = 6, 8, 10, 12, ...
451   x= x*x;          // Eleve x au carr‚
452   XPuissance = XPuissance*x;       // Xpuissance = x^5, x^7, x^9, ...
453   Total = XPuissance/Impair*Rapport;
454   do {
455     ValArcSinH = ValArcSinH +Total;
456     Rapport = Rapport*Impair/Pair;
457     Impair += 2;
458     Pair += 2;
459     XPuissance = XPuissance*x;
460
461     ValArcSinH = ValArcSinH -XPuissance/Impair*Rapport;
462     Rapport = Rapport*Impair/Pair;
463     Impair += 2;
464     Pair += 2;
465     XPuissance = XPuissance*x;
466
467     Total = XPuissance/Impair*Rapport;
468   } while (PuissancePrecision<Abs(Total));
469
470   return ValArcSinH;
471 }
472
473 NombreReel ArcTanH (NombreReel x)
474 {
475   NombreReel
476     ValArcTanH,XPuissance,Quotient;
477   NombreEntier d;
478
479   // ARCTANH(x) = 1/2* ln( (1+x)/(1-x) )
480   //            = x +x^3/3 +x^5/5 +x^7/7 +...
481   if ((x<=-1) || (1<=x)) {
482     printf ("x doit appartenir à ]-1,1[ !!!\n");
483     return 0;
484   }
485
486   ValArcTanH = x;
487   XPuissance = x*x*x;
488   x= x*x;          // Eleve x au carr‚
489   d = 3;
490   Quotient = XPuissance/d;
491   do {
492     ValArcTanH = ValArcTanH +Quotient;
493     XPuissance = XPuissance*x;
494     d += 2;
495     Quotient = XPuissance/d;
496   } while (PuissancePrecision<Abs(Quotient));
497
498   return ValArcTanH;
499 }
500
501 //=============== ARCCOSH, ARCSINH, ARCTANH ====================================
502 //=============== ARCCOSH, ARCSINH, ARCTANH ====================================
503 int main(int argc, char* argv[])
504 {
505   NombreReel x,e;
506   printf (">>> Precision = %u (=nombre de chiffres significatifs) <<<\n\n",Precision);
507
508   x = 1; AfficheExemple ("Exp",Exp);
509   x = 2; AfficheExemple ("Exp",Exp);
510   x = 2; AfficheExemple ("Ln",Ln);
511   x = 3; AfficheExemple ("Ln",Ln);
512   printf ("\n");
513   getchar ();
514
515   // --------------------------------------------
516   x = 0.123; AfficheExemple ("Cos",Cos);
517   x = 0.456; AfficheExemple ("Cos",Cos);
518   x = 0.789; AfficheExemple ("Cos",Cos);
519   printf ("\n");
520   x = 0.123; AfficheExemple ("Sin",Sin);
521   x = 0.456; AfficheExemple ("Sin",Sin);
522   x = 0.789; AfficheExemple ("Sin",Sin);
523   printf ("\n");
524   x = 0.123; AfficheExemple ("Tan",Tan);
525   x = 0.456; AfficheExemple ("Tan",Tan);
526   x = 0.789; AfficheExemple ("Tan",Tan);
527   printf ("\n");
528   getchar ();
529
530   // --------------------------------------------
531   x = 0.123; AfficheExemple ("ArcCos",ArcCos);
532   x = 0.456; AfficheExemple ("ArcCos",ArcCos);
533   x = 0.789; AfficheExemple ("ArcCos",ArcCos);
534   printf ("\n");
535   x = 0.123; AfficheExemple ("ArcSin",ArcSin);
536   x = 0.456; AfficheExemple ("ArcSin",ArcSin);
537   x = 0.789; AfficheExemple ("ArcSin",ArcSin);
538   printf ("\n");
539   x = 0.123; AfficheExemple ("ArcTan",ArcTan);
540   x = 0.456; AfficheExemple ("ArcTan",ArcTan);
541   x = 0.789; AfficheExemple ("ArcTan",ArcTan);
542   printf ("\n");
543   getchar ();
544
545   // --------------------------------------------
546   x = 0.123; AfficheExemple ("CosH",CosH);
547   x = 0.456; AfficheExemple ("CosH",CosH);
548   x = 0.789; AfficheExemple ("CosH",CosH);
549   printf ("\n");
550   x = 0.123; AfficheExemple ("SinH",SinH);
551   x = 0.456; AfficheExemple ("SinH",SinH);
552   x = 0.789; AfficheExemple ("SinH",SinH);
553   printf ("\n");
554   x = 0.123; AfficheExemple ("TanH",TanH);
555   x = 0.456; AfficheExemple ("TanH",TanH);
556   x = 0.789; AfficheExemple ("TanH",TanH);
557   printf ("\n");
558   getchar ();
559
560   // --------------------------------------------
561   x = 0.123; AfficheExemple ("ArcCosH",ArcCosH);
562   x = 0.456; AfficheExemple ("ArcCosH",ArcCosH);
563   x = 0.789; AfficheExemple ("ArcCosH",ArcCosH);
564   printf ("\n");
565   x = 0.123; AfficheExemple ("ArcSinH",ArcSinH);
566   x = 0.456; AfficheExemple ("ArcSinH",ArcSinH);
567   x = 0.789; AfficheExemple ("ArcSinH",ArcSinH);
568   printf ("\n");
569   x = 0.123; AfficheExemple ("ArcTanH",ArcTanH);
570   x = 0.456; AfficheExemple ("ArcTanH",ArcTanH);
571   x = 0.789; AfficheExemple ("ArcTanH",ArcTanH);
572   printf ("\n");
573   getchar();
574
575   // Racine carré
576   x = 2; AfficheExemple ("Racine",Racine);
577   x = 3; AfficheExemple ("Racine",Racine);
578   x = 4; AfficheExemple ("Racine",Racine);
579   printf ("\n");
580
581   // Calcul de PI
582   printf ("PI = %.12g (= ArcTan(1/2)+ArcTan(1/3))\n",(4*(ArcTan ((NombreReel)1/2)+ArcTan((NombreReel)1/3))));
583   getchar ();
584   return 0;
585 }
586
Note: See TracBrowser for help on using the browser.