C/Visual C - Teleco

 
Vista:

Teleco

Publicado por Bea (2 intervenciones) el 02/04/2009 11:21:05
Hola,

Estoy empezando a programar con Visual Studio y me ha surgido un problema...

Tengo las siguientes variables declaradas:

float t;
float STOPTIME, dt;

y luego

STOPTIME=8000000;
dt=0.01;
t=0;

for(step=0;t<STOPTIME;step++) //esta es la forma de acualizar t

t+=dt;

La cuestión es que no se por qué motivo mi dt no es 0.01 sino que es 0.010000000001, de forma que al principio no tiene importancia pero cuando va aumentando el número de steps esto si que me afecta.

Otra cosa, mucho más curiosa es que cuando t=32768; el programa empieza a pasar de la linea que actualiza t, es decir, pasa por la linea, porque lo he visto poniendo puntos de interrupción, pero t sigue valiendo 32768 para siempre, lo que produce que nunca se salga del bucle for!!

¿por qué pasa esto?¿qué tiene de especial el número 32768?
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder

RE:Teleco

Publicado por fernando.gomez (1603 intervenciones) el 03/04/2009 08:10:01
Los floats no son exactos: cambian exactitud con tal de tener precisión (en número de decimales). No hay nada de curioso en tu código, todo lo que comentas es esperado, por la forma en la que funciona la aritmética de números de punto flotante.

El siguiente artículo te da información sobre cómo se implementan los floats. En particular, en la segunda parte del artículo está la sección titulada "Effective FP Programming", cuya primera sub-sección, "Equality" detalla cómo se hace la comparación de floats y el por qué del comportamiento que estás observando.

http://www.cprogramming.com/tutorial/floating_point/understanding_floating_point.html

Por cierto, en tu ejemplo inicializas t = 0, el cuál es un entero. Intenta inicializar t = 0.0F. El sufijo F le indica al compilador que trabajas con un float (de no postfijarlo con F, el compilador asumirá que el número es un double, pero esto no suele representar un problema; pero el punto decimal sí es importante).

La solución pués, a este problema, sería que determinaras el número significativo de decimales que requieres. En tu ejemplo, solo son significativos hasta dos decimales, por lo que bien podrías truncar (o redondear) el resultado final. Revisa las funciones definidas en<math.h> si trabajas con C, o <cmath> si trabajas con C++.

Con respecto al segundo punto... Asumamos que step es de tipo entero. En plataformas contemporáneas el entero suele ser de 16 bits (consulta la información de tu compilador en particular). Esto implica que un entero puede guardar hasta 2^16 números distintos; esto es, 65536. Pero un entero guarda números positivos y negativos, por lo que el rango se divide la mitad para los negativos y la mitad para los positivos. Y la mitad de 2^16 es 32768, que es el número mágico que te da problemas.

Luego entonces, ese comportamiento sucede porque al llegar a 32768 y quererle aumentar en uno, tu variable se desborda e incurres en un comportamiento indefinido y por ende, cualquier cosa puede suceder. En tu caso, la variable simplemente no aumenta.

Una opción en estos casos es emplear un entero sin signo (unsigned int), ya que al no tener que manejar negativos, tu rango aumenta de 0 a 65536. Pero aún así es muy poco para el número 8,000,000 que quieres alcanzar. La solución radica en utilizar una variable que sea más grande. El tipo de dato long suele ser de 32 bits en plataformas contemporáneas (nuevamente, consulta la información de tu compilador), así que tienes un rango de 2^32, es decir, 4,294,967,296 números, que tomando el rango de negativos, te da un rango neto de -2147483647 a 2147483648, suficientes para alcanzar los 8,000,000 de tu ejemplo.

Saludos.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar