Pas de problème (pb), que du PowerBuilder (PB) ^^

Le forum (ô combien francophone) des utilisateurs de Powerbuilder.

Recherche rapide

Annonce

Certaines rubriques, dont des cours, sont uniquement visibles par les membres du forum ^^.
Dans la rubrique Liens & Références, vous avez accès à un sommaire de téléchargement, profitez-en !
Il existe maintenant un nouveau TOPIC "Votre CV en Ligne" accessible uniquement par demande.

#1 09-12-2011 13:15:42

abdelta  
Bienfaitrice du site
Award: bf
Lieu: La Daguenière
Date d'inscription: 21-03-2007
Messages: 393
Pépites: 14,703
Banque: 9,223,372,036,854,776,000

9.450000000000001 = 9.450000000000003 ???

Bonjour,

Nous venons de migrer notre application en PB12.0 Build 5530.
Dans une datawindow, on cherche à faire un filtre sur une colonne de type number. Si je l'affiche sur 17 caractères, il m'affiche 9.450000000000003 alors que j'ai 9.45 en base de données (colonne de type float en Oracle 10.2). Si je l'affiche sur 18 caractères, le 3 disparaît.
Je filtre avec ma_colonne = 9.450000000000001, la ligne apparaît bien !?!
Je filtre avec ma_colonne = 9.45, la ligne n'apparaît plus.
Un getitemnumber sur ma_colonne ramène bien 9.45

J'ai essayé avec une autre valeur :
filtre avec ma_colonne = 26.10, la ligne apparaît
filtre avec ma_colonne = 26.100000000000001, la ligne est toujours là !?!

Sous PB10.2 build 8011 avec Oracle 8.4 tous les filtres ci-dessus fonctionnent.

Quelqu'un a déjà vu çà ?
A l'aide !


La sirène noire
http://www.nerdtests.com/images/badge/bf1f6c78865210a9.gif

Hors ligne

 

#2 11-12-2011 18:39:01

seki  
0x73656B69
Award: bf
Lieu: Laquenexy & Luxembourg
Date d'inscription: 20-11-2008
Messages: 1118
Pépites: 4,296,080,204
Banque: 9,223,372,036,854,776,000
Site web

Re: 9.450000000000001 = 9.450000000000003 ???

abdelta a écrit:

Quelqu'un a déjà vu çà ?
A l'aide !

La version courte :

La virgule flottante (= float ou double) pour représenter des nombres décimaux, quand on ne fait pas de calcul scientifique sur des nombres très petits ou énormément grands, ça n'apporte que des ennuis.

Il est de loin préférable d'utiliser des nombre à virgule fixe (= decimal). D'autant plus si c'est pour représenter des données financières car il sur toutes les fonctions d'agrégation sur les floats se posent des problèmes d'arrondis qui font qu'on perd des centimes en route ou des euros entiers (voir plus selon la quantité de donnés)

La version longue :
La raison technique c'est que les ordis, qui ne comptent qu'avec des puissances de 2, lorsqu'ils manipulent des nombre réels dans le coprocesseur mathématique les représentent sous la forme mantisse (un petit nombre) + exposant (qui décale la virgule).
En gros, pour représenter 42 on aura 4.2E1 (4.2 x 10), pour 4200 on aura 4.2E3 (4.2 x 1000), etc.

Le problème vient qu'en interne pour représenter la mantisse, certains nombrent ne "tombent pas juste". Ils sont approchés. Avec une bonne précision tout de même, mais ça reste une approximation.
Quand j'étais encore à l'école des programmeurs, j'ai eu à faire un projet de calculette (en assembleur) et j'ai pu expérimenter certains de ces nombres : par exemple 1.2 était stocké 1.19999999... et 3.8 donnait 3.7999999... Lors de l'affichage, les valeurs sont arrondies et on ne se rend pas toujours compte de la "supercherie". Le nombre de décimales dépend du type de réel (float = simple précision, double = double précision) mais on peut déjà voir le problème.

Du coup dans le code on peut tomber sur des trucs qui paraissent aberrants du genre 9.450000000000001 = 9.450000000000003 si on arrondit les valeurs n décimales (ce qui est fait par le code à un moment ou un autre).

Pour palier à ces problèmes, on a heureusement inventé des libs de calcul en virgule fixe avec lesquelles on choisit le nombre de décimales de précision voulue et qui permettent de toujours calculer juste sans arrondi. Dans du pbscript, c'est utilisé quand on utilise decimal à la place de float : on peut par exemple choisir d'utiliser 2 chiffres après la virgule en écrivant dec{2} et on n'a plus de problème.


Maintenant toute mon explication ne répond pas forcément à ta question puisque ça semblait "marcher avant" avec les mêmes types de données dans la base. Mais je peux t'assurer que je suis sûr de ce que j'avance sur les problèmes liés aux réels et aux arrondis et que chez nous on a banni tout le code qui utilisait float ou double pour utiliser exclusivement decimal. Par ailleurs dans nos bases on n'a que du numeric (Sybase SQL Anywhere) et aucun réel.

Si tu le peux, je t'invite fortement à changer de type de valeur numérique...

Pour étayer mes propos, tu peux consulter wikipedia sur la virgule flottante, notamment les précautions d'emploi inhérentes.

En espérant aider...


The best programs are the ones written when the programmer is supposed to be working on something else. - Melinda Varian

Mes réponses PB sur StackOverflow
http://stackoverflow.com/users/flair/317266.png

Hors ligne

 

#3 12-12-2011 18:00:25

FMolinas  
Membre Geek
Lieu: Lyon
Date d'inscription: 12-06-2007
Messages: 87
Pépites: 97
Banque: 6,435,474,948,567

Re: 9.450000000000001 = 9.450000000000003 ???

seki a tout dit, ou presque. J'ajouterai un autre lien que j'aime bien sur le sujet, en anglais malheureusement : Floating-point guide

Pour ceux (dont je fais partie...) qui n'ont pas la chance d'avoir pu bannir l'arithmétique flottante de leurs applications de gestion, deux techniques palliatives :
1) Conversion à la volée vers des types décimaux. La précision devra être suffisante pour les calculs mais assez faible pour ne pas prendre en compte la micro-anomalie générée par le stockage flottant dans les profondeurs des décimales. La conversion devra se faire dès lecture de la base, avant toute manipulation qui amplifierait l'erreur.
2) Utiliser des filtres "permissifs" utilisant des expressions du genre "abs(data - cible) < 0.00001".

Dans les deux cas, ce n'est pas beau, mais ça permet de se débrouiller. La meilleure solution reste de changer les types de données à la source. Encore faut-il pouvoir mobiliser les ressources nécessaires pour ce genre de projet... (soupir)

Hors ligne

 

Pied de page des forums

Propulsé par FluxBB 1.2.22