| View previous topic :: View next topic |
| Author |
Message |
Dom Fulton Guest
|
Posted: Tue Mar 18, 2008 4:05 pm Post subject: How do I find out what C's long double is? |
|
|
I've had a go at asking this on comp.lang.c, but I've had no luck so
far. In short, I need some way to determine what exactly a C "long
double" type actually is or, at the very least, how many bits it
contains. Any ideas?
The long version is:
I need to export floating-point data from system A to system B. To do
this, I need to know the characteristics of the data format on system
A; in particular, I need to know if it conforms to IEC60559, and which
IEC60559 type it is. I would have the same problem if I needed
to do bit manipulation of the FP data (which is what system B does).
The problem is that C (or, to be more precise, the compiler in
combination with libc) exposes 3 FP types, which may be a subset, or a
superset, or even unrelated to the FP support from the underlying
hardware. 'sizeof' gives me no useful information about the 3 exposed
types.
My best guess so far is:
1) if __STDC_IEC_559__ is not defined, then I can find out nothing
useful about the types;
2) if __STDC_IEC_559__ *is* defined then (from pp442/445 of the C99
spec):
3) 'float' must be a 32-bit IEC60559 single
4) 'double' must be a 64-bit IEC60559 double
5) 'long double' may be anything. It can be a non-IEC extended format,
an IEC double, an IEC 80-bit, or an IEC 128-bit. C appears to have no
way to tell me what this type is. I can deduce its behaviour from the
constants in float.h, but I have no guarantee that I can correctly
determine the actual long double bitsize from these constants.
Any ideas? I only have to support SunOS, Windows, and various Linuxes,
so I can hard-wire in the knowledge if necessary, but I'd rather not.
I can't find anything useful in the gcc include files. There was a
defined long double size in an older gcc version, but this seems to be
gone now.
Thanks
-Dom |
|
| |
|
Back to top |
Nick Maclaren Guest
|
Posted: Tue Mar 18, 2008 5:03 pm Post subject: Re: How do I find out what C's long double is? |
|
|
In article <dl7vt3l4bf1qsk1cbn28k0rtf3u4fmb3lv@4ax.com>,
Dom Fulton <wes104@yahoo.com> writes:
|>
|> I've had a go at asking this on comp.lang.c, but I've had no luck so
|> far. In short, I need some way to determine what exactly a C "long
|> double" type actually is or, at the very least, how many bits it
|> contains. Any ideas?
I could refer you to lots of 1970s work ... but:
Number of bits in storage unit: sizeof(double)*CHAR_BIT
Number of bits in value (assuming FLT_RADIX == 2):
1+(int)ceil(log2(DBL_MAX_EXP-DBL_MIN_EXP))+DBL_MANT_DIG
|> The long version is:
|>
|> I need to export floating-point data from system A to system B. To do
|> this, I need to know the characteristics of the data format on system
|> A; in particular, I need to know if it conforms to IEC60559, and which
|> IEC60559 type it is. I would have the same problem if I needed
|> to do bit manipulation of the FP data (which is what system B does).
You need to run a test program to check (B) the size (see above),
(B) whether it supports denormalised numbers and (C) whether it
supports infinities and NaNs. Don't trust it to do the latter.
|> The problem is that C (or, to be more precise, the compiler in
|> combination with libc) exposes 3 FP types, which may be a subset, or a
|> superset, or even unrelated to the FP support from the underlying
|> hardware. 'sizeof' gives me no useful information about the 3 exposed
|> types.
True. Join the experts' club :-)
|> My best guess so far is:
|>
|> 1) if __STDC_IEC_559__ is not defined, then I can find out nothing
|> useful about the types;
See above.
|> 2) if __STDC_IEC_559__ *is* defined then (from pp442/445 of the C99
|> spec):
|>
|> 3) 'float' must be a 32-bit IEC60559 single
|>
|> 4) 'double' must be a 64-bit IEC60559 double
Vaguely, yes, but I wouldn't trust it all that far.
|> 5) 'long double' may be anything. It can be a non-IEC extended format,
|> an IEC double, an IEC 80-bit, or an IEC 128-bit. C appears to have no
|> way to tell me what this type is. I can deduce its behaviour from the
|> constants in float.h, but I have no guarantee that I can correctly
|> determine the actual long double bitsize from these constants.
If you suspect that the constants in <float.h> are incorrect, then
you can write code to determine that - but it needs more work, of the
sort that was fairly routine in the 1970s.
Regards,
Nick Maclaren. |
|
| |
|
Back to top |
Dom Fulton Guest
|
Posted: Tue Mar 18, 2008 9:29 pm Post subject: Re: How do I find out what C's long double is? |
|
|
On 18 Mar 2008 12:03:05 GMT, nmm1@cus.cam.ac.uk (Nick Maclaren) wrote:
| Quote: | Number of bits in storage unit: sizeof(double)*CHAR_BIT
Number of bits in value (assuming FLT_RADIX == 2):
1+(int)ceil(log2(DBL_MAX_EXP-DBL_MIN_EXP))+DBL_MANT_DIG
|
Very nice; thanks (and obvious now that you've pointed it out).
There's a fly in the ointment, though, which is that it's not quite
correct. The test prog below produces this output on my
Centos4.4/x86_64:
| Quote: | FLT_MAX_EXP is 128
FLT_MIN_EXP is -125
FLT_MANT_DIG is 24
FLT bits: 33
DBL_MAX_EXP is 1024
DBL_MIN_EXP is -1021
DBL_MANT_DIG is 53
DBL bits: 65
LDBL_MAX_EXP is 16384
LDBL_MIN_EXP is -16381
LDBL_MANT_DIG is 64
LDBL bits: 80
|
After some digging about, it seems that x_MANT_DIG is the logical
number of mantissa digits, including the missing MS significand bit,
so it should be (x_MANT_DIG - 1). But '80' is correct on my box, the
reason being that the x86 double extended format apparently has an
explicit MS significand bit (although I suspect that the silicon may
actually only be 79 bits?)
After a (very cursory) look at the C99 spec there doesn't seem to be a
way to find out whether the MS significand bit is implicit or
explicit, so I guess I'll have to live with this.
Any thoughts?
Thanks
-Dom
----------------------------
#include <stdio.h>
#include <float.h>
#include <math.h>
int main(void) {
printf("FLT_MAX_EXP is %d\n", FLT_MAX_EXP);
printf("FLT_MIN_EXP is %d\n", FLT_MIN_EXP);
printf("FLT_MANT_DIG is %d\n", FLT_MANT_DIG);
printf(
"FLT bits: %d\n",
1+(int)ceil(log2(FLT_MAX_EXP-FLT_MIN_EXP))+FLT_MANT_DIG);
printf("DBL_MAX_EXP is %d\n", DBL_MAX_EXP);
printf("DBL_MIN_EXP is %d\n", DBL_MIN_EXP);
printf("DBL_MANT_DIG is %d\n", DBL_MANT_DIG);
printf(
"DBL bits: %d\n",
1+(int)ceil(log2(DBL_MAX_EXP-DBL_MIN_EXP))+DBL_MANT_DIG);
printf("LDBL_MAX_EXP is %d\n", LDBL_MAX_EXP);
printf("LDBL_MIN_EXP is %d\n", LDBL_MIN_EXP);
printf("LDBL_MANT_DIG is %d\n", LDBL_MANT_DIG);
printf(
"LDBL bits: %d\n",
1+(int)ceil(log2(LDBL_MAX_EXP-LDBL_MIN_EXP))+LDBL_MANT_DIG);
return 0;
} |
|
| |
|
Back to top |
Terje Mathisen Guest
|
Posted: Tue Mar 18, 2008 9:55 pm Post subject: Re: How do I find out what C's long double is? |
|
|
Dom Fulton wrote:
| Quote: | On 18 Mar 2008 12:03:05 GMT, nmm1@cus.cam.ac.uk (Nick Maclaren) wrote:
Number of bits in storage unit: sizeof(double)*CHAR_BIT
Number of bits in value (assuming FLT_RADIX == 2):
1+(int)ceil(log2(DBL_MAX_EXP-DBL_MIN_EXP))+DBL_MANT_DIG
Very nice; thanks (and obvious now that you've pointed it out).
[snip] |
| Quote: | After some digging about, it seems that x_MANT_DIG is the logical
number of mantissa digits, including the missing MS significand bit,
so it should be (x_MANT_DIG - 1). But '80' is correct on my box, the
reason being that the x86 double extended format apparently has an
explicit MS significand bit (although I suspect that the silicon may
actually only be 79 bits?)
After a (very cursory) look at the C99 spec there doesn't seem to be a
way to find out whether the MS significand bit is implicit or
explicit, so I guess I'll have to live with this.
Any thoughts?
|
I'm guessing the only way to determine if the leading bit exist or not
is by checking out what happens when you start underflowing:
What happens when the exponent gets close to zero? Do you drop one extra
bit of resolution or not?
Terje
--
- <Terje.Mathisen@hda.hydro.com>
"almost all programming can be viewed as an exercise in caching" |
|
| |
|
Back to top |
Nick Maclaren Guest
|
Posted: Tue Mar 18, 2008 10:26 pm Post subject: Re: How do I find out what C's long double is? |
|
|
In article <nlpvt3l60caq99u0j05ugkgotndel6jbjb@4ax.com>,
Dom Fulton <wes104@yahoo.com> writes:
|>
|> >Number of bits in storage unit: sizeof(double)*CHAR_BIT
|> >Number of bits in value (assuming FLT_RADIX == 2):
|> > 1+(int)ceil(log2(DBL_MAX_EXP-DBL_MIN_EXP))+DBL_MANT_DIG
|>
|> Very nice; thanks (and obvious now that you've pointed it out).
|>
|> There's a fly in the ointment, though, which is that it's not quite
|> correct. ...
Yes, I should have said that I hadn't tested it - but you can't expect
testing for free :-)
|> After some digging about, it seems that x_MANT_DIG is the logical
|> number of mantissa digits, including the missing MS significand bit,
|> so it should be (x_MANT_DIG - 1). But '80' is correct on my box, the
|> reason being that the x86 double extended format apparently has an
|> explicit MS significand bit (although I suspect that the silicon may
|> actually only be 79 bits?)
A good point. I wasn't thinking about it very hard, and forgot that.
There are other such gotchas on architectures that are very different
from IEEE 754, but I omitted them for simplicity.
|> After a (very cursory) look at the C99 spec there doesn't seem to be a
|> way to find out whether the MS significand bit is implicit or
|> explicit, so I guess I'll have to live with this.
That's right. You can do it, but it's painful.
Regards,
Nick Maclaren. |
|
| |
|
Back to top |
Nick Maclaren Guest
|
Posted: Tue Mar 18, 2008 10:33 pm Post subject: Re: How do I find out what C's long double is? |
|
|
In article <COKdnV_597ibaULanZ2dnUVZ_j6dnZ2d@giganews.com>,
Terje Mathisen <terje.mathisen@hda.hydro.com> writes:
|>
|> I'm guessing the only way to determine if the leading bit exist or not
|> is by checking out what happens when you start underflowing:
|>
|> What happens when the exponent gets close to zero? Do you drop one extra
|> bit of resolution or not?
No, that won't work. Underflow handling doesn't necessarily give any
hints about whether there is a leading bit or not. That is enough to
distinguish IEEE 754 (sensu stricto) from Intel, but not generally.
It won't even distinguish IEEE 754 with no denorms (as commonly used)
from Intel.
There is no substitute for reverse engineering the format properly.
It can be done if you assume a fairly conventional power-of-two
radix representation, but gets to be a gibbering nightmare beyond
that.
Regards,
Nick Maclaren. |
|
| |
|
Back to top |
glen herrmannsfeldt Guest
|
Posted: Wed Mar 19, 2008 1:43 am Post subject: Re: How do I find out what C's long double is? |
|
|
Dom Fulton wrote:
| Quote: | After some digging about, it seems that x_MANT_DIG is the logical
number of mantissa digits, including the missing MS significand bit,
so it should be (x_MANT_DIG - 1). But '80' is correct on my box, the
reason being that the x86 double extended format apparently has an
explicit MS significand bit (although I suspect that the silicon may
actually only be 79 bits?)
|
Try loading an unnormalized value into a register and see
what happens. As far as I know, the bit exists in the register.
It does make normalization easier.
-- glen |
|
| |
|
Back to top |
glen herrmannsfeldt Guest
|
Posted: Wed Mar 19, 2008 1:47 am Post subject: Re: How do I find out what C's long double is? |
|
|
Dom Fulton wrote:
| Quote: | I've had a go at asking this on comp.lang.c, but I've had no luck so
far. In short, I need some way to determine what exactly a C "long
double" type actually is or, at the very least, how many bits it
contains. Any ideas?
(snip) |
| Quote: | Any ideas? I only have to support SunOS, Windows, and various Linuxes,
so I can hard-wire in the knowledge if necessary, but I'd rather not.
I can't find anything useful in the gcc include files. There was a
defined long double size in an older gcc version, but this seems to be
gone now.
|
As long as you only need IEEE types I suppose it might work.
Look at VAX floating point (F, D, G, and H-float) for cases where
your tests would fail. Also, hex-float and now decimal-float
on IBM mainframes. Are you considering different endianness?
-- glen |
|
| |
|
Back to top |
Nick Maclaren Guest
|
Posted: Wed Mar 19, 2008 1:52 am Post subject: Re: How do I find out what C's long double is? |
|
|
In article <556dncn2nJentH3anZ2dnUVZ_siknZ2d@comcast.com>,
glen herrmannsfeldt <gah@ugcs.caltech.edu> writes:
|>
|> As long as you only need IEEE types I suppose it might work.
|>
|> Look at VAX floating point (F, D, G, and H-float) for cases where
|> your tests would fail. Also, hex-float and now decimal-float
|> on IBM mainframes. Are you considering different endianness?
Not to say lots of older formats (now all obsolete, except in some
embedded devices?), TWO different formats of decimal floating-point
specified in IEEE 754R (one the same as on IBM mainframes, and one
supposed to be forthcoming on Intel chips) , and whatever lunacies
occur between now and the end of life of the program ....
Regards,
Nick Maclaren. |
|
| |
|
Back to top |
Michel Hack Guest
|
Posted: Mon Mar 24, 2008 9:05 pm Post subject: Re: How do I find out what C's long double is? |
|
|
On Mar 18, 7:05 am, Dom Fulton <wes...@yahoo.com> wrote:
| Quote: | I've had a go at asking this on comp.lang.c, but I've had no luck so
far. In short, I need some way to determine what exactly a C "long
double" type actually is or, at the very least, how many bits it
contains. Any ideas?
|
Run-time or compile-time? The latter is difficult, especially if you
can't believe standard
header files. At run-time, you can use a union type to look at the
raw bits. Then you can
test various literal values and look at the bit patterns. Initilaise
the overlay with a raw
pattern too to detect the actual length of the part changed by
floating-point assignment.
This method will permit you to identify any type you already know,
e.g. IEEE 754, Intel
x87 80-bit format, PowerPC sum-of-doubles, IBM Hex, the four VAX
formats, the
Cray formats, etc. -- limited only by the range of machinery on which
you expect this
program to run. It's an interesting puzzle to see how far you can
get with how few
test values!
It helps if your compiler supports C99-style hexadecimal literals for
floating-point, as
otherwise you are at the mercy of your run-time's conversion
routines. You can however
construct test values starting from unproblematic literals like small
integers and exact
arithmetic operations, starting from an assumption of low precision,
and working up
to higher precisions and exponent range.
Guy Steele once wrote a floating-point conversion program in plain C
that ran on nearly
any hardware, and must have performed some of the kind of tests I
mentioned above.
Michel. |
|
| |
|
Back to top |
Nick Maclaren Guest
|
Posted: Tue Mar 25, 2008 2:26 am Post subject: Re: How do I find out what C's long double is? |
|
|
In article <9a46019b-25dc-4b7f-b732-340f51b57ae0@n58g2000hsf.googlegroups.com>,
Michel Hack <hack@watson.ibm.com> writes:
|>
|> Guy Steele once wrote a floating-point conversion program in plain C
|> that ran on nearly any hardware, and must have performed some of the
|> kind of tests I mentioned above.
There were older ones in Fortran that did the same, plus code that
actually analysed the arithmetic, and ran on an even wider range of
hardware. They were NOT pretty! The two killers are the following
(in any language):
You can only analyse and/or handle aberrant behaviours that you
expect. The CDC 6600 and 7600 caught out a lot of otherwise highly
portable programs, for example. Even Intel is tricky if compilers
sometimes use SSE and sometimes don't.
You can't detect the exception boundaries, because you are into
undefined behaviour as soon as you hit them (i.e. unpredictable
nonsense, crashes etc.) I have some C code that attempts to, but
it failed on the Alpha, most vector systems, and so on.
Regards,
Nick Maclaren. |
|
| |
|
Back to top |
|