Autor Tema: Posibles "bugs" del compilador de CCS  (Leído 252516 veces)

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

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Posibles "bugs" del compilador de CCS
« Respuesta #45 en: 08 de Diciembre de 2009, 00:01:57 »
Tal vez me fumé mucho ya, pero juro que o he enloquecido, o encontré un bug bastante groso.

Encontrado en varias versiones. Actualmente uso la 4.088.

Un error en la función pow(x,y) de la librería math.h:

Hacer esto:

Código: C
  1. float32 out;
  2.    out=pow(-2.0,2.0);
  3.    printf("El resultado es: %f",out);
arroja como resultado: -4.00

No he tenido tiempo de analizar la solución, pero el problema es claramente visible en la librería math.h:

Código: C
  1. //////////////////// Power functions ////////////////////
  2.  
  3. ////////////////////////////////////////////////////////////////////////////
  4. //   float pow(float x,float y)
  5. ////////////////////////////////////////////////////////////////////////////
  6. // Description : returns the value (x^y)
  7. // Date : N/A
  8. //
  9. float32 pow(float32 x,float32 y)
  10. {
  11.    if(x>=0)
  12.      return(  exp(y*log(x)) );
  13.    else
  14.      return(  -exp(y*log(-x)) );
  15. }

 Si analizamos la condicion del IF tenemos que
      si x<0 entonces,
      return(  -(exp(y*log(-x))) );
pero como x<0, entonces hacer eso es lo mismo que hacer:
      return(  -exp(y*log(x)) );

     porque como x era menor a cero, los signos negativos se cancelan quedando x positiva...
 
si nos fijamos, en realidad lo obtenido no es mas que el resultado para x>=0 pero con distinto signo final.

Entonces, podriamos simplificar diciendo que la funcion hace esto:

Sea Q(x,y)=exp(y*log(x) ) una funcion que devolvera supuestamente el valor absoluto1 de la funcion pow

si x>=0 entonces
      devuelve Q(x,y)
sino
      devuelve -Q(x,y)

Vamos a ver en detalle el error ahora que se ha simplificado el algoritmo a sólo un cambio de signo según el signo de x.

para x=-2 e y=2

por ser x<0, entonces devolverá -Q(x,y). Asumiendo que Q(x,y) no tiene bugs y devuelve el valor absoluto1 correctamente, nos quedaría que Q(x,y) da 4.
Ahora, al aplicarle el signo menos, tenemos el terrible bug, quedando finalmente como resultado -4.

Analizando un poco más el algoritmo, observamos que el error sólo se produce cuando la base es negativa y el exponente, par.

Es evidente que el algoritmo falla, porque sólo considera el signo de la base, pero no tiene en cuenta si el exponente es par o impar. No analice el caso de exponentes fraccionales.

¿Qué les parece?

Aclaraciones:
1Podemos asegurar que Q(x,Y) devuelve siempre un valor mayor o igual a 0, porque si la analizamos:

Q(x,y) = exp(y*log(x) )

podríamos hacer una función compuesta, quedando:

Q(x,y) = exp(P(x,y))

donde P(x,y) = y*log(x)

Ahora, siendo que la funcion exp es e^x, y recordando que e es un número positivo, sabemos que no hay manera que e^P(x,y) de un resultado negativo.
Analizandolo si se necesita, tenemos que:
si P(x,y)>0, entonces el resultado será mayor a 0;
si P(x,y)=0, entonces el resultado será 1;
si P(x,y)<0, entonces el resultado será también mayor a 0; ya que e^(-P(x,y)) = 1/(e^P(x,y)) que es siempre positivo.

Queda demostrado entonces que Q(x,y)=exp(y*log(x) ) es siempre positivo,por lo que podríamos decir que devuelve el valor absoluto del resultado.
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18310
    • MicroPIC
