[C] Precision de calcul -- débutant

Precision de calcul -- débutant [C] - Programmation

Marsh Posté le 02-12-2001 à 04:09:39    

Salut,
Voila un petit prog de de debutant en C, ce que je comprends pas c'est pourquoi les valeurs ne tombent pas juste.
Le programme sert juste a calculer des sinus et ce un certain nb de fois par periode, etc, enfin un truc basique quoi.
 
 
#include <stdio.h>
#include <math.h>
 
int main()
{
 
int n=8;
double s=1, d=0, y=1, a; // g besoin que ce soit des 'double', c impose, les autres variables sont la pour le nb de periodes, un decalage...
 
for (a=0; a<y*2*M_PI; a=a+M_PI*2/n)
{
 printf("%.20lg\t%.20lg\n", a, s*sin(a)+d);
}
 
}
 
 
Et la sortie du programme, ca donne :
 
0 0
0.785398163397448279 0.70710678118654746172
1.570796326794896558 1
2.356194490192344837 0.70710678118654757274
3.141592653589793116 1.2246063538223772582e-16
3.926990816987241395 -0.70710678118654746172
4.712388980384689674 -1
5.497787143782137953 -0.70710678118654768376
 
Et donc la question est de savoir d'ou viennent toutes ces imprecisions.
 
Merci.

Reply

Marsh Posté le 02-12-2001 à 04:09:39   

Reply

Marsh Posté le 02-12-2001 à 12:06:53    

en C , tu ne travaille qu'avec des intervalles ( 1/9 ne peux pas etre codé exactement en binaire )
tu fasi a chaque fois un double (+imprecision) + un autre double( avec lui aussi une erreur ), donc a chaque tour de boucle , ton erreur augmente , ce qui peux donner des resultats abberrants .
enfin ca c mon explication.
pour arranger essaye ca :
for ( i = 0; i< n ; i++)
{
       printf("%lg\n",sin(i*M_PI*2/n));
}
en plus , ca allège ton code ( moi j'aime pas les for qui font une ligne )
 au fait , pi est defini en tant que PI dans math.h ( donc pourkoi M_PI)


---------------

Reply

Marsh Posté le 02-12-2001 à 12:09:00    

J'ai M_PI et M_PIl (en long double) dans math.h

Reply

Marsh Posté le 02-12-2001 à 12:11:23    

mes excuses , je savais pas .
mais pour le reste , je crois que mon explicataion tient debout


---------------

Reply

Marsh Posté le 02-12-2001 à 12:13:13    

moi g M_PI et M_PI2 (pi/2), M_PI4
pas de PI ni de M_PIl


---------------
What butter and whiskey won't cure, there is no cure for.
Reply

Marsh Posté le 02-12-2001 à 15:16:22    

Merci flo850, mais apparemment ca veux pas marcher ;-) J'ai toujours les meme imprecisions, et comme j'ai besoin de 17 decimales pres la virgule..... Jusqu'a 14 ca va (bien qu'il y ait un petit 1.224606...e-16 d'ou je ne sais ou) mais au dela les resultats sont pas les bons.
 
D'ailleurs, j'ai essaye avec M_PIl au lieu de M_PI et j'ai un beau 'variable non definie' alors qu'elle est bien dans mon math.h. Peut etre est ce que ca va vient du #ifdef __USE_BSD au lieu de #ifdef __USE_GNU ? Ca veut dire quoi ca ?

Reply

Marsh Posté le 03-12-2001 à 13:56:31    

Alors personne a une idee pour resoudre mon probleme ? ;-)

Reply

Marsh Posté le 03-12-2001 à 14:10:43    

il n'y a pas vraiment moyen avec les flottants/doubles si tu veux 17 décimales après la virgule. à moins de te faire ta classe de nombre décimal et de calculer le sinus à coups de développements limités, tu n'auras jamais la précision que tu veux.
 
des libs doivent exister pour ça, chercher avec www.google.com
 
