Ver Mensaje Individual
  #10 (permalink)  
Antiguo 21/02/2013, 05:03
Fw190
 
Fecha de Ingreso: junio-2010
Ubicación: Madrid
Mensajes: 620
Antigüedad: 14 años, 5 meses
Puntos: 73
Respuesta: Números Subnormales en C (estándar C99 y GCC 4.7)

Tenías razón con lo del flag -std=c99 y con fpclassify(), ejecuta este programilla y verás qué curioso lo que ocurre con la constante:

Código C:
Ver original
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <float.h>
  4. #include <math.h>
  5.  
  6. typedef struct
  7. {
  8.     unsigned    mnt : 23;   // Mantisa
  9.     unsigned    exp : 8;    // Exponente
  10.     unsigned    sgn : 1;    // Signo
  11. }
  12. Tflt;
  13.  
  14. typedef union
  15. {
  16.     int     intVal;
  17.     float   fltVal;
  18.     Tflt    bitVal;
  19. }
  20. Tval;
  21.  
  22. int main()
  23. {
  24.     Tval    x;
  25.  
  26.     printf("Sizeof(1.1F) = %d\n", sizeof(1.1F));
  27.     x.fltVal = 1.1F;
  28.     printf("X (FltHex)       = %a\n", x.fltVal);
  29.     printf("Cte (FltHex)     = %a\n", 1.1F);
  30.     printf("Cte (CastFltHex) = %a\n", (float)1.1F);
  31.     printf("Cte (DblHex)     = %a\n", 1.1);
  32.     printf("Cte (LDblHex)    = %La\n", 1.1L);
  33.     printf("X == 1.1F  ?? %s\n", (x.fltVal == 1.1F)? "SI":"NO");
  34.     printf("X == (float)1.1  ?? %s\n", (x.fltVal == (float)1.1F)? "SI":"NO");
  35.     printf("\n");
  36.     printf("X (flt) = %+f\n", x.fltVal);
  37.     printf("X (hex) = 0x%08X\n", x.intVal);
  38.     printf("X (sgn) = %u\n", x.bitVal.sgn);
  39.     printf("X (exp) = %u\n", x.bitVal.exp);
  40.     printf("X (mnt) = %06X\n", x.bitVal.mnt);
  41.     printf("X (fl2) = %a\n", x.fltVal);
  42.     printf("\n");
  43.     printf("Float   : FPCLASSIFY: %04X\n", fpclassify(FLT_MIN / (float)4.0));
  44.     printf("Double  : FPCLASSIFY: %04X\n", fpclassify(DBL_MIN / 4.0));
  45.     printf("LDouble : FPCLASSIFY: %04X\n", fpclassify(LDBL_MIN / 4.0L));
  46.     printf("\n");
  47.     printf("Float  : %e             FPCLASSIFY: %04X\n", FLT_MIN,  fpclassify(FLT_MIN / (float)4.0));
  48.     printf("Double : %e             FPCLASSIFY: %04X\n", DBL_MIN,  fpclassify(DBL_MIN / 4.0));
  49.     printf("LDouble con %%e  : %e   FPCLASSIFY: %04X\n", LDBL_MIN, fpclassify(LDBL_MIN / 4.0L));
  50.     printf("LDouble con %%Le : %Le   FPCLASSIFY: %04X\n", LDBL_MIN, fpclassify(LDBL_MIN / 4.0L));
  51.  
  52.     return 0;
  53. }

Como puedes ver, si le pido el tamaño de 1.1F me dice que 4 bytes, pero si le pido que me la imprima en hexadecimal lo hace como si tuviera 8 bytes, con lo que la comparación da negativo (pasando del sufijo). En cambio, casteando la constante la comparación da positivo.

Sobre fpclassify(), en la primera serie de printf me muestra 0x400 para float y double (que corresponde a FP_NORMAL) y 0x4400 para long double, que corresponde a FP_SUBNORMAL (que está definido como FP_NORMAL | FP_ZERO). Hasta aquí todo bien, pero fíjate qué curioso lo que sale en la segunda serie (imprimiendo previamente el valor mínimo para cada tipo), en el tercer printf.

Resumiendo:
Antes de meterse en palabras mayores con cálculos en coma flotante, habrá que hacer algunas minipruebas de este tipo para ver de qué pié cojea el compilador, independientemente del compilador, del estándar al que se adscriba, del sistema operativo y del procesador que se utilice.

Saludos,