Number of bits in C99 float types?

S

santosh

Dom 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; 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.

No, but float.h gives you compile time access to a lot of constants. You
can test these constants and appropriately declare typedefs for your
own floating types. All conforming implementations are guaranteed to
support the range 1e-37 -> 1e37 for float, double and long double.

I don't think your problem (moving floating values from one system to
another) requires you to know the number of bits in the floating point
types. I think conditional compiling with the values in float.h should
be enough to declare types appropriately to move the data, as long as
the destination system has at least one floating type that can hold the
largest value possible in the source system.

<snip>
 
E

Eric Sosman

Dom 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; 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.
[...]

Then just knowing the bit count is nowhere near enough
information. You need to know where those bits appear in
the representation, and what significance they have.

It seems to me you have two principal options and
some sub-options:

1) If the universe of A's and B's is small and fixed,
you could spend some time with their documentation and write
customized code for each pair. Of course, you need a way to
discover the types of the A and B in any particular exchange.

1a) With luck and a following wind, many of the A/B
"conversions" may turn out to be trivial.

2) You could define a common "wire format" to be used
in all exchanges, and write a set of native-to-wire and
wire-to-native converters for each system type.

2a) Use text, converting with *printf() and with *scanf()
and/or strto*().

2b) Disassemble FP numbers with frexp() and reassemble
with ldexp(). Represent the normalized fraction as a suitable
integer, using the <float.h> constants for scaling.

2c) Consider using XDR formats (RFC 1014). If you're
willing to step outside what Standard C provides, many systems
offer XDR conversion routines. You could roll your own if a
system doesn't have them, or if you're unwilling to rely
on "foreign" components.

I very much doubt that you'll be able to achieve full
round-trip fidelity in all cases, particularly with long double.
 
K

Keith Thompson

Harald van Dijk said:
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.

No, floating point representations are determined by the C
implementation, particularly by the compiler. (Typically the CPU
and/or OS imposes requirements that the compiler needs to follow, or
can violate only with some ugly contortions.)

For example, if a CPU provides, say, 32-bit, 64-bit and 128-bit
floating-point representations a C compiler can legally choose any of
the following, assuming the minimum ranges and precision are
satisified:
32-bit float, 64-bit double, 128-bit long double
32-bit float, 64-bit double, 64-bit long double
128-bit float, 128-bit double, 128-bit long double

Probably one particular choice will make much more sense than the
others.

I've worked on systems (VAX/VMS) that provide multiple floating-point
formats of the same size. The mapping to C floating-point types was
determined by the compiler, and could even be changed by command-line
options.
 
K

Keith Thompson

jacob navia said:
Eric said:
jacob said:
Eric Sosman wrote: [...]
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.

If sizeof(long double) == 12, then long double is 12 bytes, not 10
bytes. It might be the case that only 10 of those bytes contribute to
the value, and the other two bytes are some sort of padding added by
the compiler. A long double isn't 10 bytes plus some padding that
isn't part of the long double; it's 12 bytes *including* two bytes of
padding.

Similarly, if this structure:
struct {
int i; /* assume 4 bytes */
char c; /* 1 byte */
};
is padded to 8 bytes, then the size of the structure really is 8
bytes; the 3 bytes of padding are part of the structure.

You're making a valid point: that a C long double is based on a
10-byte hardware floating-point format. But that 10-byte format is
not a C long double; the padded 12-byte data type is a C long double.
 
H

Harald van Dijk

Harald van Dijk said:
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.
[...]
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.

No, floating point representations are determined by the C
implementation, particularly by the compiler. (Typically the CPU and/or
OS imposes requirements that the compiler needs to follow, or can
violate only with some ugly contortions.)

I do not think this contradicts what I posted. Yes, it's the
implementation that decides the floating point representations, but the
processor and OS are a significant part of the implementation.

What I meant was that the OS may already provide, for example, a strtod
function. Regardless of all else, if the implementation is going to use
that strtod function, it must make sure that the representation of double
matches what strtod returns.
 
C

christian.bau

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?

No. On some x86 systems the compiler uses sizeof (long double) = 16,
but the hardware uses only ten bytes. What this particular assignment
of 42.0L does depends on the code that the compiler generated: The
compiler could load the number 42 into an 80 bit floating point
register, and store the content of the register. This will modify 10
bytes and leave ten bytes unchanged. Or the compiler could have 16
byte lying around somewhere and do effectively the same as

static long double tmp = 42.0L;
memcpy (u.buff, &tmp, sizeof (tmp));

which will overwrite 16 bytes. Or the compiler could decide that
operations with 32 bit integers are much much faster than floating
point, but 16 bit integers are slower, so it could store 12 byte using
three 32-bit integer instructions. As long as the resulting 16 byte
are a valid representation for the number 42.0L, it is all correct.
 
S

santosh

Harald said:
Harald van D?k 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.

No, floating point representations are determined by the C
implementation, particularly by the compiler. (Typically the CPU
and/or OS imposes requirements that the compiler needs to follow, or
can violate only with some ugly contortions.)

I do not think this contradicts what I posted. Yes, it's the
implementation that decides the floating point representations, but
the processor and OS are a significant part of the implementation.

What I meant was that the OS may already provide, for example, a
strtod function. Regardless of all else, if the implementation is
going to use that strtod function, it must make sure that the
representation of double matches what strtod returns.

I think the processor and the purpose of the language determine the
format of floating-point types much more than the OS. A compatibility
layer implemented by the compiler can always make sure that the OS is
given what it expects. Operating systems usually don't deal heavily
with floating-point types.
 
K

Keith Thompson

Harald van Dijk said:
Harald van Dijk 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.

No, floating point representations are determined by the C
implementation, particularly by the compiler. (Typically the CPU and/or
OS imposes requirements that the compiler needs to follow, or can
violate only with some ugly contortions.)

I do not think this contradicts what I posted. Yes, it's the
implementation that decides the floating point representations, but the
processor and OS are a significant part of the implementation.

What I meant was that the OS may already provide, for example, a strtod
function. Regardless of all else, if the implementation is going to use
that strtod function, it must make sure that the representation of double
matches what strtod returns.

The strtod function is part of the C implementation, specifically of
the C runtime library. It may be provided by, or even be a part of,
the OS.

The C compiler and the C library must work together properly (for a
non-buggy implementation). If the library is provided by the OS, then
yes, a lot of the C compiler's decisions are mandated by what the OS
does.

In many cases, the CPU and the OS very strongly suggest a certain set
of floating-point types. The C implementation doesn't *have* to
follow that strong suggestion; it can do whatever it likes within the
requirements imposed by the standard. But very often there's no good
reason not to follow the OS's conventions (and a lot of extra work to
avoid them).
 

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

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top