Mail Archives: djgpp-workers/2002/11/26/16:07:53
Please look at the following code snippet:
#include <stdio.h>
int main(void)
{
long double a=1.0e309;
struct IEEExp {
unsigned manl:32;
unsigned manh:32;
unsigned exp :15;
unsigned sign:1;
} ip = *(struct IEEExp *)&a;
printf("a=%Lg\n",a);
return 0;
}
As can be seen, the variable long double a is initialised with a value greater
than DBL_MAX=1.79769e+308.
AFAIK, the variable a should be able to store values equal or smaller than
LDBL_MAX=1.18973e+4932. If the above program is started the output generated
will be:
a=Inf
IMHO, that is wrong. 1.0e309 <<< 1.18973e+4932.
I have generated assembler code for the above snippet. It looks
like:
.file "a.c"
.section .text
LC0:
.ascii "a=%Lg\12\0"
.p2align 1
.globl _main
_main:
push ebp
mov ebp, esp
sub esp, 40
and esp, -16
mov eax, 0
sub esp, eax // Initialising variable long double a:
mov DWORD PTR [ebp-24], 0 // mantissa low (32 bit): 0x00000000
mov DWORD PTR [ebp-20], -2147483648 // mantissa high (32 bit): 0x80000000
mov DWORD PTR [ebp-16], 32767 // sign: 0x0 and biased exponent (15 bit): 0x7FFF
mov eax, DWORD PTR [ebp-24]
mov DWORD PTR [ebp-40], eax
mov eax, DWORD PTR [ebp-20]
mov DWORD PTR [ebp-36], eax
mov eax, DWORD PTR [ebp-16]
mov DWORD PTR [ebp-32], eax
push DWORD PTR [ebp-16]
push DWORD PTR [ebp-20]
push DWORD PTR [ebp-24]
push OFFSET FLAT:LC0
call _printf
add esp, 16
mov eax, 0
leave
ret
.ident "GCC: (GNU) 3.2"
Of course, we are dealing with intel's 80-bit extended double format.
Mantissa high and low result in 64-bit mantissa: 0x8000000000000000 == 1.0(decimal). That is ok.
But exponent minus bias gives: 0x7FFF - 0x3FFF = 0x4000 == 16384(decimal) != 1026(decimal)
as it should be. Please note: 10^309 == 2^1026 and 10^4932 == 2^16384.
It seems to be that a value assignement greater than DBL_MAX to a long double variable
produces an "exponent overflow" generating an infinity. All this only happens if the
exponent is greater than 308. Something similar can be observed for small exponents.
As soon as the exponent becomes smaller than -308 it value jumps to -4932 implying
that the value of a long double variable becomes zero no matter what exponent value is taken
from the range [-308, -4932]. In conclusion long double seems to behave like double.
The above data can also be observed if the code is compiled and inspected with gdb.
An inspection of the IEEExp bit field with gdb shows the same data than the one shown
in the assembler code.
I have noticed this while I was implementing hex float support (new conversion type specifier 'a'
and 'A') to _doprnt() as imposed by C99.
Am I missing something?
Can someone explain to my, why long double variables are not initialised as I would expect
or what am I doing wrong?
I am using gcc 3.2, binutils 2.13 and CVS libc (2002-11-25).
TIA,
Guerrero, Juan Manuel
- Raw text -