Number of bits in C99 float types?

D

Dom Fulton

Has anyone got a mechanism for finding the number of bits in floats,
doubles, and long doubles? I need this to communicate with some
hardware.

I guess I could try to deduce this from float.h, but that looks
difficult.

I don't mind something which is system-specific; the older gccs had
various defines in cpu_limits.h and related files, but I can't find
anything in later gccs.

Thanks -

Dom
 
H

Harald van Dijk

Has anyone got a mechanism for finding the number of bits in floats,
doubles, and long doubles? I need this to communicate with some
hardware.

I guess I could try to deduce this from float.h, but that looks
difficult.

I don't mind something which is system-specific; the older gccs had
various defines in cpu_limits.h and related files, but I can't find
anything in later gccs.

If you're already looking for something system-specific, why can't you
simply put the number of bits as a constant in your code? What do you
want to do with the number of bits, that it's useful at all to be able to
deal with different numbers?

That said, every object consists of sizeof(object) * CHAR_BIT bits. Some
of those bits may not be useful in determining the value, depending on
the system and compiler. Most likely, on your system, this will work just
fine for floating point types.
 
I

Ian Collins

Dom said:
Has anyone got a mechanism for finding the number of bits in floats,
doubles, and long doubles? I need this to communicate with some
hardware.
Your compiler or platform documentation should provide this information.

You can use sizeof() to programmatically determine the sizes.
 
D

Dom Fulton

I've got to support several different systems - Windows, SunOS, and
various Linuxes. I guess I could just find out what the answer is for
the various platforms, and hard-code it in, but that gives me a bad
feeling...

sizeof doesn't work; it's rounded up for alignment reasons. On most
systems, float/double/long double will be 32/64/80 bits, but sizeof
generally returns 96 or 128 for 80-bit floats.

Thanks -

Dom
 
J

jacob navia

Dom said:
I've got to support several different systems - Windows, SunOS, and
various Linuxes. I guess I could just find out what the answer is for
the various platforms, and hard-code it in, but that gives me a bad
feeling...

sizeof doesn't work; it's rounded up for alignment reasons. On most
systems, float/double/long double will be 32/64/80 bits, but sizeof
generally returns 96 or 128 for 80-bit floats.

Thanks -

Dom

You will find all you need here.
http://docs.sun.com/app/docs/doc/801-7639/6i1ucu1uc?l=ru&a=view
The processor is important, not the OS/ There you will find all docs
for x86 and SPARC. The power pc is IEEE too, without any support for
long double.
 
H

Harald van Dijk

I've got to support several different systems - Windows, SunOS, and
various Linuxes. I guess I could just find out what the answer is for
the various platforms, and hard-code it in, but that gives me a bad
feeling...

Again, I don't see what exactly you're trying to do, and I'm not sure how
you can get an improvement over hard-coding, but I'll admit I don't do a
lot with floating point types, so I may well be missing it...
sizeof doesn't work; it's rounded up for alignment reasons. On most
systems, float/double/long double will be 32/64/80 bits, but sizeof
generally returns 96 or 128 for 80-bit floats.

Okay, so you really need the number of bits that contribute to the
float's value, not the number of bits that are used to store a float.

Here's an attempt: find the first power of two greater than or equal to
FLT_RADIX. Multiply it by DBL_MANT_DIG (or the appropriate constant for
your type). Add one for a sign bit. Add however many bits are required
for storing DBL_MAX_EXP-DBL_MIN_EXP+1 distinct exponents.

This assumes that the mantissa, sign bit, and exponent are all stored in
distinct bits, and that for example decimal floating point types are
stored in a BCD-like form. I don't have experience with any system where
FLT_RADIX is not equal to 2. You may need further tweaking.
 
H

Harald van Dijk

Dom said:
I've got to support several different systems - Windows, SunOS, and
various Linuxes. I guess I could just find out what the answer is for
the various platforms, and hard-code it in, but that gives me a bad
feeling...

sizeof doesn't work; it's rounded up for alignment reasons. On most
systems, float/double/long double will be 32/64/80 bits, but sizeof
generally returns 96 or 128 for 80-bit floats.
[...]
The
processor is important, not the OS/

The processor and the OS are both important. The processor determines
which floating point representations are available, and the OS (along
with the compiler, I suppose) decides how those map them to C's types.
 
E

Eric Sosman

