11496 sujets

JavaScript, DOM et API Web HTML5

Bonjour,

je fais un calcul avec jquery pour additionner les valeurs présentes dans des checkbox

$("div#accessoires input:checked").each(function() {
totalaccessoires += Number($(this).val());
});

Chaque checkbox à une valeur pouvant avoir une virgule et au maximum deux chiffres après la virgule.

par exemple dans un cas de figure j'ai les valeurs suivante :
5
1
0.1
1
1
3.12

ce qui devrait me donner 11,22

sauf que ça me donne 11.21999999999999999999

Je comprends pas.. Ce n'est qu'une simple addition, où va-t il cherche ce 0.00000000....1 en moins..

J'ai essayé ParseFloat à la place de number, mais ça ne change rien..

Une idée ?
Modifié par esk57 (15 Apr 2014 - 11:55)
J'ai trouvé une piste, même si je n'ai pas trouvé la solution..

En gros j'ai compris que par exemple "0.1" n'est pas égale à 0.1 Smiley lol

Voici une réponse extraite d'une discutions trouvé ici : http://stackoverflow.com/questions/19088028/floating-point-addition-giving-strange-result

0.1 is not really "0.1" with IEEE 754 Standard.

0.1 is coded : 0 01111011 10011001100110011001101 (with float number)

0 is the sign (= positive)
01111011 the exponent (= 123 -> 123 - 127 = -4 (127 is the bias in IEEE 754))
10011001100110011001101 the mantissa

To convert the mantissa in decimal number we have 1.10011001100110011001101*2^-4(base2) [the 1.xxx is implicit in IEEE 754]

= 0.000110011001100110011001101(base2)

= 1/2^4 + 1/2^5 + 1/2^8 + 1/2^9 + 1/2^12 + 1/2^13 + 1/2^16 + 1/2^17 + 1/2^20 + 1/2^21 + 1/2^24 + 1/2^25 + 1/2^27 (base10)

= 1/16 + 1/32 + 1/256 + 1/512 + 1/4096 + 1/8192 + 1/65536 + 1/131072 ...(base10)

= 0.10000000149011612(base10)


Et donc ? que faire ? J'avoue que je comprends pas pourquoi 0.1 n'est pas = à 0.1.

Pourtant en php il me sort pas ce genre de folie à la Vandamme Smiley lol
C'est un problème classique avec les nombres à virgule flottante (float, double), utilisés implicitement en javascript pour tout nombre (number).

En soi tu ne peux rien faire contre cette imprécision, elle est inhérante à la représentation binaire manipulée par la machine, comme tu l'as déjà très bien remarqué. Tu dois savoir qu'elle existe et vivre avec.

Maintenant d'un point de vue pratique, tu peux faire en sorte que l'erreur ne soit pas apparante en faisant simplement un arrondi à l'affichage avec Math.floor/round/ceil. Si tu fais un arrondi à deux décimales, en principe tu n'as aucun problème, le type float sur 32 bits garantit au moins une précision à 4 ou 5 chiffres significatifs.

EDIT: en fait, javascript utilise des double sur 64 bits, en tout cas avec IE et firefox; donc la précision est d'au moins une bonne douzaine de chiffres significatifs.

[mode taré on]
Tant qu'à faire, prouvons-le, que javascript utilise bien des double et pas des float :

alert(Math.pow(2,28)+1);
alert(Math.pow(2,52)+1);
alert(Math.pow(2,53)+1);

Vous êtes d'accord avec moi pour dire que 2^n+1 est impair quelque soit n. Amusez-vous un peu et vous verrez qu'en javascript, ce n'est plus vrai pour n>=53. Cela nous indique que la taille de la mantisse est précisément de 53 bits, ce qui correspond au type double sur 64 bits (53 bits de mantisse, 10 bits d'exposant, 1 bit de signe). Le premier test avec n=28 aurait donné un résultat pair si javascript utilisait des float, car un float a seulement 24 bits de mantisse.
[/mode taré off]
Modifié par QuentinC (15 Apr 2014 - 14:34)
QuentinC a écrit :
C'est un problème classique avec les nombres à virgule flottante (float, double), utilisés implicitement en javascript pour tout nombre (number).

En soi tu ne peux rien faire contre cette imprécision, elle est inhérante à la représentation binaire manipulée par la machine, comme tu l'as déjà très bien remarqué. Tu dois savoir qu'elle existe et vivre avec.

Maintenant d'un point de vue pratique, tu peux faire en sorte que l'erreur ne soit pas apparante en faisant simplement un arrondi à l'affichage avec Math.floor/round/ceil. Si tu fais un arrondi à deux décimales, en principe tu n'as aucun problème, le type float sur 32 bits garantit au moins une précision à 4 ou 5 chiffres significatifs.


Merci pour cette réponse. J'avais pensé à arrondir, mais je me disais que ce n'était peut-être pas la "juste" méthode ^^. En tout cas j'aurai appris quelques chose.. même si je comprends pas trop pourquoi ils font ça comme ça alors que php ne le fait pas... m'enfin, merci Smiley cligne
Relisez le premier message, j'ai fait un peu mumuse, et en fait javascript utilise des double, pas des float comme je pensais initialement. J'avais quelques souvenirs qu'il en utilisait par le passé, peut-être dans un navigateur lointain.

A noter que php utilise aussi des double, j'ai fait le même petit test.