La sortie en est :
===
[sum=314.9]
pas egal
fin
===
En effet je constate un delta entre $sum et la vraie valeur $montant_ttc :
float(-5.6843418860808E-14)
Donc mes questions sont :
- Comment détecter ce genre de saleté ?
- Comment contourner le problème le cas échéant ? (On manipule des sous donc le
bricolage me laisserait dubitatif).
Quand au pourquoi si certains savent de tête je suis preneur aussi. Car mes
souvenirs sur les erreurs de floats ne me rappelle rien sur de telles valeurs
banales. Je regarderai ce soir chez moi dans mes grimoires...
Cette action est irreversible, confirmez la suppression du commentaire ?
Signaler le commentaire
Veuillez sélectionner un problème
Nudité
Violence
Harcèlement
Fraude
Vente illégale
Discours haineux
Terrorisme
Autre
motton75
C'est classique et on ne le repetera jamais assez : les nombres decimaux ne sont pas stockables en machine tels quels - ils sont arrondis a la valeur la plus proche effectivement stockable en machine. C'est ce que l'on appelle le bruit numerique.
Par consequent, tester dans n'importe quel contexte l'egalite stricte de deux float (ou l'inegalite stricte) est une erreur de programmation : c'est trop instable. A l'exception, a la limite, de la comparaison avec zero ou avec un float entier.
La bonne demarche est d'ecrire, au lieu de : if (a == 0.01) // instable la ligne suivante : if (fabs(a-0.01) < tol) Ou tol est une tolerance, par exemple 1.e-3 si on compare des nombres dont seuls les deux premiers chiffres apres la virgule nous interessent.
C'est classique et on ne le repetera jamais assez : les nombres
decimaux ne sont pas stockables en machine tels quels - ils sont
arrondis a la valeur la plus proche effectivement stockable en machine.
C'est ce que l'on appelle le bruit numerique.
Par consequent, tester dans n'importe quel contexte l'egalite stricte
de deux float (ou l'inegalite stricte) est une erreur de programmation
: c'est trop instable. A l'exception, a la limite, de la comparaison
avec zero ou avec un float entier.
La bonne demarche est d'ecrire, au lieu de :
if (a == 0.01) // instable
la ligne suivante :
if (fabs(a-0.01) < tol)
Ou tol est une tolerance, par exemple 1.e-3 si on compare des nombres
dont seuls les deux premiers chiffres apres la virgule nous
interessent.
C'est classique et on ne le repetera jamais assez : les nombres decimaux ne sont pas stockables en machine tels quels - ils sont arrondis a la valeur la plus proche effectivement stockable en machine. C'est ce que l'on appelle le bruit numerique.
Par consequent, tester dans n'importe quel contexte l'egalite stricte de deux float (ou l'inegalite stricte) est une erreur de programmation : c'est trop instable. A l'exception, a la limite, de la comparaison avec zero ou avec un float entier.
La bonne demarche est d'ecrire, au lieu de : if (a == 0.01) // instable la ligne suivante : if (fabs(a-0.01) < tol) Ou tol est une tolerance, par exemple 1.e-3 si on compare des nombres dont seuls les deux premiers chiffres apres la virgule nous interessent.
Thomas Harding
Le 02-08-2006, FAb a écrit :
En effet je constate un delta entre $sum et la vraie valeur $montant_ttc : float(-5.6843418860808E-14)
Donc mes questions sont : - Comment détecter ce genre de saleté ? - Comment contourner le problème le cas échéant ? (On manipule des sous donc le bricolage me laisserait dubitatif).
Il faut voir du côté de GMP, qui permet de manipuler des nombres de précision arbitraire.
Sinon, il existe une fonction "round" ou "rnd", qui permet de fixer l'arrondi, (voir aussi éventuellement sprintf, mais j'éviterais cette solution pour autre chose que l'affichage).
-- Thomas Harding
Le 02-08-2006, FAb <g0up1l.at.yahoo.fr@yahoo.fr> a écrit :
En effet je constate un delta entre $sum et la vraie valeur $montant_ttc :
float(-5.6843418860808E-14)
Donc mes questions sont :
- Comment détecter ce genre de saleté ?
- Comment contourner le problème le cas échéant ? (On manipule des sous donc le
bricolage me laisserait dubitatif).
Il faut voir du côté de GMP, qui permet de manipuler des nombres de
précision arbitraire.
Sinon, il existe une fonction "round" ou "rnd", qui permet de fixer
l'arrondi, (voir aussi éventuellement sprintf, mais j'éviterais cette
solution pour autre chose que l'affichage).
En effet je constate un delta entre $sum et la vraie valeur $montant_ttc : float(-5.6843418860808E-14)
Donc mes questions sont : - Comment détecter ce genre de saleté ? - Comment contourner le problème le cas échéant ? (On manipule des sous donc le bricolage me laisserait dubitatif).
Il faut voir du côté de GMP, qui permet de manipuler des nombres de précision arbitraire.
Sinon, il existe une fonction "round" ou "rnd", qui permet de fixer l'arrondi, (voir aussi éventuellement sprintf, mais j'éviterais cette solution pour autre chose que l'affichage).
-- Thomas Harding
FAb
"motton75" writes:
C'est classique et on ne le repetera jamais assez : les nombres decimaux ne sont pas stockables en machine tels quels - ils sont arrondis a la valeur la plus proche effectivement stockable en machine. C'est ce que l'on appelle le bruit numerique.
Oui. Merci IEEE754. J'ai fini par tester en SQL et en C (float et double).
En fait ces nombres auraient du être stockés en numeric dans la base où je les lisais puis manipulés avec des types de précision arbitraire bc* en php.
Par consequent, tester dans n'importe quel contexte l'egalite stricte de deux float (ou l'inegalite stricte) est une erreur de programmation : c'est trop instable. A l'exception, a la limite, de la comparaison avec zero ou avec un float entier.
La bonne demarche est d'ecrire, au lieu de : if (a == 0.01) // instable la ligne suivante : if (fabs(a-0.01) < tol) Ou tol est une tolerance, par exemple 1.e-3 si on compare des nombres dont seuls les deux premiers chiffres apres la virgule nous interessent.
Oui on peut introduire un epsilon de tolérance... Mais dans mon cas cela me demande de revoir certaines requêtes. Je pense pencher pour convertir en type plus précis mais plus coûteux.
Merci, FAb
"motton75" <jamais.content@tele2.fr> writes:
C'est classique et on ne le repetera jamais assez : les nombres
decimaux ne sont pas stockables en machine tels quels - ils sont
arrondis a la valeur la plus proche effectivement stockable en machine.
C'est ce que l'on appelle le bruit numerique.
Oui. Merci IEEE754. J'ai fini par tester en SQL et en C (float et double).
En fait ces nombres auraient du être stockés en numeric dans la base où je les
lisais puis manipulés avec des types de précision arbitraire bc* en php.
Par consequent, tester dans n'importe quel contexte l'egalite stricte
de deux float (ou l'inegalite stricte) est une erreur de programmation
: c'est trop instable. A l'exception, a la limite, de la comparaison
avec zero ou avec un float entier.
La bonne demarche est d'ecrire, au lieu de :
if (a == 0.01) // instable
la ligne suivante :
if (fabs(a-0.01) < tol)
Ou tol est une tolerance, par exemple 1.e-3 si on compare des nombres
dont seuls les deux premiers chiffres apres la virgule nous
interessent.
Oui on peut introduire un epsilon de tolérance... Mais dans mon cas cela me
demande de revoir certaines requêtes. Je pense pencher pour convertir en type
plus précis mais plus coûteux.
C'est classique et on ne le repetera jamais assez : les nombres decimaux ne sont pas stockables en machine tels quels - ils sont arrondis a la valeur la plus proche effectivement stockable en machine. C'est ce que l'on appelle le bruit numerique.
Oui. Merci IEEE754. J'ai fini par tester en SQL et en C (float et double).
En fait ces nombres auraient du être stockés en numeric dans la base où je les lisais puis manipulés avec des types de précision arbitraire bc* en php.
Par consequent, tester dans n'importe quel contexte l'egalite stricte de deux float (ou l'inegalite stricte) est une erreur de programmation : c'est trop instable. A l'exception, a la limite, de la comparaison avec zero ou avec un float entier.
La bonne demarche est d'ecrire, au lieu de : if (a == 0.01) // instable la ligne suivante : if (fabs(a-0.01) < tol) Ou tol est une tolerance, par exemple 1.e-3 si on compare des nombres dont seuls les deux premiers chiffres apres la virgule nous interessent.
Oui on peut introduire un epsilon de tolérance... Mais dans mon cas cela me demande de revoir certaines requêtes. Je pense pencher pour convertir en type plus précis mais plus coûteux.
Merci, FAb
motton75
Oui on peut introduire un epsilon de tolérance... Mais dans mon cas cela me demande de revoir certaines requêtes. Je pense pencher pour convertir en type plus précis mais plus coûteux.
Sinon, si tu n'as pas besoin de trop de chiffres, utilise un type entier (genre BIGINT pour les grosses sommes ?) - tu stockes tous les montants en centimes ou en milliemes d'euros et tu ne rajoutes la virgule qu'au moment de l'affichage ?
Oui on peut introduire un epsilon de tolérance... Mais dans mon cas cela me
demande de revoir certaines requêtes. Je pense pencher pour convertir en type
plus précis mais plus coûteux.
Sinon, si tu n'as pas besoin de trop de chiffres, utilise un type
entier (genre BIGINT pour les grosses sommes ?) - tu stockes tous les
montants en centimes ou en milliemes d'euros et tu ne rajoutes la
virgule qu'au moment de l'affichage ?
Oui on peut introduire un epsilon de tolérance... Mais dans mon cas cela me demande de revoir certaines requêtes. Je pense pencher pour convertir en type plus précis mais plus coûteux.
Sinon, si tu n'as pas besoin de trop de chiffres, utilise un type entier (genre BIGINT pour les grosses sommes ?) - tu stockes tous les montants en centimes ou en milliemes d'euros et tu ne rajoutes la virgule qu'au moment de l'affichage ?