Journal SQL Decimal vs Double

Posté par  (site web personnel) . Licence CC By‑SA.
Étiquettes : aucune
13
11
sept.
2017

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  (site web personnel, Mastodon) . Évalué à 10.

    Je pense que toute l'astuce est là :

    Donc, "10.222" sera tronqué à "10.22", ce qui est un arrondit violent.

    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 :

    1. Tu as des erreurs de re-normalisation qui ne se compensent pas (par exemple tu produits un ticket avec HT et TVA qui ne font pas TTC, à 1 ou 2 centimes prêt).
    2. Tu obtiens des arrondis (sur le site web par exemple) qui ne collent pas avec ceux du SI financier et qui foutent la merde dans les calculs.

    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  . Évalué à 6.

      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).

      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  (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  . É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  (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  . É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  (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  (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  (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 ?

      Sinon certains SGBD (dont PostgreSQL) ont un type pour le monétaire, mais j'ai jamais testé.

      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  (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  (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  (site web personnel) . Évalué à 3.

          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.

          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  (site web personnel) . Évalué à 6. Dernière modification le 11 septembre 2017 à 15:59.

    Donc, "10.222" sera tronqué à "10.22"

    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  (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  (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  (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).

  • # Cumul des arrondis

    Posté par  (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  (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  (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  (site web personnel) . Évalué à 2.

          C'est cette phrase qui m'a fait penser à ça :

          Tu aurais plus intérêt à arrondir à 10.22€ certains mois et à 10.23€ d’autre, pour éviter les dérives.

          "La première sécurité est la liberté"

      • [^] # Re: Cumul des arrondis

        Posté par  (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  (site web personnel) . Évalué à 3.

          c'est vraiment 1,2 (qui n'est même pas représentable exactement en flottant).

          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.

          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).

          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  (site web personnel) . Évalué à 2.

            du moment que tu restes dans les 10^{16} d'amplitude

            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 à 10^{16} centimes en tous cas ;-).

            ton résultat final varie en fonction du nombre d'intermédiaire de calcul que tu utilises.

            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  (site web personnel) . Évalué à 2.

              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.

              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  (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  (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 :

    1. Les erreurs ne se propagent pas de façon linéaire dans les calculs numériques.
    2. Tu parles bien d'éviter d'ajouter « des éléphants et des souris », mais c'est un cas assez classique en finance, où il est fréquent d'avoir plusieurs ordres de grandeur entre les montants sur les comptes et les montants des transactions.

    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  (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  . É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  (Mastodon) . Évalué à 7.

      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)

      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 mantisse\times{}2^{exposant} 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  . É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  (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  (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  (site web personnel) . Évalué à 8.

      essaie d'insérer la valeur 30000.14 dans un champ MySQL/MariaDB de type FLOAT

      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  . Évalué à 6.

        Pas besoin d'une base de données. En C:

        #include <stdio.h>
        
        int main(int argc, char *argv[]) {
                        float value = 30000.14;
                        printf("%f", value);
        }

        Ça donne:

        $ ./a.out 
        30000.140625
        

        « 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  (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  (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  (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  (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  (site web personnel) . Évalué à 3.

                  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.

                  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.

                  Avec du décimal, on additionnerait des valeurs exactes, et le résultat serait donc exact.

                  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  (site web personnel) . Évalué à 6.

                    Avec 2 millions d'addition, tu ne pourra pas en effet.

                    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

                    une erreur (petite et bornée, certes).

                    C'est triste ton opinion sur les erreurs.

                    • [^] # Re: nan, c'est pas un problème d'arrondi qui te guette

                      Posté par  . É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  (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  (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  (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  (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  (site web personnel) . Évalué à 4.

                              "Si on a du float ou double pour du monétaire, la réponse est clairement "non". "

                              Je répondais à cette phrase-ci.

                              "Et ce nonobstant toutes les explications qu'on t'a données. C'est un peu dommage."

                              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  . Évalué à 5.

                                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 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  (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.

                                  "4.5*.93 = 4.185+ε (avec ε positif), en arrondi bancaire 4.19"

                                  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  (site web personnel) . Évalué à 2.

                                    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.

                                    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  . É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  (Mastodon) . Évalué à 2.

          Hop, je relance d'un nounours…

          #include <stdio.h>
          
          int main(int argc, char *argv[]) {
                          double value = 30000.14;
                          printf("%.12f\n", value);
          }

          Et BLAM :

          ~/Essais/Sqlite $ ./a.out 
          30000.139999999999
          
  • # Exemple simple

    Posté par  . É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.

    • Calcul exact:
      • 4.5*.07 = .315, en arrondi bancaire .32
      • 4.5*.93 = 4.185, en arrondi bancaire 4.18
      • Somme: .32 + 4.18 = 4.50
    • Calcul sur les flottants
      • 4.5*.07 = .315+ε (avec ε positif), en arrondi bancaire .32
      • 4.5*.93 = 4.185+ε (avec ε positif), en arrondi bancaire 4.19
      • Somme: .32 + 4.19 = 4.51

    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  . É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  . É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  (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  . É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  (site web personnel, Mastodon) . Évalué à 1.

          Ok, merci!

        • [^] # Re: Exemple simple

          Posté par  (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  (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  . É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  (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  . É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 X\sim\mathcal{U}(\{0,.1,\cdots,9.9,10\}) On a trivialement que \mathbb{E}X=5:

              Maintenant notons A_s(\cdot) le mode d'arrondi qui envoie .5 sur le supérieur, et A_b(\cdot) 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  . Évalué à 1.

                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.

                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  (site web personnel) . Évalué à 6.

                  Non justement, pour l'arrondi "classique", mathématique, oui c'est le fait que transformer x.0 en x 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  . Évalué à -1.

                Merci pour cette explication.

  • # Le point clef est le calcul scientifique, pas la finance

    Posté par  (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:

    • un très grand nombre de transactions à équilibrer;
    • un grand nombre de “chemins de calcul” à cause du nombre de partenaires qui “font le même calcul en face.”

    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  (site web personnel) . Évalué à 2.

      "qui me laissait avec 17.97 jours de congé,"

      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.

      Ce sont les ingrédients idéaux pour voir apparaître des erreurs d'arrondi en virgule flottante.

      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  (Mastodon) . Évalué à 3.

        Il est tout à fait possible de suivre les mêmes règles avec du code utilisant des flottants.

        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  . Évalué à 4. Dernière modification le 12 septembre 2017 à 12:02.

        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.

        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  (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  (site web personnel) . Évalué à 4.

        Les calcul en DECIMAL posent exactement les mêmes problèmes.

        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! :)

  • # "double" et "long double"

    Posté par  (site web personnel) . Évalué à 0.

    En C:

    #include <stdio.h>
    
    int main(int argc, char *argv[]) {
        float  fvalue = 30000.14;
        double dvalue = 30000.14;
        long double ldvalue = 30000.14;
    
        printf("float: %f\n", fvalue);
        printf("double %lf\n", dvalue);
        printf("long double %Lf\n", ldvalue);
    
        return 0;
    }
    
    andre@home:~/tests $ ./test 
    
    float: 30000.140625
    double 30000.140000
    long double 30000.140000
    

    Je suis quasi certain que les bases de données modernes utilisent double ou long double.

    • [^] # Re: "double" et "long double"

      Posté par  (Mastodon) . Évalué à 2.

      Je suis quasi certain que les bases de données modernes utilisent double ou long double.

      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  (Mastodon) . Évalué à 2.

      Ahem…

      ~/Essais/Sqlite $ cat t.c
      #include <stdio.h>
      
      int main(int argc, char *argv[]) {
                      long double value = 30000.14;
                      printf("%.12Lf\n", value);
      }
      ~/Essais/Sqlite $ gcc -Wall t.c
      ~/Essais/Sqlite $ ./a.out 
      30000.139999999999
      

      Où est l'erreur ? Dans la mécanique interne ou dans le printf ?

      • [^] # Re: "double" et "long double"

        Posté par  (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  (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  . É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  (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.