Autor Tema: Problemas con la instrucion atof  (Leído 6072 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Orko

  • Colaborador
  • PIC18
  • *****
  • Mensajes: 423
Problemas con la instrucion atof
« en: 26 de Mayo de 2008, 21:46:29 »
Hola a todos, tengo un problema con la instruccion atof, quizá me puedan ayudar a solucionarlo.

Tengo el siguiente programa donde deseo convertir una cadena de caracteres a su representacion en este caso un numero de punto flotante (float), pero al realizar la simulacion entrega un numero algo diferente al original.

#include <18F452.h>
#use delay(clock=4000000)
#include <stdlib.h>
char   cadena[12]={"4805.8021"};
float   total;

void main()
{
   total=atof(cadena);
}

El resultado esperado seria total=4805.8021, pero la realidad es total=4805.80176
Alguien sabe cuál es el problema o en su defecto, ¿como solucionar este problema asi sea con otro método?

Gracias de antemano.

Orko  8)

Desconectado Gonzalo_BlackHawk

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 519
Re: Problemas con la instrucion atof
« Respuesta #1 en: 26 de Mayo de 2008, 23:00:55 »
mmmm, en este momento no puedo probar nada, pero prueba tu esto:

Código: [Seleccionar]
#include <18F452.h>
#use delay(clock=4000000)
#include <stdlib.h>
char cadena[10];
float total;

void main()
{
   strcpy (cadena, "4805.8021");
   total = atof(cadena);
}

Luego me cuentas, saludos.
"Siempre piensa si el jugo vale la exprimida..."

"La muerte esta tan segura de vencer que nos da toda una vida de ventaja."

Desconectado migsantiago

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8257
    • Sitio de MigSantiago
Re: Problemas con la instrucion atof
« Respuesta #2 en: 27 de Mayo de 2008, 10:02:46 »
Parece ser un problema de redondeo de los float, no es posible asignar exactamente .8021 por los límites de trabajo de los float. Busqué en las definiciones de datos de CCS y no encontré double, que es un float con mayor precisión.

Talvez te convenga manejar la parte entera en un int16 y la parte decimal en el float para no perder precisión...

Código: [Seleccionar]
#include <18F452.h>
#use delay(clock=4000000)
#include <stdlib.h>
char   cadena[12]={"0.8021"};
int16 entero=4805;
float   decimal;

void main()
{
   decimal=atof(cadena);
}

Desconectado Gonzalo_BlackHawk

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 519
Re: Problemas con la instrucion atof
« Respuesta #3 en: 27 de Mayo de 2008, 14:36:20 »
Hola migsantiago, El tipo de datos double no se implementa en CCS (aunque sea una palabra reservada del compilador, es por un tema de compatibilidad) y en mi opinion no creo que sea un problema de precisión pues con el float se pueden lograr muchisimas mas decimales, yo he utilizado 20 ceros despues de la coma y no he tenido ningun problema, y creo que el alcance del float todavia vas mas alla de eso, el numero float de 32 bits que es el que implementa CCS tiene un rango permitido desde -1.5 x 10^45  a  3.4 x 10^38 y como es coma flotante podrías expresar una cantidad equivalente de decimales, dependiendo de cuantos enteros tienes despues de la coma.
Me parece que el asunto pasa por el tratamiento del numero mas que por el numero en si, hoy cuando vuelva a casa probaré en el Mplab a ver como es el asunto.

Nos estamos escribiendo.
"Siempre piensa si el jugo vale la exprimida..."

"La muerte esta tan segura de vencer que nos da toda una vida de ventaja."

Desconectado migsantiago

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8257
    • Sitio de MigSantiago
Re: Problemas con la instrucion atof
« Respuesta #4 en: 27 de Mayo de 2008, 16:28:08 »
Hola

Hice pruebas con el convertidor de números que trae CCS.

Primero ingresé el flotante 4805.8021, y el convertidor entrega 0x8B162E6B como los datos que se ingresan a los 4 bytes de la variable.



Luego borré el dato que capturé en flotante y borré el int que me entregó, y pegué el entero 0x8B162E6B para ver como hacía la reconversión a flotante...



El error que existe se debe a que se debe truncar el número flotante para poderlo convertir. El error que aquí existió es: -0.0001.