Re: Posibles "bugs" del compilador de CCS
« Respuesta #46 en: 08 de Diciembre de 2009, 02:46:01 »
Parece evidente que es un fallo.
Yo he tenido que eliminar todos los cálculos en float de un proyecto en el que estoy trabajando porque hacía cosas raras: a veces se colgaba, otras los servos empezaban a vibrar porque los timers no iban finos, etc...
Me costó encontrar el problema, pero desde que eliminé los float todo ha ido como la seda.

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Posibles "bugs" del compilador de CCS
« Respuesta #47 en: 08 de Diciembre de 2009, 04:21:48 »
Que lástima. Lo que pasa es que yo no puedo eliminar los floats ya que los utilizo para todos los cálculos. :(

Me detuve ahora un ratito a ver por qué calculaba así la potenciación, y la respuesta salió rápidamente:

Hay una entidad de los logaritmos que dice que:

     y
ln(x ) =y*ln(x)

Entonces, puedo elevar "e" a cada lado de la ecuación , y la igualdad debería mantenerse...
          y    
    (ln(x )     (y*ln(x))
e^        =e^
                                     ln(f(x))
y ahora, sabiendo que e^            = f(x) nos queda que:

 y              (y*ln(x))
x         =e^                 = Q(x,y) = exp(y*log(x))  que es la que la librería usa.

Lo anterior está bien,PERO el dominio del lado derecho es siempre que X>0. Si x<=0, el logaritmo neperiano no exíste...Y acá está el problema del algoritmo.

Perdón por no usar LATEX pero me está metiendo un símbolo raro que no debería...:(

Ahora estoy estudiando cómo solucionar el algoritmo.
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Posibles "bugs" del compilador de CCS
« Respuesta #48 en: 08 de Diciembre de 2009, 07:31:20 »
Bueno. He solucionado parcialmente el asunto.

Con parcial me refiero a que la funcion no acepta exponentes fraccionarios.

Entre a analizar en profundidad, y el problema es bastante amplio y difícil de solucionar algorítmicamente. He descubierto cosas asombrosas.

Como por ejemplo, que la calculadora de Windows tampoco podía resolver algo tan sencillo como (-8)^(1/3).

Si recuerdan algo de análisis, recordarán que eso es lo mísmo que raíz cúbica de -8, lo cual facilmente nos da -2.

Programas profesionales de calculo matemático tampoco pudieron resolverlo. El Derive tuvo que recurrir a números complejos para resolver el ejemplo anterior.

Por ahora, y por siempre seguramente, me conformo con corregir la función para exponentes enteros.

Código: C
  1. float32 pow(float32 x,float32 y)
  2. {
  3.    if(x>=0)
  4.      return(  exp(y*log(x)) );
  5.    else
  6.       if((int32)y%2){
  7.          return(  -exp(y*log(-x)) );
  8.       }else{
  9.          return(   exp(y*log(-x)) );
  10.       }
  11. }

A modificar la math.h... :D

"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado PalitroqueZ

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5490
    • Electrónica Didacta
Re: Posibles "bugs" del compilador de CCS
« Respuesta #49 en: 08 de Diciembre de 2009, 09:36:19 »
Bruno, y se supone que el C nos facilita la vida  :D

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

Desconectado Suky

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: Posibles "bugs" del compilador de CCS
« Respuesta #50 en: 08 de Diciembre de 2009, 11:52:19 »
Lo que pasa que la raíz de un numero negativo siempre va a tener resultados imaginarios, por ejemplo -81/3 tiene -2, 1 - 1.73i y 1 + 1.73i. Y si la calculadora no trabaja con números imaginarios no lo va a resolver  :mrgreen:

Después miren lo que dice la versión 4.093 de la función Pow:
Citar
Calculates X to the Y power.

 

Note on error handling:

If "errno.h" is included then the domain and range errors are stored in the errno variable. The user can check the errno to see if an error has occurred and print the error using the perror function.

 

Range error occurs in the following case:

·   pow: when the argument X is negative


Saludos!
No contesto mensajes privados, las consultas en el foro

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Posibles "bugs" del compilador de CCS
« Respuesta #51 en: 08 de Diciembre de 2009, 18:48:07 »
Bruno, y se supone que el C nos facilita la vida  :D

Ja ja! Pero qué cosa,eh! Uno renegando hasta con lo más "fácil".

Lo que pasa que la raíz de un numero negativo siempre va a tener resultados imaginarios, por ejemplo -81/3 tiene -2, 1 - 1.73i y 1 + 1.73i. Y si la calculadora no trabaja con números imaginarios no lo va a resolver  :mrgreen:

Muchísimas funciones tienen resultados tanto en los reales y en los complejos...

Está bien, pero si vos tenés un resultado dentro del dominio de los Reales, entonces deberías poder encontrarlo si realmente te haces llamar "calculadora". Yo no digo que está mal que la calculadora de Windows no arroje los resultados imaginarios. Digo que está mal que no arroje el -2 como resultado posible siendo que está dentro del dominio que supuestamente maneja. Lo mísmo para el Derive.
Obviamente que el impedimento debe estar en que para poder llegar al -2, las formulas utilizadas deben tener que usar números complejos para ello.

Después miren lo que dice la versión 4.093 de la función Pow:
Citar
Calculates X to the Y power.

 

Note on error handling:

If "errno.h" is included then the domain and range errors are stored in the errno variable. The user can check the errno to see if an error has occurred and print the error using the perror function.

 

Range error occurs in the following case:

·   pow: when the argument X is negative


Saludos!

Interesante eso! Entonces supuestamente no soportaba bases negativas! Jaaaa! Pero no era tan dificil aceptarlas,eh? :S
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado Suky

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: Posibles "bugs" del compilador de CCS
« Respuesta #52 en: 08 de Diciembre de 2009, 20:06:32 »
Lo que pasa que la raíz de un numero negativo siempre va a tener resultados imaginarios, por ejemplo -81/3 tiene -2, 1 - 1.73i y 1 + 1.73i. Y si la calculadora no trabaja con números imaginarios no lo va a resolver  :mrgreen:

Muchísimas funciones tienen resultados tanto en los reales y en los complejos...

Está bien, pero si vos tenés un resultado dentro del dominio de los Reales, entonces deberías poder encontrarlo si realmente te haces llamar "calculadora". Yo no digo que está mal que la calculadora de Windows no arroje los resultados imaginarios. Digo que está mal que no arroje el -2 como resultado posible siendo que está dentro del dominio que supuestamente maneja. Lo mísmo para el Derive.
Obviamente que el impedimento debe estar en que para poder llegar al -2, las formulas utilizadas deben tener que usar números complejos para ello.

Supongo que se implementa de esa manera para no mostrar resultados incompletos, que a los estudiantes puede llevarles a confusión  ;-)

Saludos!
No contesto mensajes privados, las consultas en el foro

Desconectado ramiroreal

  • PIC10
  • *
  • Mensajes: 8
Re: Posibles "bugs" del compilador de CCS
« Respuesta #53 en: 17 de Diciembre de 2009, 05:58:53 »
Buenas!!! Les cuento una cosa muy curiosa: Resulta que necesito utilizar de la librería math.h, el problema es que necesito trabajar con el PIC 18F4550, puesto que con todas las operaciones que utilizo logro llenar la RAM del PIC 19F877A (segun el CSS). La historia viene cuando calculo el seno, con el 16F877A obtengo 0.841471, lo que viene siendo un resultado correcto  :), pero a la hora de trabajar con el 4550, obtengo 3 resultados distintos!! vamos que el seno es variable: 0.250971 , 0.500011 y 0.500008.

Les cuento que todo lo estoy haciendo con las respectivas versiones del PIC Simulator Idle y ambas programaciones están hechas bajo CCS C, abajo les dejo el código para que vean que es exáctamente igual, no puede ser un error en la MATH.H puesto que utilizo la misma en ambos proyectos.
Voy a probar ésto con un entrenador (el PIC SCHOOL) para salir definitivamente de dudas.
Les cuento mis resultados, saludos.


18F4550
Código: [Seleccionar]
#include "C:\Users\USUARIO22\Desktop\Brujula - Tarjeta nueva\18F4550,solo sin\prueba.h"
#include "C:\Users\USUARIO22\Desktop\Brujula - Tarjeta nueva\18F4550,solo sin\lcd.c"
#include "C:\Users\USUARIO22\Desktop\Brujula - Tarjeta nueva\18F4550,solo sin\math.h"


void main()

{
   double res;
   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_spi(FALSE);
   setup_wdt(WDT_OFF);
   setup_timer_0(RTCC_INTERNAL);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   setup_oscillator(False);

   // TODO: USER CODE!!
   lcd_init();
   delay_ms(10);
   while(1)
  
   {
   delay_ms(5);
   res=sin(1);
   printf(lcd_putc "\f %4f",res);
   }
}

16F877A
Código: [Seleccionar]
#include "C:\Users\USUARIO22\Desktop\Brujula - Tarjeta nueva\16f877a\16f877a.h"
#include "C:\Users\USUARIO22\Desktop\Brujula - Tarjeta nueva\16f877a\lcd.c"
#include "C:\Users\USUARIO22\Desktop\Brujula - Tarjeta nueva\16f877a\math.h"


void main()
{
   double res;

   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_spi(FALSE);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
  
  

   // TODO: USER CODE!!
   lcd_init();
   delay_ms(10);
   while(1)
  
   {
   delay_ms(5);
   res=sin(1);
   printf(lcd_putc "\f %4f",res);
   }

}
« Última modificación: 17 de Diciembre de 2009, 12:52:26 por un Moderador »

Desconectado migsantiago

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8257
    • Sitio de MigSantiago
Re: Posibles "bugs" del compilador de CCS
« Respuesta #54 en: 17 de Diciembre de 2009, 12:50:38 »
Hola Ramiroreal, no creo que sea buena idea usar una variable declarada como double ya que CCS no la implementa con 8 bytes de precisión, hasta donde recuerdo la implementa como un float de 4 bytes. Además en la ayuda de CCS se comenta que solo es una palabra reservada...

double
 Is a reserved word but is not a supported data type.

Desconectado ramiroreal

  • PIC10
  • *
  • Mensajes: 8
Re: Posibles "bugs" del compilador de CCS
« Respuesta #55 en: 18 de Diciembre de 2009, 07:43:23 »
Buenas!!! gracias por contestar, resulta que mi predicción fué correcta, con un entrenador funciona a la perfección, de todas formas estoy usando la variable float.
Saludos.

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Optimización a rutina de escritura en EEPROM externa 24LCxxx y otras
« Respuesta #56 en: 01 de Enero de 2010, 17:08:47 »
Bueno, estoy usando la versión 4.088 del CCS, y siempre he usado las librerías standard para leer/escribir en una EEPROM externa.

Ahora, optimizando mis algoritmos de lectura/escritura para el sistema de archivos que estoy desarrollando para los PICs, me di cuenta de que podían mejorarse.

Pre-conceptos utilizados:
* Una memoria 24LCxxx tarda según el datasheet aproximadamente 5mS en escribir un byte;
* La memoria no responde a los comandos durante el proceso de escritura(no hay ACK);

Si miran las rutina de escritura, verán que el proceso de escritura se realiza siguiendo el siguiente orden:

1)Escribir en la EEPROM;
2)Esperar hasta que la memoria responda(aprox. 5ms);

