Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Mi micro no sabe multiplicar...

Iniciado por fiero, 18 de Octubre de 2002, 01:05:55 AM

« anterior - próximo »

fiero

                                Bueno, esto es un error en un código muy sencillo, del que me acabo de dar cuenta. Resulta que quiero multiplicar un número en coma flotante por 10 y asignarselo a un entero. Algo en teoría trivial, pero que requiere dos lineas de código para que salga el resultado que yo quiero:



int entero;

float flotante,angulo=-179.9;



entero=angulo*10; //Resultado de esta operación entero=-1798



flotante=angulo*10;

entero=flotante;  //Resultado de esta operación entero=-1799



La línea de arriba es la que yo ponía antes de detectar el error, y como veis, se pierde una décima en la operación. Las líneas de abajo funcionan bien.

Explicación:


entero=angulo*10;

  fld     dword ptr [angulo] // ST0 = -1.79899993896484375e+0002

  fmul  dword ptr [__real@41200000]   // numero 10.0

  call    __ftol

  mov  dword ptr [entero],eax





flotante=angulo*10;

  fld     dword ptr [angulo] // ST0 = -1.79899993896484375e+0002

  fmul  dword ptr [__real@41200000]   // numero 10.0

  fstp   dword ptr [flotante]  // flotante=-1799.0



entero=flotante;

  fld     dword ptr [flotante] // ST0 = -1.79900000000000000e+0003

  call    __ftol

  mov  dword ptr [entero],eax



Como veis, el error se produce porque la instrucción FLD carga el número -1.79899993896484375e+0002 en el coprocesador, en vez de -1799.0 y luego al pasarlo a entero con la función FISTP (que hay dentro de __ftol) se recortan los decimales y se jode una decima del número. Por defecto el copro siempre "recorta" en vez de "redondear".
En las instrucciones de abajo el error se corrige porque la instrucción FSTP redondea el número a -1799.  INEXPLICABLEMENTE  :o en la siguiente instrucción FLD se carga ST0 = -1.79900000000000000e+0003

Alguien me puede decir por qué en la primera operación FLD se carga ST0 = -1.79899993896484375e+0002 y en la segunda ST0 = -1.79900000000000000e+0003 ????

Tambien me gustaría saber si este código funciona igual en un K7, yo tengo un PIII. Solo teneis que copiar las 5 líneas en C para probarlo...

gracias y perdón por el tocho
un saludo                                
www.videopanoramas.com Videopanoramas 3D player

fiero

                                Acabo de probar una cosa, los números terminados en .0 ó .5 se cargan bien en el coprocesador, los demás se cargan con decimales de basura de más o de menos....

Estoy pasando algo por alto? es mi micro o todos los ordenadores del mundo mundial pierden una décima en cada multiplicación??... no entiendo nada....                                
www.videopanoramas.com Videopanoramas 3D player

sés

                                Utiliza double en lugar de float, a mí me soluciona los problemas de "basura".                                
Soy indeciso... ¿o no?

synchrnzr

                                Todos los ordenadores del mundo pierden precisión en los últimos decimales debido a la conversión a binario del número con coma flotante. Para comprobarlo sólo tienes que cambiar de base tu -179,9 a binario y verás cómo te da un número con decimales infinitos (sabes pasar números decimales a binario ¿verdad? ;))

Sync                                

sés

                                Pos la verdad es que yo no me acuerdo. Este... no acostumbro a hacerlo :P
Sólo recuerdo que era una coñazo impresionante y que entraba en los exámenes ^_^                                
Soy indeciso... ¿o no?

fiero

                                La verdad es que nunca me habia dado por estudiarme la codificación de un número flotante, por vagancia (ya que yo no he estudiado informatica en la uni). Acabo de echarle un vistacillo por encima a como se hace y ahora lo comprendo. A primera vista, lo primero que se me ocurre es "vaya mierda de sistema de codificación". No sé por qué lo han hecho así, ya lo estudiaré más a fondo a ver si entiendo algo...

Yo pensaba que se codificaba de una forma más simple, en binario de toda la vida. Es decir, para el caso de un float de 32, un bit para el signo, 8 bits para el exponente y los 23 bits restantes para la mantisa. De esa forma, se tienen hasta 7 digitos decimales significativos del número. Y claro codificar el número 1799 con 23 bits es una mingada, pero tal y como se hace con la norma IEEE esta, no lo tengo tan claro.

De todas formas los decimales se pierden al cargar el número en el coprocesador. Y lo acabo de probar con DOUBLES y tambien se pierde, en este caso en la centésimas (32 bits más de precisión para salvar las décimas  :-? )

Ejemplo: Si quiero almacenar un número double dentro de un entero, pero multiplicado por 100 para coger hasta las centésimas, necesito hacerlo en dos pasos y con una variable auxiliar para que me salga bien:



int entero;

double flotante,angulo=-179.91;



entero=angulo*100; //Resultado de esta operación entero=-17990



flotante=angulo*100;

entero=flotante;  //Resultado de esta operación entero=-17991



saludos                                
www.videopanoramas.com Videopanoramas 3D player

ethernet

No se si te has dado cuenta pero el error q tienes es pequeño por q una unidad cuando estas trabajando con 2000 no es tanto.
De todas maneras:



int abajo, redondea;

float a=0.6;

abajo=(int)a;

redondea= (int)(a+0.5);


saludos






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.