Ver Mensaje Individual
  #2 (permalink)  
Antiguo 02/01/2008, 17:39
Avatar de derkenuke
derkenuke
Colaborador
 
Fecha de Ingreso: octubre-2003
Ubicación: self.location.href
Mensajes: 2.665
Antigüedad: 21 años, 4 meses
Puntos: 45
Re: Ayuda!!! Sumas y restas no exactas

Bueno Angel_Cruijff:

Tengo que decirte que has descubierto un BUG -no famoso- de javascript. Y contra el que no podemos luchar. Lo único que se puede hacer es usar Math.round(), o algo así.

El bug no se queda ahí, fallan muchas más cosas. Falla la suma de elementos decimales, falla la multiplicación... como ves o_O

¿Cuánto dirías que da 0.1*0.1? Exacto, da 0.010000000000000002.
Tampoco hay que ir tan lejos. ¿0.2+0.1? Bien: 0.30000000000000004

En números enteros (integer) no he encontrado nada... Menos mal.

He hecho un pequeño script que revela que para multiplicaciones de números de una décima tenemos un montón de errores. Se apoya en multiplicar los números sumándolos (3*2 = 3+3), y comparar esos dos resultados.

Código:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es" lang="es">
<head>
<meta http-equiv="Content-type" content="text/html;charset=iso-8859-1" />
<meta name="Author" content="derkeNuke" />
<title>Bug de Math en javascript</title>
<style type="text/css">

</style>
</head>

<body>


<script type="text/javascript">
<!--


// escribir en el documento una ristra (x)html fuera de tiempo de ejecución.
function e(q,sinBR) {
	var elDIV = document.createElement("DIV");
	if(q==undefined) q="";
	if(!sinBR) q+="<br/>";
	elDIV.innerHTML = q;
	for(var a=0; elDIV.childNodes.length>a; a++) {
		document.body.appendChild( elDIV.childNodes[a].cloneNode(true) );
	}
}



// Si x = 0.04 nos devuelve [4, 100]. El número en entero y el multiplicador necesario para ello.
function aEntero(x) {
	var multiplicador = 1;
	while( x!=parseInt(x) ) {
		multiplicador *= 10;
		// corremos la coma 1 posicion
		x = Number( x.toString().replace(/(\.)(\d)/, "$2$1") );
	}
	return [x, multiplicador];
}

// Multiplicación manual: Multiplica dos números sumando y veces el x
function m(x,y) {
	x = aEntero(x);
	y = aEntero(y);
	var mult = x[1] * y[1];
	for(var i=0, r=0; i<y[0]; i++)
		r+=x[0];
	return r/mult;
}

// Compara la multiplicación nativa con la manual, devuelve true si no son iguales (si hay bug)
function hayBug(x,y) {
	var mult = (x*y);
	var bien = m(x,y);
	var o = [ (mult!=bien), bien, mult ];
	o.toString = function() { return this[0]; }
	return o;
}


// Bucle principal
for(var i=0; i<1; i+=0.1, i=Math.round(i*10)/10 ) {
	for(var j=0; j<1; j+=0.1, j=Math.round(j*10)/10 ) {
		var b = hayBug(i,j);
		if( b[0] ) {
			e( i+"*"+j+" = "+ b[1] +", pero da "+b[2] );
		}
	}
	e();
}

// -->
</script>

</body>
</html>


Bueno, no sé si posteé sobre esto hace tiempo, no lo he encontrado -de todas maneras no habría tenido respuestas, me acordaría- pero si alguien sabe de este tema, o de sitios donde hablen de ello y la 'regla' que lo produce, que lo postee por favor.

A estas alturas y con bugs tan gordos...




Un saludo y a ver si se agregan más detalles de ésto
__________________
- Haz preguntas inteligentes, y obtendrás más y mejores respuestas.
- Antes de postearlo Inténtalo y Búscalo.
- Escribe correctamente tus mensajes.