El código:
Código: C
  1. void write_ext_eeprom(long int address, BYTE data)
  2. {
  3.    short int status;
  4.    i2c_start();
  5.    i2c_write(0xa0);
  6.    i2c_write(address>>8);
  7.    i2c_write(address);
  8.    i2c_write(data);
  9.    i2c_stop();
  10.    i2c_start();
  11.    status=i2c_write(0xa0);
  12.    while(status==1)
  13.    {
  14.    i2c_start();
  15.    status=i2c_write(0xa0);
  16.    }
  17.    i2c_stop();
  18. }

Algo completamente factible, pero no óptimo. Aprovechando que tanto la escritura como la lectura, comienzan enviando los mísmos comandos(y es aquí donde la memoria también responde(o no) si es que está en pleno proceso de escritura previo) se me ocurrió optimizarlo, haciendo:

Código: C
  1. void write_ext_eeprom(long int address, BYTE data)
  2. {
  3.    short int status;
  4.  
  5.    do{
  6.       i2c_start();
  7.       status=i2c_write(0xa0);      
  8.    }while(status==1);
  9.  
  10.    i2c_write(address>>8);
  11.    i2c_write(address);
  12.    i2c_write(data);
  13.    i2c_stop();
  14. }

Entonces, el orden ahora resulta en:
1) Verificar si se estaba grabando algo, esperar de ser necesario;
2) Grabar el dato(sin esperar a que finalice);