Dom said:
I've got to support several different systems - Windows, SunOS, and
various Linuxes. I guess I could just find out what the answer is for
the various platforms, and hard-code it in, but that gives me a bad
feeling...

sizeof doesn't work; it's rounded up for alignment reasons. On most
systems, float/double/long double will be 32/64/80 bits, but sizeof
generally returns 96 or 128 for 80-bit floats.

If sizeof(long double) * CHAR_BIT == 96 on some system,
then 96 *is* the number of bits in a long double, not some
kind of "rounded up" result. If you are attaching some other
meaning to "number of bits," you need to explain what you mean.
It might be

- The number of significand bits (variation: count or
omit a "hidden" bit),

- The number of bits that participate in the value
(sign, exponent, and significand),

- Something else altogether.

It might also help if you described what you intend to
do with the answer once you have it. So far, you've said
only that you need to "communicate with some hardware," a
description that's pretty low on the specificity scale.
 
J

jacob navia

Eric said:
If sizeof(long double) * CHAR_BIT == 96 on some system,
then 96 *is* the number of bits in a long double, not some
kind of "rounded up" result.

No. In the x86 the long double is 10 bytes, but it
is rounded up into 12 (lcc-win) or even 16, just for
alignment reasons.
 
E

Eric Sosman

jacob said:
No. In the x86 the long double is 10 bytes, but it
is rounded up into 12 (lcc-win) or even 16, just for
alignment reasons.

So, I can safely store a few additional chars in the
extra bytes?

union {
long double aligner;
unsigned char buff[16];
} u;
memset (u.buff, 'x', sizeof u.buff);
*(long double*)u.buff = 42.0L;
assert (u.buff[10] == 'x');

All happy and hunky-dory, right?
 
D

Dom Fulton

Thanks for the suggestions - I'll check them out in the morning.

So, I can safely store a few additional chars in the
extra bytes?

union {
long double aligner;
unsigned char buff[16];
} u;
memset (u.buff, 'x', sizeof u.buff);
*(long double*)u.buff = 42.0L;
assert (u.buff[10] == 'x');

All happy and hunky-dory, right?

Actually, I suspect that you can. Your assertion may not actually
pass, but whatever the compiler stores in that location has nothing to
do with the bit pattern associated with '42'. Note that on x86 gcc, at
least, I can actually tell the compiler whether sizeof should return
96 or 128 bits; it's just an ABI alignment issue.

There's also some interesting stuff going on in Valgrind. It knows
that the float is 80 bits, and complains about C code which assumes
that it's 128 bits; it says the top bits are uninitialised.

-Dom
 
J

jacob navia

Eric said:
jacob said:
No. In the x86 the long double is 10 bytes, but it
is rounded up into 12 (lcc-win) or even 16, just for
alignment reasons.

So, I can safely store a few additional chars in the
extra bytes?

union {
long double aligner;
unsigned char buff[16];
} u;
memset (u.buff, 'x', sizeof u.buff);
*(long double*)u.buff = 42.0L;
assert (u.buff[10] == 'x');

All happy and hunky-dory, right?

??? What do you want to prove?

That long doubles are NOT 10 bytes?

Or what?

I do not see the point.
 
S

santosh

jacob said:
Eric said:
jacob said:
Eric Sosman wrote:
Dom Fulton wrote:
I've got to support several different systems - Windows, SunOS,
and various Linuxes. I guess I could just find out what the answer
is for the various platforms, and hard-code it in, but that gives
me a bad feeling...

sizeof doesn't work; it's rounded up for alignment reasons. On
most systems, float/double/long double will be 32/64/80 bits, but
sizeof generally returns 96 or 128 for 80-bit floats.

If sizeof(long double) * CHAR_BIT == 96 on some system,
then 96 *is* the number of bits in a long double, not some
kind of "rounded up" result.

No. In the x86 the long double is 10 bytes, but it
is rounded up into 12 (lcc-win) or even 16, just for
alignment reasons.

So, I can safely store a few additional chars in the
extra bytes?

union {
long double aligner;
unsigned char buff[16];
} u;
memset (u.buff, 'x', sizeof u.buff);
*(long double*)u.buff = 42.0L;
assert (u.buff[10] == 'x');

All happy and hunky-dory, right?

??? What do you want to prove?

That long doubles are NOT 10 bytes?

Or what?

I do not see the point.

