Précédent   Forum des professionnels en informatique > PHP > Outils > WAMP
WAMP Forum d'entraide sur WAMP (Windows Apache MySQL PHP) : installation, utilisation, etc.
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 14/02/2007, 14h30   #1
Nouveau Membre du Club
 
Inscription : avril 2005
Messages : 70
Détails du profil
Informations forums :
Inscription : avril 2005
Messages : 70
Points : 25
Points : 25
Par défaut round() : bizarre ?

Bonjour.

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

Le code :
Code :
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.
jpascal est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 14/02/2007, 14h54   #2
Expert Confirmé

 
Avatar de Amara
 
Inscription : juillet 2004
Messages : 2 684
Détails du profil
Informations personnelles :
Localisation : France, Sarthe (Pays de la Loire)

Informations forums :
Inscription : juillet 2004
Messages : 2 684
Points : 2 910
Points : 2 910
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.
__________________
Pas de questions techniques par MP, le forum est là pour ça et est plus efficace.

Orthographe : une connexion (avec un x), un langage (sans u), une requête (un seul t), 'une quote' (avec qu), une syntaxe (sans h)
Amara est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 15/02/2007, 03h42   #3
Nouveau Membre du Club
 
Inscription : avril 2005
Messages : 70
Détails du profil
Informations forums :
Inscription : avril 2005
Messages : 70
Points : 25
Points : 25
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 :
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);
jpascal est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 15/02/2007, 09h19   #4
Membre éclairé
 
Inscription : août 2006
Messages : 379
Détails du profil
Informations personnelles :
Âge : 24

Informations forums :
Inscription : août 2006
Messages : 379
Points : 383
Points : 383
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é.
SpiritOfDoc est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 15/02/2007, 10h04   #5
Modérateur
 
Avatar de mathieu
 
Inscription : juin 2003
Messages : 4 893
Détails du profil
Informations forums :
Inscription : juin 2003
Messages : 4 893
Points : 4 466
Points : 4 466
Citation:
Envoyé par jpascal
Pour être précis, j'ai recréé un code minimal pour montrer le bug :
Code :
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 :
1
2
echo serialize($d[$c[$a][$b]]) . '<br>';
echo serialize(6.765) . '<br>';
__________________
Modérateur PHP
mathieu est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/02/2007, 01h21   #6
Nouveau Membre du Club
 
Inscription : avril 2005
Messages : 70
Détails du profil
Informations forums :
Inscription : avril 2005
Messages : 70
Points : 25
Points : 25
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
jpascal est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/02/2007, 02h00   #7
Membre émérite
 
Inscription : juin 2002
Messages : 1 013
Détails du profil
Informations forums :
Inscription : juin 2002
Messages : 1 013
Points : 959
Points : 959
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
francis m est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/02/2007, 03h23   #8
Nouveau Membre du Club
 
Inscription : avril 2005
Messages : 70
Détails du profil
Informations forums :
Inscription : avril 2005
Messages : 70
Points : 25
Points : 25
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 :
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);
jpascal est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/02/2007, 15h46   #9
Membre émérite
 
Inscription : juin 2002
Messages : 1 013
Détails du profil
Informations forums :
Inscription : juin 2002
Messages : 1 013
Points : 959
Points : 959
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 :
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
francis m est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/02/2007, 17h43   #10
Nouveau Membre du Club
 
Inscription : avril 2005
Messages : 70
Détails du profil
Informations forums :
Inscription : avril 2005
Messages : 70
Points : 25
Points : 25
Citation:
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 :
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 ?
jpascal est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/02/2007, 22h51   #11
Membre émérite
 
Inscription : juin 2002
Messages : 1 013
Détails du profil
Informations forums :
Inscription : juin 2002
Messages : 1 013
Points : 959
Points : 959
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...
francis m est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/02/2007, 01h51   #12
Nouveau Membre du Club
 
Inscription : avril 2005
Messages : 70
Détails du profil
Informations forums :
Inscription : avril 2005
Messages : 70
Points : 25
Points : 25
En effet, j'ai posté mon code trop vite.
Un meilleur code serait donc :
Code :
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.
jpascal est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 02h26.


 
 
 
 
Partenaires

Hébergement Web