¿Dónde está la ganancia?
Bueno, primero: el código resultante es más corto.
Segundo: Esos 5mS que la rutina original se queda esperando, ustedes pueden aprovecharlos para ejecutar otros procesos con el PIC sin necesidad de esperar a la memoria...

Por otro lado, si optan por cambiar esta rutina, también deberán cambiar la de lectura, quedando:

Código: C
  1. BYTE read_ext_eeprom(long int address) {
  2.    BYTE data;
  3.    short int status;
  4.  
  5.    do{                           //wait if previous writing...
  6.       i2c_start();
  7.       status=i2c_write(0xa0);      
  8.    }while(status);
  9.    
  10.    i2c_write(address>>8);
  11.    i2c_write(address);
  12.    i2c_start();
  13.    i2c_write(0xa1);
  14.    data=i2c_read(0);
  15.    i2c_stop();
  16.    return(data);
  17. }

Porque la lectura, ahora, también debe contemplar el caso en que haya quedado una escritura previa, en la cual deberá esperar a que finalice antes de poder leer el byte solicitado.

En un caso práctico,si hacemos:

write_ext_eeprom(0x0000,0x88);
delay_ms(10);
write_ext_eeprom(0x0001,0xAA);
delay_ms(10);

con las rutinas originales, debería demorar en ejecutarse(aprox.): 5mS+10mS+5mS+10mS=30mS.