Hice otra prueba:

Flotante capturado: 123.45689999999 flotante binario: 8576E9EF
Binario capturado: 8576E9EF Flotante reconvertido: 1.2345690E+02
Error: 0.00000000001

Flotante capturado: 32.650856423 flotante binario: 84029A7A
Binario capturado: 84029A7A Flotante reconvertido: 3.2650856E+01
Error: 0.029999577

Flotante capturado: 0.0023657223321 flotante binario: 761B0A3C
Binario capturado: 761B0A3C Flotante reconvertido: 2.3657223E-03
Error: -0.0000000000321

Flotante capturado: 6.5434562136466 flotante binario: 815163FE
Binario capturado: 815163FE Flotante reconvertido: 6.5434560E+00
Error: -0.0000002136466

El error varía dependiendo del tamaño del entero, su exponente y la cantidad de decimales, pero la reconversión nunca es igual al número completo original, lo trunca.

También puse el número 4805.802123654654654654, y el int que genera deja de cambiar, se queda fijo en 0x8B162E6B, a partir del noveno dígito ignora los decimales.

Leí el archivo float.h de ccs y encontré que sí existe el double, hice una prueba con double y sí me dejó compilar...

Código: [Seleccionar]
#include <18F452.h>
#use delay(clock=4000000)
#include <stdlib.h>
char   cadena[12]={"4805.8021"};
double total;

void main()
{
   total=(double)atof(cadena);
   while(1);
}

Pero no lo pude simular, no sé si funcione, sobre todo porque atof entrega datos en float, y pues aunque use el casting no sirve de mucho.

Además el archivo float.h no muestra diferencia alguna entre float, double y long double, que es como mencionas Gonzalo.


Desconectado Gonzalo_BlackHawk

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 519
Re: Problemas con la instrucion atof
« Respuesta #5 en: 28 de Mayo de 2008, 16:22:28 »
Hola mig. Tenias razón, el float que utiliza microchip y por ende CCS posee una mantisa de 23 bits, por lo tanto no permite obtener numeros con una precisión mayor de 1.2 x 10^ -7, es decir 1 / (2^23).
Para el caso de Orko  tenemos una inexactitud de (4805.8021 - 4805.80176) / 4805.8021 = 7 x 10 ^ -8 lo cual estaria contemplado en la imprecisión del tipo de datos float.

Anduve leyendo algo de info sobre los numeros con comas flotantes y descubri esto. La imprecision de los numeros con coma flotante recae basicamente en dos causas. La primera es que la representacion de un numero esta contemplada con una precisión finita con el fin de conservar memoria. En nuestro caso, son los 23 bits de la mantisa. Esto no quiere decir que no podemos representar ningun numero con precisión, solo que aquellos que requieren mas de 23 bits de precisión son truncados.

Segundo, la base del sistema numerico (10 para el decimal y 2 para el binario) influye en cuan preciso puede un numero en particular ser representado. Por ejemplo es imposible representar el numero 0.3 en binario sin algun tipo de error pues hay que truncar el numero luego de cierta cantidad de bits (En nuestro caso 23). En cambio, en sistema binario no tenemos inconvenientes de representar el numero 0.5 con precision. Podemos extrapolar el mismo pensamiento al sistema decimal y por ejemplo el numero 1/3 y veremos que es imposible representar en este sistema numérico sin perder precisión (Para poder representar este numero con precision habria que trabajar con un sistema numerico de base 3). Como conclusión, y tal como lo ha dicho mig los numeros float conllevan una inexactitud dependiente de la cantidad de digitos significativos, los numeros contenidos en el y hasta en cierta medida del exponente.

Saludos.
"Siempre piensa si el jugo vale la exprimida..."

"La muerte esta tan segura de vencer que nos da toda una vida de ventaja."

Desconectado migsantiago

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8257
    • Sitio de MigSantiago
Re: Problemas con la instrucion atof
« Respuesta #6 en: 28 de Mayo de 2008, 17:34:16 »
jeje acabo de aprender algo nuevo, ya conocía lo del error del float pero no conocía el porqué

