delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2002/11/26/16:07:53

From: "Juan Manuel Guerrero" <ST001906 AT HRZ1 DOT HRZ DOT TU-Darmstadt DOT De>
Organization: Darmstadt University of Technology
To: djgpp-workers AT delorie DOT com
Date: Tue, 26 Nov 2002 21:42:29 +0100
Subject: Difficulty with long double
X-mailer: Pegasus Mail for Windows (v2.54DE)
Message-ID: <1FCB82C4018@HRZ1.hrz.tu-darmstadt.de>
X-MailScanner: Found to be clean
Reply-To: djgpp-workers AT delorie DOT com

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 -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019