Pour des calculs financiers, il est conseillé souvent d'utiliser le type DECIMAL et non un type float classique pour stocker des montant d'argent. L'argument principal est que DECIMAL n'arrondit pas, au contraire de float. Mais c'est complètement faux. Un type DECIMAL(10,2), a 10 chiffres significatifs, et 2 chiffres après la virgule. Donc, "10.222" sera tronqué à "10.22", ce qui est un arrondit violent. A l'inverse, il est vrai que "0.1" sera stocké exactement en DECIMAL, et par une approximation avec un flottant. L'approximation sera de 10-16 avec un double, ce qui laisse une bonne marge.
J'ai cherché des exemples d'"horror story" avec les calculs financiers, j'ai juste trouvé une personne qui propose d'utiliser un entier à la place de DECIMAL, mais je ne vois pas de nombre 32 bits qui ne se stocke pas dans un double. Certains parlent aussi du fait de ne pas utiliser d'opérateur = ou <> avec des flottants, mais c'est la base de la base en calcul flottant, car chaque calcul porte le 10-16 d'imprécision en lui. L'autre règle est de ne pas additionner des "éléphants et des souris", car l'étape de normalisation/shift peut introduire de grosse erreur (genre 1016 +0.01 = 1016)
Les nombres flottants disposent d'arrondi bien défini, celui de base, le "round to even" est celui qui propose le moins d'erreur quand on somme un grand nombre de nombre.
Avez vous des exemples de code qui se comportent réellement mal spécifiquement de le cas monétaire ? Qu'est-ce qu'il y a de plus compliqué que du code flottant classique ?
# Un retour d'expérience
Posté par SpaceFox (site web personnel, Mastodon) . Évalué à 10.
Je pense que toute l'astuce est là :
Si c'est un montant (monétaire) final (et pas un intermédiaire de calcul), sur une monnaie comme l'euro, la troisième décimale et toutes celles au-delà n'ont pas d'existence réelle. D'ailleurs il y a des règles officielles pour arrondir si les calculs donnent un montant à plus de 2 décimales (de mémoire : partie décimale < 0,5 --> inférieur, partie décimale >= 0,5 --> supérieur).
Du coup dans ton cas il n'y a pas réellement de « arrondit violent » : c'est le résultat du calcul qui donne bien, selon les règles de la finance, 10.22 et non 10.222.
D'une manière générale, c'est aussi un domaine où on a besoin autant que faire ce peut de valeurs exactes et pas « avec des approximations qu'on peut normaliser » sur toutes les valeurs finales. D'expérience, pour avoir bossé quelques années dans le e-commerce, utiliser des double au lieu de décimale fixe t'expose à deux types de blagues :
Utiliser correctement les outils basés sur des décimales fixes permettent d'éviter ces écueils, même si c'est généralement lourd et chiant à faire.
La connaissance libre : https://zestedesavoir.com
[^] # Re: Un retour d'expérience
Posté par claudex . Évalué à 6.
Uniquement pour la facture, pas pour le prix. Par exemple, le prix du carburant est toujours donné au millième d'euro.
« Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche
[^] # Re: Un retour d'expérience
Posté par SpaceFox (site web personnel, Mastodon) . Évalué à 2.
Oui, ce que je veux dire c'est que dès qu'il y a des mouvements réels d'argent en jeu, on est définis à 2 décimales : typiquement si tu achètes 1 litre d'essence à 1.298 €/litre, tu vas payer 1.30 €.
La connaissance libre : https://zestedesavoir.com
[^] # Re: Un retour d'expérience
Posté par dyno partouzeur du centre . Évalué à 5.
La pratique est, pour autant que je sache, de faire les calculs en interne avec 5 décimales et d'arrondir à l'affichage à deux décimales en utilisant l'arrondi bancaire.
[^] # Re: Un retour d'expérience
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
c'est un "round to nearest".
"La première sécurité est la liberté"
[^] # Re: Un retour d'expérience
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
Tout cela c'est valide pour un prix de transfert final, mais pour tous calcul intermédiaire, on ne peut se contenter de 2 chiffres après la virgule.
"La première sécurité est la liberté"
[^] # Re: Un retour d'expérience
Posté par Kerro . Évalué à 2.
Vu qu'il parle de SQL, je suppose que c'est pour stocker les montants finaux (ligne de facture, montant d'échéance, etc).
Pour les calculs c'est en mémoire que c'est géré, et là il faut bien entendu adapter au besoin.
[^] # Re: Un retour d'expérience
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
Si tu manipules une masse de truc tu finis souvent par faire des tables temporaires pour continuer des calculs. J'ai l'impression que c'est fini le fait de ne stocker que les données "raw", des étapes intermédiaires peuvent être stocker aussi.
"La première sécurité est la liberté"
# Monnaie = danger
Posté par Christie Poutrelle (site web personnel) . Évalué à 3.
De manière générale, pour le monétaire, je stocke deux INTEGER et non un DOUBLE ni un DECIMAL ni aucun autre type avec précision: le premier INTEGER contient la valeur multipliée par 10la précision - et le second contient la précision.
On calcule et on affiche la précision (2 ou 3 décimales ou autre) selon la monnaie à un moment donné, et tu peux changer globalement la configuration de la précision par monnaie à tout moment dans ton logiciel, les anciennes valeurs stockées ainsi avec la précision à côté sont à l'épreuve du temps.
Problème de cette méthodologie, tu ne peux pas laisser le SQL faire des aggrégats sur les montants si la précision diffère, c'est à la partie logicielle de le faire… Mais la cohérence dans l'espace et le temps à un coût.
Sinon certains SGBD (dont PostgreSQL) ont un type pour le monétaire, mais j'ai jamais testé.
[^] # Re: Monnaie = danger
Posté par Nicolas Boulay (site web personnel) . Évalué à 5.
quel différence avec un double correctement utilisé ? si on suit ta méthode, un double est constitué de 2 INTEGER, l'un de 54 bits et l'autre de 16. Et leur gestion est directement pris en charge par les fpu. Et si tu prends 10x, cela revient à utiliser le type DECIMAL mais sans pouvoir changer la précision.
Pourquoi s’embêter avec un truc aussi complexe ? Quel erreur tu évites ainsi ?
MONEY pour postresql, c'est DECIMAL(10,2), autant prendre DECIMAL tout court qui est plus précis.
"La première sécurité est la liberté"
[^] # Re: Monnaie = danger
Posté par Christie Poutrelle (site web personnel) . Évalué à 1. Dernière modification le 12 septembre 2017 à 10:35.
D'après ce que je lis MONEY peut être casté en float, et si j'ai bien lu la doc, les règles qui s'appliquent sur les calculs dépendent de la locale configurée soit niveau système, soit au niveau de la base, tu n'as donc pas la souplesse que tu souhaites pour gérer plusieurs monnaies différentes.
De plus, stoker seulement en 2 ça veut souvent dire que tu as déjà arrondi tes valeurs calculées pour stoker (par exemple si tu appliques des réductions en % qui peuvent te donner des fractions en résultat).
Si je devais utiliser un type natif de la base, j'utiliserais définitivement un DECIMAL et pas un type money, en tout cas avec PostgreSQL, et surement pas un DECIMAL avec MySQL à cause des cast implicites et des pertes de précision. C'est souvent pour ça que j'ai tendance à conseiller des valeurs en 2 INTEGER et 1 VARCHAR (ou ENUM ou INTEGER) soit le montant, le delta (précision et puissance), et enfin la currency.
A noter que finalement, quand je dis "conseiller", c'est à prendre avec un peu de recul, car ça dépend aussi vraiment du besoin à la base, pour un logiciel de caisse par exemple, tu ne vas gérer qu'une currency et tu stockera toujours tout déjà arrondi puisque tu stockes la somme réellement payée, par exemple dans ce contexte tout ce que je viens de dire semble relativement inutile.
[^] # Re: Monnaie = danger
Posté par -=[ silmaril ]=- (site web personnel) . Évalué à 1.
Je ne cautionne pas le "format" proposé ci dessus, même s'il y a surement des usages (bien qu'un INTEGER donc 32 ou 64b pour stocker une puissance reste quand même un poil abusé).
Par contre le double même "correctement utilisé" reste un dérivé du float, et donc une approximation du nombre d'origine via une puissance de 2 => dans tout les cas c'est inadapté à des calculs monetaires précis.
le DECIMAL() est un format de stockage et des règles de calculs adaptés au monetaire (tant que le calcul se fait dans le SGBD) similaire au format proposé dont je ne vois pas bien l'intérêt sauf pour le coté NIH peut-être …
Si tu a vraiment besoin d'une précision à 5 ou plus chiffres après la virgule il suffit de partir sur un DECIMAL(13,5) ou plus.
[^] # Re: Monnaie = danger
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
Oui, il faut faire attention aussi que le langage hôte ne fasse pas de conversion en double sans prévenir.
"La première sécurité est la liberté"
# "10.222" n'existe pas
Posté par Zenitram (site web personnel) . Évalué à 6. Dernière modification le 11 septembre 2017 à 15:59.
Le soucis dans ta logique est que tu parles de choses qui n'existent pas.
10.222€ n'existe pas.
Attention : je ne dis pas que 10.222 n'existe pas, mais qu'en monétaire on va regarder 10.22 et que seul 10.22 existe en €.
par exemple, sur un portefeuille de part, on pourra dire que tu as 1000 actions à 0.010222€ virtuels (calcul intermédiaire), quand on va te les payer ce sera bien 10.22€ qu'on te filera et pas 0.002€ de plus.
Je prend l'exemple de l'essence ci-dessus, si le litre est à 1.234€ affiché et que tu prends 1 litre (imaginons pas de minimum pour l'exemple), la caisse te facturera 1.23€ point (pas de 0.004€ en plus).
Tu dois donc décider :
- tu comptes des € : DECIMAL (ou autre méthode) avec 2 décimales (pour l'€), toujours arrondi.
- calculs intermédiaires : tu comptes avec d'autres règles à fixer (par exemple, si j'ai 0.13€ à payer en 12x, on me fait 11x 0.01€ puis 1x0.02€; autre exemple avec la TVA, si tu veux vendre à 0.99€ tu ne vas pas faire le HT à 0.99/1.2=0.825 et TVA = 0.825*0.2=0.165, car comment tu vas payer ta TVA avec 0.005€? tu fais 0.99/1.2=0.825 arrondi donc à 0.83€, et la TVA est 0.16€, différent de si tu avais fait l'arrondi de la TVA car ça aurait donné 0.17€, j'apprends ça en ce moment en découvrant les problèmes d'arrondis sur TVA avec des phases intérmédiaires, allez pour rigoler différente méthodes d'arrondis)
Bref, il y a des règles, qu'il faut connaitre, de quand et comment tu arrondis, ce n'est pas forcément une question de DECIMAL ou DOUBLE, mais un gestion bien précise des règles (quand et comment arrondir), un programme qui va utiliser un arrondi par défaut en monétaire est juste mauvais, et un programme qui va filer 10.222 à un DECIMAL(10,2) est mal barré car n'a pas appliqué la règle définie par la compta, mais est-ce que ça existe?
[^] # Re: "10.222" n'existe pas
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
Je comprends mieux. Le problème n'est pas du tout DECIMAL vs double. C'est uniquement que les transferts se font en centime et rien d'autre, et qu'il faut gérer correctement les arrondis.
"La première sécurité est la liberté"
[^] # Re: "10.222" n'existe pas
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
Je viens de penser à un truc, si tu factures avec la méthode 2 qui calcul avec arrondi chaque ligne pour avoir des sommes de TVA facile à avoir, il est possible d'avoir de la TVA à zéro avec des toutes petites sommes facturées ?!
Genre tu factures une ligne 0.20€ ttc tu as 0.2*.02 = 0.004 € de TVA qui s'arrondissent à 0 ?
"La première sécurité est la liberté"
[^] # Re: "10.222" n'existe pas
Posté par Zenitram (site web personnel) . Évalué à 5.
A ma connaissance, l'administration française n'apprécierait pas de faire des calculs intermédiaires arrondis pour faire une somme de TVA nulle, et l'arrondi se ferait sur la somme finale plutôt.
donc moins de 5c de facture totale pour avoir 0 de TVA, non rentable (coût de facturation).
[^] # Re: "10.222" n'existe pas
Posté par Nicolas Boulay (site web personnel) . Évalué à 4.
Je me doutais un peu.
"La première sécurité est la liberté"
# Cumul des arrondis
Posté par Aeris (site web personnel) . Évalué à 4.
Le problème de l’arrondi dans le bancaire n’est pas qu’il se fasse, mais qu’il se fasse toujours dans le même sens, occasionnant à long terme une perte ou un gain « important » pour le créditeur ou le débiteur.
Par exemple sur une facturation mensuel de calcul de la TVA, si tu arrondis toujours 10.222€ à 10.22€, tu vas perdre 24 centimes au bout de 10 ans de paiement. Tu aurais plus intérêt à arrondir à 10.22€ certains mois et à 10.23€ d’autre, pour éviter les dérives.
Le fait d’être en virgule flottante ajoute aussi l’erreur (indétectable) de perte de précision lors de la conversion, alors qu’en virgule fixe, tu peux détecter qu’un arrondi s’est produit et réagir en conséquence.
C’est pour ça que des langages comme COBOL sont très présents encore aujourd’hui dans le secteur bancaire, parce que sa gestion des arrondis et des débordements ainsi que le fait qu’il soit en calcul à virgule fixe et non flottante permet un suivi plus propre de ces dérives sur le long terme.
[^] # Re: Cumul des arrondis
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
Ce genre de "dérive" à long terme, se gère en automatisme par un intégrateur. Je ne sais pas si cela se fait dans le secteur bancaire, mais avec la sauvegarde de l'erreur dans un coin, on peut la refacturer la fois suivante.
"La première sécurité est la liberté"
[^] # Re: Cumul des arrondis
Posté par SpaceFox (site web personnel, Mastodon) . Évalué à 3.
Ça n'est pas dans les pratiques de re-facturer des erreurs. Il ne doit pas y avoir d'erreur de dérive.
La connaissance libre : https://zestedesavoir.com
[^] # Re: Cumul des arrondis
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
C'est cette phrase qui m'a fait penser à ça :
"La première sécurité est la liberté"
[^] # Re: Cumul des arrondis
Posté par Matthieu Moy (site web personnel) . Évalué à 4.
C'est justement la subtilité du monétaire : quand tu prends pour « 10,222 € » d'essence, le pompiste te facture exactement 10,22, et ne te dit pas « vous me payerez la fraction d'euro plus tard ». La valeur arrondie est la valeur exacte du paiement.
Un autre exemple : si tu prends un crédit à 1,2 %, c'est vraiment 1,2 (qui n'est même pas représentable exactement en flottant). Et là aussi il y a un arrondi à faire chaque année, et les calculs mathématiques du style (1 + taux)<nombre d'année> donnent un résultat incorrect car ils ne font pas les arrondis au bon endroit.
On peut certainement s'en sortir en faisant les calculs en flottant et en montrant que les arrondis flottants sont assez petits pour être absorbés par les arrondis bancaires au centime près (au moins avec des double en tous cas), mais ça ne simplifie pas vraiment la question par rapport à faire tous les calculs exacts en comptant des nombres entiers de centimes (ce qui revient à compter les euros en virgule fixe).
[^] # Re: Cumul des arrondis
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
Oui mais on s'en fout en fait, car tu peux faire tout les calculs que tu veux du moment que tu restes dans les 1016 d'amplitude. C'est une histoire d'arrondis ensuite.
C'est plus compliqué que ça. Sinon, ton résultat final varie en fonction du nombre d'intermédiaire de calcul que tu utilises.
"La première sécurité est la liberté"
[^] # Re: Cumul des arrondis
Posté par Matthieu Moy (site web personnel) . Évalué à 2.
Oui, c'est ce que j'écrivais après sur le fait qu'on pouvait s'en sortir si on sait prouver que les arrondis flottants ne changent pas l'arrondi bancaire. C'est problématique si on manipule des sommes supérieures à centimes en tous cas ;-).
Oui mais justement, les intermédiaires sont bien définis par les règles bancaires. Par exemple pour un compte à intérêt, les intérêts sont calculés tous les ans et arrondis tous les ans (la somme que tu vois arriver comme intérêts chaque année est une valeur exacte même si le calcul pour l'obtenir inclue un arrondi).
[^] # Re: Cumul des arrondis
Posté par Matthieu Moy (site web personnel) . Évalué à 2.
Mais note quand même que c'est un problème beaucoup plus compliqué qu'il en a l'air. Par exemple, faire des calculs en double puis arrondir en float peut donner un résultat incorrect comparé à un calcul fait entièrement en float à cause des problèmes de double arrondis. Je suppose que c'est pareil en mélangeant des double et des arrondis bancaires.
# Horreurs story avec les décimales ...
Posté par Christophe B. (site web personnel) . Évalué à 6.
Au siècle dernier il existait le stockage en C-ISAM float double etc …
Le seul cas tordu que j'ai vu est une facture d'un certain montant mais qui passée en compta n'avait pas le même montant, les règles d'arrondis étant les bases de l'informatique de gestion, le client a voulu comprendre.
Et après recherche on a fini par trouver une valeur 0 négative … d’où l'erreur.
Erreur de lecture/écriture, bug de la librairie … je n'ai jamais su ni réussi à le reproduire
Réponse au client : vous émettez plus de 1000 factures / mois et donc depuis 3 ans : 3 x 12 x 1000 = 36 000 factures
1 de fausses sur 36000 c'est pas un si mauvais score …
mais très vite est venu le DCB (Decimal Codé Binaire) qui à mon avis avait une librairie C plus pratique ou précise, je ne saurais le dire
# Propagation d'erreurs, éléphants et souris
Posté par SpaceFox (site web personnel, Mastodon) . Évalué à 8.
Tu fais aussi souvent référence au fait que les
double
portent une précision de 10-16 environ, ce qui devrait être suffisant.Mais c'est oublier deux choses :
Les calculs d'intérêts, typiquement, se retrouvent très bien dans ces deux points.
La connaissance libre : https://zestedesavoir.com
[^] # Re: Propagation d'erreurs, éléphants et souris
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
Il faut que je lise ton 1) plus complètement, mais il me semble écrit par un mathématicien qui parle du cas général et non du cas habituel. Dans un système habituel, les entrée ont aussi une part d'imprécision (en gros, toute entrée de capteurs) et donc, il n'y a jamais aucun algo utilisé qui "divergent" ou qui est chaotique.
En général, l'erreur est de 1/2 lsb par opération max, mais le "round to even" fait qu'en moyenne c'est beaucoup moins. De plus, souvent les fpu ont plus de précision que les 64 bits de base (80 bits pour la fpu x87, opération a*b+c en une seul passe). Il prend pour exemple la soustraction qui est le pire cas, car si a et b sont du même ordre de grandeur, il ne reste plus que l'erreur, ce qui est "physiquement" normal.
"La première sécurité est la liberté"
# nan, c'est pas un problème d'arrondi qui te guette
Posté par pralines . Évalué à 2. Dernière modification le 11 septembre 2017 à 22:23.
je crois c'est plutôt un problème de représentation/stockage des nombres en virgule flottante en SQL (peut-être à cause de la nature binaire des principaux composants informatiques)
certains nombres flottant n'ont pas de représentation interne et ne peuvent être stockés
exemple de surprise que j'ai déjà rencontré : essaie d'insérer la valeur 30000.14 dans un champ MySQL/MariaDB de type FLOAT
c'est rigolo… jusqu'au moment ou un client t'appelle pour te dire que ton calcul du TTC est faux
depuis que je me suis fait avoir, je n'utilise plus que des decimaux ou bien des entiers (pour stocker des centimes)
Envoyé depuis mon Archlinux
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par Buf (Mastodon) . Évalué à 7.
Oui, c'est ça, mais c'est pas limité au SQL, on a le même problème avec les floats/doubles dans n'importe quel langage de programmation qui les gère.
Comment est stocké un float (ou double, peu importe) en mémoire ? On a 3 éléments : une mantisse, un exposant et un signe. La mantisse et l'exposant sont des nombres entiers, le signe est juste un bit. La valeur représentée sera calculée comme puis suivant le bit de signe, ça sera positif ou négatif. Le problème de ceci, c'est que l'exposant est appliqué en base 2, ce qui empêche de représenter de façon exacte certains nombres. Par exemple, on peut représenter sans problème 0.5 (2-1), mais 0.1 n'a pas de représentation exacte en float. C'est exactement le même problème qu'en décimal pour représenter des nombres comme 1/3 ou 1/7, on doit se contenter d'une approximation.
Pour un type decimal ou monétaire, c'est exactement le même principe, on retrouve nos mantisse, exposant et signe, mais la différence est que l'exposant est appliqué en base 10. Du coup, tout nombre avec un développement décimal fini est représentable de façon exacte (tant qu'on reste dans les bornes admises par le type).
Le problème quand on manipule des données monétaires avec des floats, c'est que pratiquement chaque valeur non entière sera entachée d'une petite erreur dès le départ, et que ces erreurs vont pouvoir s'accumuler au fil des calculs, et on risque d'avoir un résultat significativement faux à la fin.
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par guppy . Évalué à 2.
Exactement, et très bien expliqué.
Pour ma part quand j'ai été confronté à ce problème (des additions de quelques milliers de terme), j'ai préféré ne pas prendre de risques : tout est stocké en centime aussi bien en sql que dans la couche métier.
Intuitivement ça me semblait préférable. Je ne me sentais pas capable d'en faire la démonstration, mais quand on travaille avec de l'argent des clients, pas le droit à l'erreur : stockage entier en centimes.
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par Nicolas Boulay (site web personnel) . Évalué à 4.
Facile si tu n'as que des additions. Si tu dois faire des divisions, cela commence à devenir sportif en entier.
"La première sécurité est la liberté"
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par Buf (Mastodon) . Évalué à 1.
Si tu stockes tout en centimes, tu utilises des nombres à virgule fixe, ce qui revient à avoir un exposant constant et décidé à l'avance. Comme tu appliques ton exposant en base 10, ça évite les problèmes de précision qu'on a avec le binaire.
En pratique, ça marche aussi, mais ça a l'inconvénient que tu limites d'entrée de jeu la précision que tu peux avoir. Si un jour tu as besoin de dixièmes de centime, tu es bloqué.
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par Michaël (site web personnel) . Évalué à 8.
Tu peux nous raconter la fin de l'histoire, pour ceux qui ont la flemme de déployer une base de données? :D
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par claudex . Évalué à 6.
Pas besoin d'une base de données. En C:
Ça donne:
« Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
float est sur 32 bits, la mantisse est sur 24 bits soit 7 chiffres significatifs. Le résulat est tout à fait logique.
"La première sécurité est la liberté"
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par Buf (Mastodon) . Évalué à 1.
Le problème n'est pas une question de chiffres significatifs, si on fait le même test avec 30.14, on obtient à l'affichage 30.139999 (alors même que la valeur de base n'a que 4 chiffres significatifs).
Le problème, c'est que l'exposant est appliqué en base 2, et du coup, le nombre en question n'est pas représentable de façon exacte, peut importe la taille de la mantisse et de l'exposant, tout comme on ne peut pas représenter de façon exacte le développement décimal de 1/3.
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
Mais cela n'a pas d'importance !
si float x = 30.14
Cela veut dire que 30.14+10-7>= x >= 30.14-10-7 (en gros)
donc "30.139999" arrondit à 6 chiffres donnent bien 30.14.
"La première sécurité est la liberté"
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par Buf (Mastodon) . Évalué à 3.
Ben si, ça a de l'importance, parce que dès le départ, ta valeur est entachée d'une erreur (petite et bornée, certes). Maintenant, si tu additionnes 2 millions de nombres avec chacun ce type d'erreur, les erreurs s'additionnent, et le résultat pourra être faux de manière imprévisible, même si on ne fait aucun arrondi intermédiaire.
Avec du décimal, on additionnerait des valeurs exactes, et le résultat serait donc exact.
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
Pas de manière imprévisible, cela peut tout à fait se calculer. si tu n'as que des additions, tu as n opérations, donc n * l'erreur au maximum erreur de 10-7 ou 10-16 (float32 ou float64). Avec des montants inférieur au milliard d'euro, tu peux faire quelques milliers d'addition en float64 avant d'avoir un soucis. Avec 2 millions d'addition, tu ne pourra pas en effet.
Oui dans le cas simple d'addition sans arrondi ni overflow.
"La première sécurité est la liberté"
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par Michaël (site web personnel) . Évalué à 6.
Cela veut dire qu'un particulier qui ferait ses comptes en virgule flottante aurait une erreur après quelques années, si jamais, alors qu'une banque au bout de quelques mois voire quelques heures – ou même quelques minutes pour certains autres opérateurs financiers.
@ Buf
C'est triste ton opinion sur les erreurs.
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par Kerro . Évalué à 2.
Le particulier n'aura ps d'erreur car il n'y a pas 2 millions d'opérations à la suite sur un même compte.
La banque n'a pas non plus le problème puisque l'erreur ne vaut que pour chaque compte (pas pour le cumule des opérations de tous les comptes). Elle aura UNE erreur si UN compte a plus de 2 millions d'opérations. Et l'erreur sera de UN centime pour chaque tranche de 2 millions d'opération sur ce compte.
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par Buf (Mastodon) . Évalué à 2.
La question à se poser, c'est pas tellement s'il y aura ou pas une erreur à la fin, c'est plutôt : est-ce que j'utilise un type de données adapté à mon problème ?
Si on a du float ou double pour du monétaire, la réponse est clairement "non". Même si dans la majorité des cas, on arrivera quand même à un résultat correct, il existe des types de données mieux adaptés (car conçus précisément pour résoudre ce problème).
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par Nicolas Boulay (site web personnel) . Évalué à 0.
Je suis désolé, car c'est faux. J'ai un cas qui a besoin d'une division, le type monétaire ne contient pas assez de décimal pour ne pas faire d'erreur grossière au final. Ce que tu dis n'est vrai que pour des transferts ou la valeur de compte courant. Bref, pour les IO mais surtout pas pour des calculs internes.
"La première sécurité est la liberté"
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par Buf (Mastodon) . Évalué à 6.
Ça change rien au problème, la question de base reste la même : est-ce que le type de données utilisé est adapté au problème ?
Si le type monétaire que tu utilises n'offre pas la précision voulue pour les calculs que tu dois faire, clairement, il n'est pas adapté, mais ça ne veut pas pour autant dire que les flottants binaires sont la solution. Il existe d'autres types décimaux, avec plus de chiffres significatifs (voire de précision arbitraire, genre
BigDecimal
en Java), c'est de ce côté-là qu'il faut chercher.Après, suivant le problème, on peut éventuellement ne pas avoir besoin d'une grande précision au final (genre pour une analyse statistique), et là, les flottants binaires seront adaptés, car nettement plus efficaces.
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par SpaceFox (site web personnel, Mastodon) . Évalué à 2.
J'ai l'impression que contrairement à ce que laissait entendre ton journal, tu ne l'as pas posté pour essayer de comprendre « pourquoi les types flottants natifs sont très peu utilisés pour faire des calculs financiers » mais plutôt pour tenter de convaincre tes lecteurs que selon toi, dans la majorité des cas, on pourrait très bien utiliser ces fameux flottants natifs. Et ce nonobstant toutes les explications qu'on t'a données. C'est un peu dommage.
La connaissance libre : https://zestedesavoir.com
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par Nicolas Boulay (site web personnel) . Évalué à 4.
Je répondais à cette phrase-ci.
J'ai quand même appris plein de truc. Mais je trouve qu'il n'y a pas d'exemple d'horror story et beaucoup de "on dit".
J'ai appris l'existence de l'arrondis bancaire, ainsi que les règles d'arrondis pour la TVA. Cela peut se faire avec n'importe quel type. Je me suis rendu compte que le type DECIMAL qui code exactement certain nombre décimal évite le problème de l'accumulation d'erreur d'un nombre flottant, mais c'est valide pour la somme d'un très grand nombre de ligne. Cela peut aussi se faire avec un simple entier qui représente des centimes. Les IO d'argent se font uniquement en centimes.
C'est déjà pas mal !
La où on ne m'a pas convaincu, c'est l'obligation d'utiliser un type DECIMAL dans mes calculs internes comme le propose certain langage.
"La première sécurité est la liberté"
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par jben . Évalué à 5.
Je t'ai pourtant mis un exemple avec un arrondi bancaire qui ne fait pas le résultat attendu sur un calcul avec des flottants. Je te conseille de le lire à nouveau.
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
Tu parles de ça : https://linuxfr.org/users/niconico/journaux/sql-decimal-vs-double#comment-1713014 ?
J'ai du le louper.
Le truc c'est le ε qui traine, qui fait une bascule. Mais même un décimal ne peut pas stocker tous les nombre de façon exact (1/3,1/7, sqrt(2), e, Pi…), pour toi, il n'existe pas de cas pathologique similaire ?
Tu as toujours le ((a-1)*n) + (a * n) = n, pour n dans [0;1] ? Et c'est vrai aussi pour plus de 2 termes ? avec du calcul décimal.
"La première sécurité est la liberté"
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par Michaël (site web personnel) . Évalué à 2.
Dans les modèles numériques courants seul les modèles d'arithmétique exacte satisfont les identités algébriques dans leur généralité. Le calcul en virgule flottante ou en virgule fixe ne le font pas. Si je comprends bien le rappel https://www.w3schools.com/sql/sql_datatypes.asp le DECIMAL de SQL est essentiellement traité comme un nombre en virgule flottante (pour toute la partie arithmétique je suppose) mais la virgule est repositionnée pour la sérialisation.
Si tu veux faire faire ton calcul garanti exact par le serveur SQL il me semble que c'est peine perdue – sauf si tu sais a priori que la précision utilisée est suffisante pour ce calcul.
Je n'imagine pas t'apprendre quoique ce soit mais je précise pour ceux qui lisent encore: à part Lisp et Scheme les langages généralistes ne calculent pas en arithmétique exacte et il faut donc utiliser une bibliothèque spécialisée, comme la gmp lib pour C et bignum en OCaml.
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par jben . Évalué à 3.
Le truc, c'est que les frontières de décisions utilisées dans les calculs financiers (qui sont de la forme
xx.xxx5
) ne sont pas codables forcément de manière exacte sur les flottants, mais le sont sur les décimaux. C'est déjà un point moins problèmatique.[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par Tonton Th (Mastodon) . Évalué à 2.
Hop, je relance d'un nounours…
Et BLAM :
# Exemple simple
Posté par jben . Évalué à 8.
Puisque tu veux un exemple simple : je te demande de diviser 4.50 € en deux part de 7% et 93% en utilisant l'arrondi bancaire au centime.
On peut trouver le même problème avec les autres modes d'arrondi. Le problème, c'est qu'on a un calcul qui nous emmène pile sur la frontière de décision, et quelque soit l'erreur qu'on fait, on peut être amené à prendre une mauvaise décision.
[^] # Re: Exemple simple
Posté par WhiteCat . Évalué à 1. Dernière modification le 12 septembre 2017 à 08:29.
Question sérieuse : pourquoi pas 0.31 et 4.19 ?
Y'a une règle/convention objective et internationale pour faire ces arrondis ?
[^] # Re: Exemple simple
Posté par pralines . Évalué à -1. Dernière modification le 12 septembre 2017 à 08:37.
arrondi inférieur si < 5
arrondi supérieur si >= 5
ça permet de diviser en 2 l'intervalle ?
0-1-2-3-4 / 5-6-7-8-9
il y a certainement une justification/formalisation mathématique précise, mais les maths et moi ça fait 3
Envoyé depuis mon Archlinux
[^] # Re: Exemple simple
Posté par gilles renault (site web personnel, Mastodon) . Évalué à 3.
Bonjour,
Dans ton calcul exact, pourquoi arrondis-tu 0.315 à 0.32 et le 4.185 à 4.18 et non 4.19 ? Quand on a un 5 en dernière décimale, on arrondit au supérieur, non ?
[^] # Re: Exemple simple
Posté par R. Danell Olivaw . Évalué à 5.
L'arrondi bancaire est aussi appelé arrondi au paire le plus proche ; si le dernier chiffre est 5, alors l'arrondi est toujours paire.
[^] # Re: Exemple simple
Posté par gilles renault (site web personnel, Mastodon) . Évalué à 1.
Ok, merci!
[^] # Re: Exemple simple
Posté par pulkomandy (site web personnel, Mastodon) . Évalué à 2.
Et c'est justement ça qui fait que 93% de n + 7% de n = n. Les méthodes "classiques" d'arrondi ne permettent pas d'avoir cette garantie.
[^] # Re: Exemple simple
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
En quoi cet arrondis n'est pas classique ? C'est le mode par défaut des fpu.
"La première sécurité est la liberté"
[^] # Re: Exemple simple
Posté par NicolasP . Évalué à 2.
Je vois bien que ça marche sur l'exemple donné plus haut, mais ce n'est pas du tout évident pour moi que l'arrondi bancaire donne cette garantie. Tu peux détailler stp ?
N'étant pas convaincu de la garantie, j'ai essayé de comprendre l'intérêt de l'arrondi bancaire par rapport à l'arrondi au plus proche (celui où quand la partie à arrondir vaut exactement 5, on arrondit au supérieur).
Intuitivement, l'arrondi au plus proche est meilleur car les plages d'arrondis font exactement la même taille pour tous les nombres. Par exemple si on arrondit à l'entier (pour simplifier, ça ne change rien si on arrondit à 2 décimales) :
- La plage [0.5- 1.5[ s'arrondit à 1
- La plage [1.5- 2.5[ s'arrondit à 2
- La plage [2.5- 3.5[ s'arrondit à 3
- La plage [3.5- 4.5[ s'arrondit à 4
- …
Alors qu'avec l'arrondi bancaire, on a un biais qui favorise les nombres pairs :
- La plage ]0.5- 1.5[ s'arrondit à 1
- La plage [1.5- 2.5] s'arrondit à 2
- La plage ]2.5- 3.5[ s'arrondit à 3
- La plage [3.5- 4.5] s'arrondit à 4
- …
Cependant vu que c'est utilisé en plein d'endroits par plein de gens plus compétents que moi, il y a sûrement une raison mais je ne l'ai pas trouvée.
Wikipedia évoque un biais corrigé par l'arrondi bancaire, mais sans expliquer lequel.
Sur le web, on peut lire que le problème de l'arrondi au plus proche c'est que quand la partie à arrondir vaut exactement 5, on arrondit toujours au supérieur. Mais je ne vois pas en quoi c'est un problème. Pour moi, c'est une nécessité si on veut une bonne répartition des arrondis.
Quelqu'un peut m'éclairer ?
[^] # Re: Exemple simple
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
Il y a moins d'erreur à la fin.
Pour faire le teste, il faudrait générer quelques millions de nombre et faire la somme, et recommencer avec des nombres arrondis et estimer l'erreur final. Le "round to even" devrait avoir une erreur plus faible.
"La première sécurité est la liberté"
[^] # Re: Exemple simple
Posté par jben . Évalué à 10.
Tu n'as pas cette garantie, tu as juste la nullité du biais.
Un biais, c'est l'espérance d'une erreur, et avec l'arrondi bancaire, l'idée c'est qu'une fois sur deux tu fais une erreur à la hausse, une fois sur deux à la baisse. Avec le mode d'arrondi au supérieur pour le milieu, dans les cas .5, tu ne fais que des erreurs à la hausse.
L'idée c'est que les .1 (qui s'arrondissent à la baisse) se compensent avec les .9 qui s'arrondissent à la hausse, les .2 avec les .8, les .3 avec les .7, les .4 avec les .6, mais pour les .5 on a un problème. Le principe de l'arrondi bancaire est qu'ils se compensent avec eux même.
Exemple, soit On a trivialement que :
Maintenant notons le mode d'arrondi qui envoie .5 sur le supérieur, et l'arrondi bancaire qui envoie .5 sur le pair le plus proche.
On obtient:
et
On a donc les biais suivants:
et
En résumé, avec l'arrondi bancaire, on a pas la garantie que les erreurs somment à zero, mais on sait qu'en moyenne elles se compensent.
Nota: L'arrondi à l'impair le plus proche présente exactement les mêmes propriétés, ce n'est qu'une histoire de convention (mais en fait, je n'ai jamais vu quelqu'un l'utiliser).
[^] # Re: Exemple simple
Posté par Kerro . Évalué à 1.
On pourrait aussi considérer que le .5 (arrondi à la hausse) s'équilibre avec le .0 (équivalent à l'arrondi à la baisse).
[^] # Re: Exemple simple
Posté par Sufflope (site web personnel) . Évalué à 6.
Non justement, pour l'arrondi "classique", mathématique, oui c'est le fait que transformer
x.0
enx
soit également un arrondi, avec une perte d'information, qui amène à arrondir.5
à l'excès, comme ça on a autant de cas d'excès (5 / 6 / 7 / 8 / 9) que de défauts (0 / 1 / 2 / 3 / 4), mais dans la perspective "tenir des comptes justes" non, puisqu'en arrondissant.1
à la baisse tu "oublies" 0,1, mais le.9
arrondi à la hausse consomme 0,1 donc ça s'équilibre ; mais le.5
arrondi à la hausse consomme 0,5 tandis que le.0
arrondi n'oublie rien, donc pas de compensation. D'où cette règle qui permet de répartir les.5
en deux camps qui vont se compenser les uns les autres.[^] # Re: Exemple simple
Posté par NicolasP . Évalué à -1.
Merci pour cette explication.
# Le point clef est le calcul scientifique, pas la finance
Posté par Michaël (site web personnel) . Évalué à 3. Dernière modification le 12 septembre 2017 à 08:58.
La situation que tu décris où on a besoin d'arithmétique exacte ou d'arithmétique de position est celle de la comptabilité, des inventaires, etc. mais parfois en finance on fait aussi du calcul scientifique [1] dans certains contextes. Une règle de décision simple pour orienter son jugement – en l'absence de connaissances plus sûres – est qu'en gros si on a besoin de l'exponentielle ou qu'on travaille sur des mesures physiques il faut utiliser les flottants autrement ce n'est probablement pas le bon choix. (Exponentielle et apparentés, donc logarithmes, fonctions trigo, puissances fractionnaires, etc.)
Le calcul en virgule flottante est particulièrement bien présenté dans le livre de Knuth (Art of Computer Programming) mais il ne va pas dans le domaine “horror story” si ma mémoire est exacte.
Ceci dit j'ai déjà vu un logiciel de gestion de personnel (soit Staff squared ou Personio) qui me laissait avec 17.97 jours de congé, ce qui m'a presque fait pleurer de rire – et très perplexe parcequ'il faut beaucoup d'imagination pour trouver une explication à une erreur si grosse.
On peut certainement construire des exemples “taillés pour” dans le cadre de la comptabilité personnelle mais c'est peut-être plus satisfaisant de changer de contexte pour voir le problème. Si on prend par exemple une banque ou une chambre de compensation (un organisme interbancaire) on se retrouve avec:
Ce sont les ingrédients idéaux pour voir apparaître des erreurs d'arrondi en virgule flottante.
[1]:
- http://linuxfr.org/users/sytoka/journaux/la-mort-de-solaris-et-de-sparc#comment-1712484
- https://softwareengineering.stackexchange.com/questions/224434/why-do-we-still-use-floats/224518#224518
[^] # Re: Le point clef est le calcul scientifique, pas la finance
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
C'est typiquement ce qui arrive avec des arrondis qui traine dans les calculs intermédiaires. Si le logiciels ne faisaient jamais d'arrondis (sauf à l'affichage), il n'y aura pas de problème.
Les calcul en DECIMAL posent exactement les mêmes problèmes. La solution du secteurs bancaires semble d'avoir redéfinit ses propres opérateurs qui se traduise avec l'arrondis bancaire, si je comprends bien les autres commentaires. Il est tout à fait possible de suivre les mêmes règles avec du code utilisant des flottants.
"La première sécurité est la liberté"
[^] # Re: Le point clef est le calcul scientifique, pas la finance
Posté par Buf (Mastodon) . Évalué à 3.
Non, parce que les valeurs initiales seront déjà entachées d'une erreur. Par exemple, on ne peut pas représenter exactement un montant de 10.15€ avec un float, donc peut importe les règles qu'on définit derrière, le résultat pourra être faux.
[^] # Re: Le point clef est le calcul scientifique, pas la finance
Posté par oinkoink_daotter . Évalué à 4. Dernière modification le 12 septembre 2017 à 12:02.
Hors sujet, mais dans ce cas le Droit français passe. Le droit non entier à congés est arrondi à l'entier supérieur. Donc même en se viandant dans les calculs, le logiciel ne devrait pas arriver à cette valeur.
[^] # Re: Le point clef est le calcul scientifique, pas la finance
Posté par Sufflope (site web personnel) . Évalué à -1.
Cette incertitude sur le calcul des congés est un frein manifeste à l'embauche. Imaginez, un patron de PME peut du jour au lendemain devoir offrir presque un jour de congé à un salarié ! Nul doute que La République en Marche s'attachera à reformer cet archaisme pour redynamiser le marché de l'emploi.
[^] # Re: Le point clef est le calcul scientifique, pas la finance
Posté par Michaël (site web personnel) . Évalué à 4.
Par DECIMAL tu veux parler d'arithmétique exacte en virgule fixe? La situation est différente parceque en arithmétique exacte l'addition est associative et commutative (comme en cours d'algèbre) mais ce n'est pas le cas pour les opérations en virgule flottante. Ainsi, si deux établissements bancaires font leur bilan en virgule flottante, ils peuvent ne pas arriver au même résultat si ils ne font pas leurs opérations dans le même ordre. (En fait ils peuvent aussi arriver à un résultat différent même s'ils font les calculs dans le même ordre, parceque certains circuits doublent la précision des nombres en virgule flottante en interne – pour traiter correctement la multiplication – en bordant les nombres en entrée par un contenu aléatoire.)
Les conventions d'arrondi que tu évoques ne s'appliquent probablement qu'au calcul d'intérêt, pas aux calculs des bilans.
Enfin c'est un peu hors-sujet mais ce n'est pas très connu alors j'en profite pour le préciser: beaucoup d'implémentations de fonctions mathématiques (comme l'exponentielle ou quelques fonctions moins connues comme Bessel ou gamma faisant partie de l'attirail de base pour le calcul scientifique) ne sont correctes que jusqu'à l'avant dernier bit du résultat et le dernier bit n'est pas garanti. C'est une petite concession en précision qui permet de gagner du temps. Pour certaines fonctions on abandonne même les 3 derniers bits. Bien-sûr il y a aussi des implémentations avec des garanties de précision plus grandes. Bref, c'est tout un petit monde en soi! :)
[^] # Re: Le point clef est le calcul scientifique, pas la finance
Posté par Buf (Mastodon) . Évalué à 3.
Le décimal est généralement en virgule flottante, mais l'exposant est simplement appliqué en base 10 au lieu de base 2.
[^] # Re: Le point clef est le calcul scientifique, pas la finance
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
Le DECIMAL en sql, est plus une virgule fixe. Même si des implémentations particulières peuvent avoir des tailles variables.
"La première sécurité est la liberté"
# "double" et "long double"
Posté par Andre Rodier (site web personnel) . Évalué à 0.
En C:
Je suis quasi certain que les bases de données modernes utilisent double ou long double.
[^] # Re: "double" et "long double"
Posté par Buf (Mastodon) . Évalué à 2.
Les bases de données possèdent plusieurs types numériques (dont float et double), mais pour stocker du monétaire, elles n'utilisent ni l'un ni l'autre, elles utilisent des flottants décimaux. Le C ne possède nativement aucun type de ce genre, mais ça existe dans d'autres langages (type
decimal
en .Net, par exemple).[^] # Re: "double" et "long double"
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
La dernière version du IEE754 ajoute un type décimal (BCD ?) qui doit être supporté dans les dernières versions de GCC.
"La première sécurité est la liberté"
[^] # Re: "double" et "long double"
Posté par Tonton Th (Mastodon) . Évalué à 2.
Ahem…
Où est l'erreur ? Dans la mécanique interne ou dans le printf ?
[^] # Re: "double" et "long double"
Posté par Renault (site web personnel) . Évalué à 3.
Comme tu demandes au printf d'afficher plus de chiffres significatifs que celui que tu commentes, il est normal d'obtenir quelque chose de différent. Le compilateur choisira une autre représentation.
# Pour info
Posté par Pol' uX (site web personnel) . Évalué à 4.
A lire absolument un jour dans sa vie de programmeur : http://www.itu.dk/~sestoft/bachelor/IEEE754_article.pdf
Adhérer à l'April, ça vous tente ?
[^] # Re: Pour info
Posté par flavien75 . Évalué à 1.
J'allais justement poster la version html de chez Oracle. C'est le même texte, avec des compléments à la fin.
Dont des remarques sur la gestion par C99
Les vrais naviguent en -42
[^] # Re: Pour info
Posté par Nicolas Boulay (site web personnel) . Évalué à 3. Dernière modification le 13 septembre 2017 à 17:11.
Oui, c'est très connu comme papier. Et une source infini de problème provient du fait que les optimiseurs de certain compilateur prennent les flottants pour des réels.
"La première sécurité est la liberté"
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.