He is saying that the "size" of an object within a C program is the size
that sizeof returns for it, or the size that you defined. What goes on
underneath is not something that a portable C program can know or take
advantage of. The standard doesn't guarantee anything about writing to
bits set aside for padding, even if you can determine which bits they
are.

All this is still of no use to the OP. The only answer is for him to
actually look at the details of the systems that he is developing for
and write conditional code for each differing system.
 
J

jacob navia

santosh said:
He is saying that the "size" of an object within a C program is the size
that sizeof returns for it, or the size that you defined. What goes on
underneath is not something that a portable C program can know or take
advantage of. The standard doesn't guarantee anything about writing to
bits set aside for padding, even if you can determine which bits they
are.

Well, then, this is exactly what I said. I said that long doubles
are 10 bytes with some padding, so only 80 bits are really data,
the rest is padding. He was saying that sizeof() gives the number
of bits. But I see, again, word games ad nauseum.
All this is still of no use to the OP.
Yes

The only answer is for him to
actually look at the details of the systems that he is developing for
and write conditional code for each differing system.

As in the document from Sun that I pointed to in my answer: there the
different bit representations are explained in all details for x86
and Sparc.
 
Y

ymuntyan

No. In the x86 the long double is 10 bytes, but it
is rounded up into 12 (lcc-win) or even 16, just for
alignment reasons.

Except when you use an MS compiler on windows.

Yevgen
 
U

user923005

Except when you use an MS compiler on windows.

The compiler in question does not change the size of the hardware long
double (but one could effectively argue that the C compiler
implementation formally defines what the size of a type for the
compiler is).

With the MS compilers, you can use 80 bits internally:
http://msdn2.microsoft.com/en-us/library/aa272724(VS.60).aspx says:
"The Microsoft run-time library sets the default internal precision of
the math coprocessor (or emulator) to 64 bits. This default applies
only to the internal precision at which all intermediate calculations
are performed; it does not apply to the size of arguments, return
values, or variables. You can override this default and set the chip
(or emulator) back to 80-bit precision by linking your program with
LIB/FP10.OBJ. On the linker command line, FP10.OBJ must appear before
LIBC.LIB, LIBCMT.LIB, or MSVCRT.LIB."

However, you do not get the full width when printing out the answers,
since the values get truncated to 8 byte doubles.

At any rate, giving me only 64 bits of my 80 bit floating point
registers stinks.
 
Y

ymuntyan

The compiler in question does not change the size of the hardware long
double (but one could effectively argue that the C compiler
implementation formally defines what the size of a type for the
compiler is).

I didn't say anything about hardware, I referred to

"If sizeof(long double) * CHAR_BIT == 96 on some system"
....
"No. In the x86 the long double is 10 bytes, but it
is rounded up into 12 (lcc-win) or even 16,"

I take that meant that on x86 sizeof(long double) will
always be at least 10 (or even 12?), and usually 12 or
even 16. Not true if you are using an MS compiler, that's it.
With the MS compilers, you can use 80 bits internally:
http://msdn2.microsoft.com/en-us/library/aa272724(VS.60).aspx says:
[snip]

However, you do not get the full width when printing out the answers,
since the values get truncated to 8 byte doubles.

All values, so it's not just printing answers, it's
the answers themselves in the first place. You don't
care much if there were some bits if you can't touch
those bits :)

Yevgen
 
D

Dom Fulton

Thanks for the input, everyone. It's not quite what I was looking for,
so perhaps I can restate the problem.

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 exactly the same problem if I needed
to do bit manipulation of the FP data.

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 __STC_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 size from these constants.

Any ideas? The gcc system includes did historically have a define
which gave the size of a long double, but this seems to be gone now.

Thanks

-Dom
 
B

Ben Bacarisse

Dom Fulton said:
Thanks for the input, everyone. It's not quite what I was looking for,
so perhaps I can restate the problem.

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;

You are still a bit too close to your problem to explain all the
corners of it. There is no obvious need to know this details you ask
for to export data -- it is done all time simply by converting to
decimal and back.

Your problem may require either more speed or more accuracy (or both)
than this method is capable of. If accuracy is the only problem
(i.e. you want to loose no more bits than you have to due any
difference in formats been A and B) then I think you can find a way
using frexp and scalbn (repeatedly) to construct a representation that
is portable but loses no information.

If speed is the primary problem I suspect you will probably need
another route -- and it won't be portable!.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top