gracias Gonzalo  :mrgreen:

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Problemas con la instrucion atof
« Respuesta #7 en: 28 de Mayo de 2008, 17:46:11 »
Qué explicación, realmente magistral, Gonzalo.
El ejemplo del 0.3 y 0.5 es de lo más ilustrativo. Muchas gracias

Desconectado Orko

  • Colaborador
  • PIC18
  • *****
  • Mensajes: 423
Re: Problemas con la instrucion atof
« Respuesta #8 en: 29 de Mayo de 2008, 16:58:36 »
Hola,

Gracias por sus respuestas, todas son muy analíticas.
La presicion del proyecto me obliga a tener una exactitud del 100% frente a las cifras; es este orden de ideas que puedo hacer para lograr esta exactitud? ya que varios numeros flotantes serán guardados en una menoria serial para posterior análisis.

Alguna sugerencia adicional al respecto?

Gracias,

Orko  8)


Desconectado Gonzalo_BlackHawk

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 519
Re: Problemas con la instrucion atof
« Respuesta #9 en: 29 de Mayo de 2008, 17:32:13 »
Hola Orko, mira, si necesitas utilizar numeros con una cantidad de digitos significativos como el que tu expusiste, el 4805.8021 por ejemplo, estos pueden ser representados con exatitud del 100% utilizando numeros con coma fija. En tu caso te recomiendo que utilizes el tipo de datos int32 para guardar tus numeros. De esta forma puedes guardar el numero 4805.8021 por ejemplo como 48058021. De esta forma el numero en realidad se guarda como un entero lo cual trae aparejada ciertas ventajas. En primer lugar procesar un numero entero int32 es mucho mas rápido que procesar un numero float, para que te des una idea una resta de dos numeros int32 demora tan solo 3 us con un PIC a 20 MHz mientras que la misma operacion en formato float demora 113 us. La diferencia es apreciable y no puede obviarse. Segundo, una variable int32 ocupa lo mismo que una variable float, 4 bytes, asi que no hay una mayor demanda o no de memoria.

Hay muchas formas de manejar numeros con coma fija, y depende de lo que uno quiera hacer. Lo unico que debes tener en cuenta en tal caso es que la coma siempre quede colocada para todos los numeros en una misma posición, asi puedes realizar las operaciones sin necesidad de convertir los numeros. Por el rango de numeros que puedes guardar, una variable de 32 bits podria almacenar numeros, con 4 decimales como tu caso, de hasta 429496.7295 para una variable sin signo o bien hasta +-214748.3647 para una con signo. Eso es lo que yo te recomiendo en base a lo poco que conozco acerca de lo que quieres hacer, tal vez algun maestro del foro podria guiarte mejor.

Suerte.
"Siempre piensa si el jugo vale la exprimida..."

"La muerte esta tan segura de vencer que nos da toda una vida de ventaja."

Desconectado PalitroqueZ

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5474
    • Electrónica Didacta
Re: Problemas con la instrucion atof
« Respuesta #10 en: 29 de Mayo de 2008, 18:51:47 »
yo recuerdo que tuve problemas con un programa donde requería 9 digitos después de la coma y con un float de 32bits no se lograba (creo que con 32bits se llega a 7 digitos) entonces hice algo loco: cree tablas y tablas de datos, todos float y después en la ecuación, hacia sumas, y después con unas funciones ajustaba algunas partes del cálculo donde ocurria los errores de aproximación (tales como el 0,5).

es una forma extraña de hacerlo, pero a mi me funcionó.



La propiedad privada es la mayor garantía de libertad.
Friedrich August von Hayek

Desconectado migsantiago

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8257
    • Sitio de MigSantiago
Re: Problemas con la instrucion atof
« Respuesta #11 en: 29 de Mayo de 2008, 19:16:29 »
Gonzalo,

¿se podría modificar el archivo float.h para que el tipo de dato double pueda implementarse?