pourquoi as-tu besoin d'autant de précision au fait ?

Reply

Marsh Posté le 03-12-2001 à 14:19:32    

for (eps = 1.0; (1.0+eps)!=1.0;eps /= 2); //sisi il y a un ;  a la fin
 
cette simple ( :D ) ligne te donne la presision machine, c'est a dire la precision a attendre d'une addition.
voici les valeurs que j'avais obtenu sur je ne sais quelle machine
double 1.11022e-16
long double 9.62965e-35
 
tu as donc 16 chiffres significatif sur une addition de doubles, et 34 sur une addition de long doubles....
 
A voir sur ta machine... mais de toute evidence pour avoi tes 17 decimales les doubles sont un peu justes...
 
a voir en long double avec des sinl et cosl mais la ca depend du compilo...

 

[edtdd]--Message édité par BENB--[/edtdd]

Reply

Marsh Posté le 03-12-2001 à 15:03:10    

eps est pas definie chez moi...
 
a ne pas oublier non plus le "bug" de tous les processeurs sur les virgules flotants


---------------
What butter and whiskey won't cure, there is no cure for.
Reply

Marsh Posté le 03-12-2001 à 15:03:10   

Reply

Marsh Posté le 03-12-2001 à 15:06:42    

deathsharp a écrit a écrit :

eps est pas definie chez moi...
 
a ne pas oublier non plus le "bug" de tous les processeurs sur les virgules flotants  




ajoute double eps ou long double eps avant :D
et pour faire du long double il faut mettre 1.0L au lieu de 1.0, en particulier lors de la comparaison, et 2.0L au lieu de 2.0 lors de la division...

 

[edtdd]--Message édité par BENB--[/edtdd]

Reply

Marsh Posté le 03-12-2001 à 15:36:14    

arf
avait pas caller que c t une variable :D


---------------
What butter and whiskey won't cure, there is no cure for.
Reply

Marsh Posté le 03-12-2001 à 19:09:28    

Salut,
Bah en fait cette precision, je l'ai pas choisi, on ma l'a impose, c'est un programme que j'ai a faire pour mon 'assignment' de ce semestre.
Un extrait :
 

The generator must send a data stream
representing a sequence of sine wave samples to
stdout. Each sample should be should be sent as a
double and followed by a new_line code so that, if
sent to the screen, a single column of numbers is
produced. Samples should have 17 decimal places
of accuracy.
Four parameters are required to specify the number sequence. They are:
n: the number of samples per cycle (an int)
s: the scale factor (a double)
d: The offset (a double)
y: the number of cycles to be sent (a double)
The diagram below shows samples of a sine wave where y=2 cycles, n=16 samples per cycle,
the scale factor s=1 and the offset d=0.5. In this case there are 32 samples generated. The
amplitude of each sample is s * sin(a) + d where a is the angle for the sample. Be aware that
the sin( ) function in math.h expects the angle in radians, not degrees.

 
En totalite si vous voulez :
http://joule.ee.port.ac.uk:5050/assignment_2001.pdf
 
Voili voilo :)
 
@+.

 

[edtdd]--Message édité par snotling--[/edtdd]

Reply

Marsh Posté le 04-12-2001 à 10:50:02    

snotling a écrit a écrit :

Salut,
Bah en fait cette precision, je l'ai pas choisi, on ma l'a impose, c'est un programme que j'ai a faire pour mon 'assignment' de ce semestre.
Un extrait :
 

The generator must send a data stream
representing a sequence of sine wave samples to
stdout. Each sample should be should be sent as a
double and followed by a new_line code so that, if
sent to the screen, a single column of numbers is
produced. Samples should have 17 decimal places
of accuracy.
Four parameters are required to specify the number sequence. They are:
n: the number of samples per cycle (an int)
s: the scale factor (a double)
d: The offset (a double)
y: the number of cycles to be sent (a double)
The diagram below shows samples of a sine wave where y=2 cycles, n=16 samples per cycle,
the scale factor s=1 and the offset d=0.5. In this case there are 32 samples generated. The
amplitude of each sample is s * sin(a) + d where a is the angle for the sample. Be aware that
the sin( ) function in math.h expects the angle in radians, not degrees.

 
En totalite si vous voulez :
http://joule.ee.port.ac.uk:5050/assignment_2001.pdf
 
