IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

EDI, CMS, Outils, Scripts et API PHP Discussion :

round() : bizarre ? [Wamp]


Sujet :

EDI, CMS, Outils, Scripts et API PHP

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    73
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 73
    Par défaut round() : bizarre ?
    Bonjour.

    Désolé pour le titre du sujet peu explicite.

    Le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    echo($odds_missings[$combos_book_id[$groupe][$number]]);
    echo($odds_rounds[$combos_book_id[$groupe][$number]]);
    echo(round($odds_missings[$combos_book_id[$groupe][$number]], $odds_rounds[$combos_book_id[$groupe][$number]]));
    echo(round(6.765, 2));
    me donne :
    6.765
    2
    6.76
    6.77

    Je ne comprends vraiment pas.

    Si quelqu'un a une idée.

  2. #2
    Membre Expert Avatar de Amara
    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    2 688
    Détails du profil
    Informations personnelles :
    Localisation : France, Sarthe (Pays de la Loire)

    Informations forums :
    Inscription : Juillet 2004
    Messages : 2 688
    Par défaut
    Je crois avoir lu récemment une histoire semblable, le problème venait du stockage des valeurs des variables, par exemple ton chiffre peut être stocké 6.764999999 ce qui donnerait en arrondissant 6.76 et pas 6.77.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    73
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 73
    Par défaut
    Sans vouloir insister, je ne comprends toujours pas.

    $odds_missings[$combos_book_id[$groupe][$number]] = 6.765
    $odds_rounds[$combos_book_id[$groupe][$number]] = 2
    round($odds_missings[$combos_book_id[$groupe][$number]], $odds_rounds[$combos_book_id[$groupe][$number]])) = round(6.765, 2) = 6.77
    Or il m'affiche 6.76

    Pour être précis, j'ai recréé un code minimal pour montrer le bug :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $a = 1;
    $b = 1;
    $c[$a][$b] = 1;
    echo ($d[$c[$a][$b]] = 3.3 * 2.05) . '<br>';
    echo($e[$c[$a][$b]] = 2) . '<br>';
    echo round($d[$c[$a][$b]], $e[$c[$a][$b]]) . '<br>';
    echo round(6.765, 2);

  4. #4
    Membre chevronné
    Profil pro
    Inscrit en
    Août 2006
    Messages
    379
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 379
    Par défaut
    6.765 => Valeur arrondi.
    6.7649999999 => Véritable valeur.

    6.7649999999 à l'arrondi à 10^-2 => 6.76 car 0.49999999 < 0.5

    C'est pas plus compliqué.

  5. #5
    Expert confirmé
    Avatar de mathieu
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    10 667
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 10 667
    Par défaut
    Citation Envoyé par jpascal
    Pour être précis, j'ai recréé un code minimal pour montrer le bug :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $a = 1;
    $b = 1;
    $c[$a][$b] = 1;
    echo ($d[$c[$a][$b]] = 3.3 * 2.05) . '<br>';
    echo($e[$c[$a][$b]] = 2) . '<br>';
    echo round($d[$c[$a][$b]], $e[$c[$a][$b]]) . '<br>';
    echo round(6.765, 2);
    désolé mais ton code de test m'affiche deux fois '6.77'
    je ne pourrais pas te dire s'il s'agit d'un bug dans ta version de PHP (ou la mienne) ou bien un problème de logique d'utilisation des valeures réelles

    Déjà pout savoir comment est stockée la valeur "6.765" utilise le code suivant, tu auras des autres suprises
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    echo serialize($d[$c[$a][$b]]) . '<br>';
    echo serialize(6.765) . '<br>';

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    73
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 73
    Par défaut
    En effet, je suis surpris.
    Je ne comprends pas quel est l'intérêt de stocker la valeur 6.765 sous la forme 6.7649999999999987920773492078296840190887451171875 ???
    Car on a quand même 3.3*2.05 = 6.765, j'ai vérifié à la main.

    J'ai la version 5.2 fournie avec WAMP 1.6.6

    D'autres personnes peuvent-elles lancer mon prog pour savoir ce qu'elles obtiennent et avec quelle version ?

    Pour moi
    php : 5.2.0
    résultat : 6.76 / 6.77

  7. #7
    Membre émérite
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    1 012
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 012
    Par défaut
    oui j'ai le même résultat

    mais l'explication de spiritofdoc est claire

    tu réfléchis en base 10, donc pour toi 3.3*2.05 = 6.765 tout rond
    mais toute information est stockée en base 2. essaie de mettre n'importe quel nombre réel en base 2 et tu verras que dans de nombreux cas cela ne peut se faire aussi nettement.
    donc, 6.765 étant stocké sous une forme 11011101 (ce n'est sûrement pas cela, j'ai mis n'importe quoi), cela peut donner 6.765000000001 ou 6.7649999999

    ce n'est pas qu'il y a un intérêt, c'est la conception de l'informatique en binaire qui fait cela

  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    73
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 73
    Par défaut
    Hum

    De ce que tu m'écris je peux donc en déduire qu'en base 2 :
    6.765 = 6.765 (voir serialize($num))
    ET
    3.3 != 3.3 OU/ET 2.05 != 2.05 (voir serialize($a))

    Ca me parait bizarre.


    P.S. : Un code pour tester chez vous
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    echo $num = 6.765 . '<br>';
    echo ($a = 3.3 * 2.05) . '<br>';
    echo ($b = 2) . '<br>';
    echo serialize($num) . '<br>';
    echo serialize($a) . '<br>';
    echo 'Arrondi avec variables : '.round($a, $b) . '<br>';
    echo 'Arrondi avec valeurs : '.round(6.765, 2) . '<br>';
    echo round($num, 2);

  9. #9
    Membre émérite
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    1 012
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 012
    Par défaut
    pas vraiment non

    dans ton dernier code, 6.765 en binaire donne 6.765 mais est considéré comme un single

    rajoute à la fin de ton code les lignes suivantes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    echo ($num = 3.3) . '<br>';
    echo serialize($num) . '<br>';
    echo ($num = 6.765) . '<br>';
    echo serialize($num) . '<br>';
    et tu verras que 3.3 ne donne pas exactement 3.3. du coup, $num est considéré comme un double par php afin de d'approcher au mieux de 3.3.
    et quand tu re-affiches serialize($num), il reste en double et donne un résultat légèrement différent

    en conclusion, il faut que tu te souviennes qu'un nombre stocké n'est pas forcément exactement le nombre attendu

    et pour obtenir un bon résultat, la solution est simple : tu fais l'affichage de ton arrondi après y avoir additionné une valeur epsilon, par exemple .00001 pour un arrondi de 2 chiffres derrière la virgule

  10. #10
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    73
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 73
    Par défaut
    3.3 = d:3.29999999999999982236431605997495353221893310546875;
    2.05 = d:2.04999999999999982236431605997495353221893310546875;
    6.765 = d:6.76499999999999968025576890795491635799407958984375;
    La messe est dite.

    Je vais dorénavant suivre ton conseil francis m.

    Par contre je persiste et signe. Quel intérêt de dire qu'un round($a, 2) donne 1.12 alors qu'en pratique, si $a = 1.115 mais est une valeur calculée, le résultat sera 1.11 ???


    Pourquoi choisir 0.00001 (10^-5) pour un arrondi de 2 et pas 0.001 (10^-3) ?

    Dorénavant je compte donc utiliser à la place la fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    function round_perso($value, $precision)
    {
    	$new_value = $value + pow(10, -1 - $precision);
    	return round($new_value, $precision);
    }
    Est-ce que cela vous semble juste ?

  11. #11
    Membre émérite
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    1 012
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 012
    Par défaut
    oui la fonction me semble juste, à un détail près

    j'ai indiqué 10^-5 pour un arrondi à 2 parce que je ne souhaite pas trop influencer le chiffre, juste corriger un delta de stockage

    et avec 10^-3 tu modifies ton chiffre, tu fais plus que corriger l'erreur de stockage :

    exemple : si ton chiffre = 3.764, round donne logiquement 3.76
    si tu ajoutes .001 cela donne 3.765 et le round donne 3.77

    bien sûr tu as le même problème avec 10^-5 :
    3.76499 donne 3.76
    +.00001 = 3.76500 donne 3.77
    mais l'erreur est moins flagrante

    sur l'essai que tu viens de faire, tu constates que la correction de stockage peut se faire avec 10^-15 ...

    à part cela, tu as raison sur le principe de la fonction round, mais ce problème existe sur les fonction d'arrondis dee tus les logiciels que je connais...

  12. #12
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    73
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 73
    Par défaut
    En effet, j'ai posté mon code trop vite.
    Un meilleur code serait donc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    function round_perso($value, $precision)
    {
    $new_value = $value + pow(10, -10 - $precision);
    return round($new_value, $precision);
    }
    Merci à toi et aux autres pour toutes ces explications.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. taille de structure bizarre ...
    Par lyrau dans le forum C
    Réponses: 3
    Dernier message: 20/11/2003, 10h46
  2. OpenDialog(round 2)
    Par shogoune dans le forum Composants VCL
    Réponses: 4
    Dernier message: 10/06/2003, 14h10
  3. qu'est ce que l'instruction "round"?
    Par isa_21 dans le forum Langage SQL
    Réponses: 2
    Dernier message: 10/03/2003, 10h37
  4. Un String Bizarre
    Par YanK dans le forum Langage
    Réponses: 6
    Dernier message: 07/02/2003, 11h05
  5. Réponses: 4
    Dernier message: 28/09/2002, 00h00

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo