Precision de calcul -- débutant [C] - Programmation
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)
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
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
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 ?
Marsh Posté le 03-12-2001 à 13:56:31
Alors personne a une idee pour resoudre mon probleme ? ;-)
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 ?
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 ( ) 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]
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
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
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]
Marsh Posté le 03-12-2001 à 15:36:14
arf
avait pas caller que c t une variable
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]
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...
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 ( ) 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 ?
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...
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.
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...
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.
@+.
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.