Desconectado Gonzalo_BlackHawk

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 519
Re: Problemas con la instrucion atof
« Respuesta #12 en: 30 de Mayo de 2008, 16:37:08 »
Hola mig, el archivo float.h solo contiene los alcances y definiciones de los numeros con coma flotante, y ya trae incluido el tipo de datos float de 48 y 64 bits (definidos como double y long double), de todas formas esto no te sirve de mucho a la hora de implementar un tipo de datos que no son los built-in de CCS. Creo que si solo vas a usar el formato para almacenar datos o bien transmitirlos por UART o guardarlos en la EEPROM se pueden crear las estructuras del tipo de datos a partir de las definiciones en float.h y generar las funciones para el almacenamiento del numero, no es mas que un trabajo orientado a manipular bytes.
Inclusive, me animo a decir que la implementaciones de casting para convertir este nuevo tipo de datos a otros estandar de CCS tampoco es una tarea imposible.

Ahora, si ya deseas realizar operaciones aritmeticas o trigonométricas con este tipo de datos la cosa se complica, pues aunque su implementacion solo sea expandir los alcance de las funciones de math.h (para citar un archivo que contenga funciones matemáticas basadas en numeros float) hay que realizar toda una maquinaria de funciones que deben ser livianas de trabajar con PICS de la gama de los 16F o 18F y que no te coman vivo a la hora de implementarlos, de lo contrario pierden su versatilidad.

Ah me olvidaba, los tipos de datos con coma flotante de 48 y 64 bits ya existen en CCS y se definen como float48 y float64 (que se diferencian del float estandar que es float32) por lo tanto son palabras reservadas del compilador, asi que en realidad no tendrias que tener problema en poder crear un programa que los utilize. Ahora bien, solo el compilador PCD (el de juego de instrucciones de 24 bits, es decir el compilador para DSPIC y PIC24) puede generar .hex con este tipo de datos por lo que al fin y al cabo no serian aplicables al ejemplo del compañero Orko. Esperemos que en futuras versiones de CCS float48 y float64 esten disponibles para los demas compiladores, pero yo en mi opinion esperaria sentado.

Un saludo.
"Siempre piensa si el jugo vale la exprimida..."

"La muerte esta tan segura de vencer que nos da toda una vida de ventaja."

Desconectado RICHI777

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1498
Re: Problemas con la instrucion atof
« Respuesta #13 en: 30 de Mayo de 2008, 17:50:11 »
Gonzalo, magistral clase de matematica de punto flotante y matematica de punto fijo !!!

Citar
¿se podría modificar el archivo float.h para que el tipo de dato double pueda implementarse?

No te sirve de nada, recordar que los H solo van declaraciones de la funciones y es para que el compilador pueda conocer de parametros y retornos, si quisieras hacer eso, tendrias que modificar el fuente donde esta la libreria "intrinsica" del compilador.

Con respecto a la implementación de punto fijo más alla de un dword o int32 se puede hacer, de hecho se hace asi, en base a arrays de bytes, depende de la aplicación es la cantidad de funciones que debes implementar, pero tal vez con las 4 operaciones basicas alcanze. La idea es mas o menos esta.
Código: [Seleccionar]
unsigned char Oper1[5];
unsigned char Oper2[5];

Esto declara un nuevo tipo de datos que en definitiva es un array de 5 bytes y extiende la precisión del int32 en un byte mas, si no consideramos el signo esto da una precision de 0 a 1.099.511.627.775 !

Normalmente una función de suma seria en C de esta manera:

Código: [Seleccionar]
bool Add( unsigned char *Operand1, unsigned char *Operand2 );

Que haria lo sgte -> Oper1 = Oper1 + Oper2

La forma de implementarla es sencilla ( lo mejor para mi en estas cosas es usar assembler plano ) es ir sumando cada byte de los dos arrays empezando desde el menos significativo ( primero con carry en 0 ) y los demas sumar con carry esto es para ir checkeando el overflow al final de la operacion. Ejemplo si sumo 0xFF 0xFF 0xFF 0xFF 0xFF + 0x01 el resultado se va de la precision del array y un overflow se produce...
Para la resta es extactamente lo mismo pero en vez de sumar, resto y lo que devuelvo al final se llama underflow...

Cuando tenga un poco mas de tiempo paso los algoritmos para multiplicar y dividir de esta manera y sin usar tanto overhead del micro, los tengo para 8051 asi que los tengo que pasar a pseudo-codigo.

Saludos !
« Última modificación: 30 de Mayo de 2008, 17:58:39 por RICHI777 »


 

anything