Voili voilo :)
 
@+.  
 
 




Certes l'interface doit etre en double, mais l'implementation, et en particulier les phases de calcul peuvent etre en long double...

Reply

Marsh Posté le 04-12-2001 à 11:41:34    

BENB a écrit a écrit :

for (eps = 1.0; (1.0+eps)!=1.0;eps /= 2); //sisi il y a un ;  a la fin  
 
cette simple ( :D ) ligne te donne la presision machine, c'est a dire la precision a attendre d'une addition.  
voici les valeurs que j'avais obtenu sur je ne sais quelle machine  
double 1.11022e-16  
long double 9.62965e-35  
 
tu as donc 16 chiffres significatif sur une addition de doubles, et 34 sur une addition de long doubles....  
 
A voir sur ta machine... mais de toute evidence pour avoi tes 17 decimales les doubles sont un peu justes...  
 
a voir en long double avec des sinl et cosl mais la ca depend du compilo...  
 
 




bah ça ça te donne la précision en admettant que ton calcul sorte pas des registres du proco, non, tu perds de la précision en passant en 32 bits ?
non ?

Reply

Marsh Posté le 04-12-2001 à 11:54:06    

minusplus a écrit a écrit :

 
bah ça ça te donne la précision en admettant que ton calcul sorte pas des registres du proco, non, tu perds de la précision en passant en 32 bits ?
non ?  




Ben ca depend de la machine, mais sur un PC les registres du proco ils font 80 bits...

Reply

Marsh Posté le 04-12-2001 à 12:29:20    

BENB a écrit a écrit :

 
Certes l'interface doit etre en double, mais l'implementation, et en particulier les phases de calcul peuvent etre en long double...  




 
Euh on fait ca comment stp ? T'aurais un petit exemple vite fait pour me montrer ?
Merci.

Reply

Marsh Posté le 04-12-2001 à 13:58:02    

Bon le prog complet pour determiner quel niveau de precision donnent des differents types de donnees du C/C++
 
int main()
{
   float epsm;
   double eps;
   long double eps2;
   for(epsm=1.0F; (1.0F+epsm)!=1.0F; epsm /= 2.0F);
   printf("%g\n",(double)(epsm));
   for(eps=1.0; (1.0+eps)!=1.0; eps /= 2.0);
   printf("%g\n",eps);
   for(eps2 = 1.0L; (1.0L+eps2) != 1.0L; eps2/=2.0L);
   printf("%g\n",(double)(eps2));
}
 
Le cas float est donne a titre d'exemple, puisque normalement les calculs sont fait en double puis tronque.
 
ton prog, je reprends la version qui minimise le nombre d'addtions successives autant de sources de troncatures...
 
 
for ( i = 0; i< n ; i++)  
{  
      long double argument = (long double)(i)*(long double)(M_PI)*2.0L/((long double)(n));
      long double result = (long double)(s)*sinl(argument)+(long double)(d)
      printf("%lg\n",(double)(resultat));  
}  
s,n,d sont des doubles (stockage) mais les calculs sont faits en long double (additions, multiplication, divisions et sinus) donc avec une precision accrue...
le resultat est affiche comme un double, la troncature est fait sur le resultat et non lors de calculs intermediaires...

Reply

Marsh Posté le 05-12-2001 à 20:07:15    

Ouais j'ai compris en fait :  
 
printf("%.17lg", sin(M_PI));
 
Ca renvoie meme pas 0, donc mes problemes sont tout de suite resolus : ce ne sont plus des problemes, c'est la limite de la becane. :)
 
Merci a tous.
@+.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed