11544 sujets

JavaScript, DOM et API Web HTML5

Pages :
(reprise du message précédent)

Release 1 d'accurateRoundTo suite à remaque Tony Monast des erreurs sur les nombres compris entre 0 et 1 et traitement des nombres négatifs :




	function accurateRoundTo(number,precision){

		var	nstr, parts, resint, dotpos, dummy, isneg, isnul;

		isneg=0;
		isnul=0;
		parts=new Array();
		if(number<0){
			number=Math.abs(number);
			isneg=1;}		
		nstr=number.toString();
		dotpos=nstr.indexOf(".",0);
		if((dotpos<0)||(nstr.length<(dotpos+precision+2))){
			if(isneg)
				return("-"+nstr);
			else
				return(nstr);}
		parts=nstr.split(".");
		if(parts[0]=="0"){
			parts[0]="10";
			isnul=1;}
		resint=parts[0]+parts[1].substr(0,precision);
		if(parseInt(parts[1].charAt(precision))>4){
			dummy=parseInt(resint)+1;
			resint=dummy.toString();}
		parts[0]=resint.substr(0,resint.length-precision);
		parts[1]=resint.substr(parts[0].length,precision);
		if(isnul)
			parts[0]=parts[0].substr(1,1);
		if(isneg)
			parts[0]="-"+parts[0];
		return(parts[0]+"."+parts[1]);}

Modifié par aCOSwt (19 Jan 2007 - 22:39)
....

bonsoir , très intéressant .. mais je crois que ce post je vais me le garder pour demain matin .. à tête reposée Smiley lol
kzone a écrit :
....

bonsoir , très intéressant .. mais je crois que ce post je vais me le garder pour demain matin .. à tête reposée Smiley lol


Tu as bien raison, regarde Tony, il a voulu lire l'explication à 2h39 du matin et... je ne suis pas sûr qu'il était dans sa meilleure forme...

Ce d'autant que les mauvaises nouvelles sur ce sujet ne font que... commencer.
Je suis à l'étude de quelques corollaires du problème soulevé par Tony et de ses raisons... le sujet ne s'arrête pas là.
J'en dirai plus plus tard.
Modérateur
aCOSwt a écrit :

Tu as bien raison, regarde Tony, il a voulu lire l'explication à 2h39 du matin et... je ne suis pas sûr qu'il était dans sa meilleure forme...


Oh, je ne suis pas aussi assidu que ca. Je suis rarement debout à 2h00 du matin. C'est le fuseau horaire, je suis au Québec. Smiley cligne
Tony Monast a écrit :

...C'est le fuseau horaire, je suis au Québec. Smiley cligne


Tabernacle !
Salut cousin !
-------------------------
Bon ! C'est pas le tout ça mais comme promis, laissez-moi vous livrer quelques side-effects de la bombe que Tony a lancée sur ce forum :

En effet, étant données les causes de l'erreur détectée par Tony, il n'y a évidemment pas que la fonction round qui soit impactée...

C'est potentiellement tout calcul mathématique, à commencer par la plus simple des additions.

Julien Royer notait que 100 * 9.075 = 907.49999999...
Je vous recommandais de calculer 0.1 + 0.2 = 0.30000000000000004

Vous vous imaginez un peu :


function loto(x,y){

         z=x+y;
         if(z==0.3)
             alert("vous gagnez le gros lot");
         else
             alert("vous avez perdu !");}


Alors vous tentez votre chance avec loto(0.1,0.2)
Et...
VOUS AVEZ PERDU !

Et oui, ce topic ne concerne plus que les seuls paranoids de la précision max. Malgré la meilleure des analyses fonctionnelles / détaillées aucun test ne passera sans accroc notable !

LE REMEDE :

Je ne vois qu'une seule solution à cela :

ARRONDIR ! arrondir en permanence avant les instructions de tests.

Arrondir en cohérence avec la nature des nombres impliqués dans le code.
Si on sait que l'on travaille avec deux chiffres après la virgule, il FAUT tout arrondir à deux chiffres après la virgule.

Par exemple, dans mon exemple plus haut, ce n'est pas z qu'il faut tester mais bien l'arrondi de z.

Et si on cherche à travailler avec la précision maximale alors... il faut arrondir à la 16° décimale quoique la 15° me semblerait plus secure.

ARRONDIR !

Pas avec Math.round, Math.floor ou Math.ceil évidemment, on a vu plus haut les souçis.
Arrondir avec un truc du style accurateRoundTo !

Je reprends donc mon exemple plus haut en partant de l'hypothèse que mon analyse a déterminé que ma procédure n'aurait pas à traiter de nombres x et y de plus de 3 décimales :


function loto(x,y){

         z=accurateRoundTo(x+y,3);
         if(z.valueOf==0.3)
             alert("vous gagnez le gros lot");
         else
             alert("vous avez perdu !");}


Allez... Rien n'est perdu...
Modifié par aCOSwt (21 Jan 2007 - 19:10)
Et Hop ! Une release de plus...

En fait, une alternative :

En effet, comme le disait Julien Royer, tout traiter en chaine de caractère... ce n'est pas une perspective joyeuse joyeuse...
Comme le problème est tout de même mathématique et logique à la base, il se devait d'exister une solution purement mathématique.

Je l'ai cherchée et... la voilà :


	function accurateRoundTo(number,precision){
		
		var	isneg, nbdgtlft, signif, corrfct;
		
		if((precision<0)||(number==0))
                         return(number);
                isneg=0;
		if(number<0){
			number=Math.abs(number);
			isneg=1;}
		nbdgtlft=Math.ceil(Math.log(number)/Math.LN10);
		signif=15-nbdgtlft;
		if((precision<signif)&&(signif>0)){
			corrfct=Math.pow(10,signif);
			number=(number*corrfct+5)/corrfct;
			corrfct=Math.pow(10,precision);
			number=Math.round(number*corrfct)/corrfct;}
		if(isneg)
			number=0-number;
		return(number);}


Le principe consiste à arrondir 2 fois.
- Une fois à la précision max possible pour compenser l'erreur de non arrondi du 53° digit de la mantisse,
- une seconde fois à la précision voulue si celle-ci est inférieure à la précision max dispo.

Autre avantage, le résultat de l'opération reste un numérique. Plus besoin de valueOf dans les tests.
Modifié par aCOSwt (22 Jan 2007 - 13:47)
Modérateur
Salut aCOSwt,

Je n'ai pas encore eu le temps de jeter un oeil à ta dernière fonction. Je suis plutôt dans le rush cette semaine. Je vais y revenir dans quelques jours.

Merci en tout cas ! Smiley smile
Il faut tout simplement utiliser la fonction javascript toFixed(y) où y est le nombre décimales.
Modérateur
Samos a écrit :
Il faut tout simplement utiliser la fonction javascript toFixed(y) où y est le nombre décimales.


Non, justement, toFixed fonctionne plutôt mal dans Firefox. J'énonce justement le problème dès le premier message. Smiley cligne
Modifié par Tony Monast (06 Mar 2007 - 15:00)
Pages :