Con las rutinas que propongo, el mísmo código deberia demorar en ejecutarse(aprox.): 10mS+10mS=20mS.

Conclusión:
En el peor de los casos, el nuevo código tardará, a lo sumo, como el original que trae el compilador.
En el mejor de los casos, la escritura será prácticamente gratuita en cuanto a gasto de tiempo se refiere.(siempre y cuando entre escrituras, el uC aproveche los 5mS posterior a cada escritura haciendo otra cosa ajena a la memoria).

No es un bug, pero creo que puede servirle a varios. A mi me ha ahorrado mucho tiempo.

Saludos.
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado AKENAFAB

  • Colaborador
  • DsPIC30
  • *****
  • Mensajes: 3227
Re: Posibles "bugs" del compilador de CCS
« Respuesta #57 en: 01 de Enero de 2010, 17:43:14 »
Tambien para ahorrar tiempo y en caso de que sean varios bytes , se puede escribir por pagina,lo mismo la lectura.

Esto lo conoci XD al trabajar con las imagenes para la GLCD que guardo en las eeprom, el tiempo se reduce muchisimo.

Saludos!


Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Posibles "bugs" del compilador de CCS
« Respuesta #58 en: 01 de Enero de 2010, 17:47:07 »
Claro que si!

Siempre hay que mirar los datasheets.

Las librerías que trae el CCS suelen ser muy básicas.
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18310
    • MicroPIC
Re: Posibles "bugs" del compilador de CCS
« Respuesta #59 en: 02 de Enero de 2010, 03:15:09 »
Muy interesante optimización. Gracias don Bruno