Ensuring C++ doubles are 64 bits
Asked Answered
A

9

30

In my C++ program, I need to pull a 64 bit float from an external byte sequence. Is there some way to ensure, at compile-time, that doubles are 64 bits? Is there some other type I should use to store the data instead?

Edit: If you're reading this and actually looking for a way to ensure storage in the IEEE 754 format, have a look at Adam Rosenfield's answer below.

Ardeha answered 15/4, 2009 at 15:44 Comment(5)
Exactly what are you doing? Are you looking for a completely portable way to take eight bytes and interpret them as an IEEE-standard 64-bit floating-point number?Formalism
@David: Yes, that's exactly what I'm doing. I'd found something somewhere that said C++ floats and doubles were in the IEEE-754 format. I wasn't sure whether doubles always used the same precision and wanted to add a check for it.Ardeha
Now I'm not sure that my original information was correct. What's the convention here? Should I delete this question and add another asking about conversion from IEEE-754?Ardeha
IIUC: 1) IEEE 754 is not guaranteed by the standard (otherwise, I fail to see the point for std::numeric_limits::is_iec559) 2) is_iec559 == true does not guarantee a binary representation.Hyacinthus
Eric: numeric_limits::is_iec559 exists because numeric_limits is designed to be extensible, and, for example, there might be a numeric_limits<BigFloat> specialization for a user-defined BigFloat type for which is_iec559==false. However, you're right that built-in floats might not be IEEE 754.Bedder
L
15

An improvement on the other answers (which assume a char is 8-bits, the standard does not guarantee this..). Would be like this:

char a[sizeof(double) * CHAR_BIT == 64];

or

BOOST_STATIC_ASSERT(sizeof(double) * CHAR_BIT == 64);

You can find CHAR_BIT defined in <limits.h> or <climits>.

Linguistics answered 15/4, 2009 at 18:7 Comment(6)
um, no, it does not at all. sizeof returns in units of chars. CHAR_BIT is defined as the number of bits per char. multiply sizeof(x) by CHAR_BIT and you have exactly how many bits x is.Linguistics
So for example, on x86 CHAR_BIT is defined as 8. sizeof(double) return's 8. (8 * 8) == 64.Linguistics
Quoting the standard, 5.3.3p1: "The sizeof operator yields the number of bytes in the object representation of its operands." QEDBedder
Also, since CHAR_BIT is inhertied from c, the rules of c apply: to quote the C99 draft standard (section 6.2.6.1p3): "Values stored in objects of any other object type consist of n x CHAR_BIT bits, where n is the size of an object of that type, in bytes."Linguistics
Finally, from that SAME paragraph you quoted: "sizeof(char), sizeof(signed char) and sizeof(unsigned char) are 1;" if sizeof(char) == 1 and sizeof by definition returns in units of bytes. then that means that a char is the same size as a byte. However, a byte need not be 8-bits.Linguistics
So yes, your original comment was correct that I assumed that a char is the same size as a byte. But you are incorrect in thinking they are different. The standard clearly shows that they are the same. However, it makes no claims that a byte is 8-bits.Linguistics
M
41

In C99, you can just check if the preprocessor symbol __STDC_IEC_559__ is defined. If it is, then you are guaranteed that a double will be an 8-byte value represented with IEEE 754 (also known as IEC 60559) format. See the C99 standard, Annex F. I'm not sure if this symbol is available in C++, though.

#ifndef __STDC_IEC_559__
#error "Requires IEEE 754 floating point!"
#endif

Alternatively, you can check the predefined constants __DBL_DIG__ (should be 15), __DBL_MANT_DIG__ (should be 53), __DBL_MAX_10_EXP__ (should be 308), __DBL_MAX_EXP__ (should be 1024), __DBL_MIN_10_EXP__ (should be -307), and __DBL_MIN_EXP__ (should be -1021). These should be available in all flavors of C and C++.

Mariann answered 15/4, 2009 at 18:17 Comment(2)
This is an even better solution than I'd hoped for. Accepted Evan's answer, though, since it answers the question as it exists. I just asked the wrong question.Ardeha
This is inconsistent between compilers and platforms.Atli
C
16

Check std::numeric_limits< double >::is_iec559 if you need to know whether your C++ implementation supports standard doubles. This guarantees not only that the total number of bits is 64, but also the size and position of all fields inside the double.

Corydon answered 17/4, 2009 at 14:38 Comment(0)
L
15

An improvement on the other answers (which assume a char is 8-bits, the standard does not guarantee this..). Would be like this:

char a[sizeof(double) * CHAR_BIT == 64];

or

BOOST_STATIC_ASSERT(sizeof(double) * CHAR_BIT == 64);

You can find CHAR_BIT defined in <limits.h> or <climits>.

Linguistics answered 15/4, 2009 at 18:7 Comment(6)
um, no, it does not at all. sizeof returns in units of chars. CHAR_BIT is defined as the number of bits per char. multiply sizeof(x) by CHAR_BIT and you have exactly how many bits x is.Linguistics
So for example, on x86 CHAR_BIT is defined as 8. sizeof(double) return's 8. (8 * 8) == 64.Linguistics
Quoting the standard, 5.3.3p1: "The sizeof operator yields the number of bytes in the object representation of its operands." QEDBedder
Also, since CHAR_BIT is inhertied from c, the rules of c apply: to quote the C99 draft standard (section 6.2.6.1p3): "Values stored in objects of any other object type consist of n x CHAR_BIT bits, where n is the size of an object of that type, in bytes."Linguistics
Finally, from that SAME paragraph you quoted: "sizeof(char), sizeof(signed char) and sizeof(unsigned char) are 1;" if sizeof(char) == 1 and sizeof by definition returns in units of bytes. then that means that a char is the same size as a byte. However, a byte need not be 8-bits.Linguistics
So yes, your original comment was correct that I assumed that a char is the same size as a byte. But you are incorrect in thinking they are different. The standard clearly shows that they are the same. However, it makes no claims that a byte is 8-bits.Linguistics
M
6

I don't think you should focus on the "raw size" of your double (which is generally 80 bit, not 64 bit), but rather on its precision.

Thanks to numeric_limits::digits10 this is fairly easy.

Mangrove answered 15/4, 2009 at 15:51 Comment(2)
80 bit doubles are an Intel-ism, and true only if the FPU is actually in 80-bit mode (there's also 64-bit mode)...Coraliecoraline
And even 32-bit mode depending on how you initialize Direct3D.Catechin
H
5

The solution without boost is to define the array like so

char a[ 8 == sizeof(double) ];

If the double is not 64 bits then the code will looks like

char a[0];

which is an compile time error. Just put the appropriate comment near this instruction.

Hatband answered 15/4, 2009 at 15:48 Comment(9)
a byte isn't guaranteed to be 8-bitsLinguistics
@Evan: Interesting point. Add "&& (unsigned char) 255 == 255 && (unsigned char) 256 == 0" to the condition to check that chars are 8 bits.Nitrification
What about the case when the size of the double is 16 byte, but the byte consist of 4 bits?Hatband
@j_random_hacker: better yet add "&& CHAR_BIT == 8" since CHAR_BIT is defined as the number of bits per char/unsigned char.Linguistics
or better yet "sizeof(double) * CHAR_BIT == 64"Linguistics
Mykola, a byte can never consist of 4 bits. it has to have at least 8 bits.Archaeornis
ok. I put this only as example to the j_random_hacker proposalHatband
@Evan: I agree, "sizeof(double) * CHAR_BIT == 64" is a better solution (e.g. it handles Mykola's quirky 16 * 4 case) as well as being clearer.Nitrification
Actually, char a[0]; compiles fine on gcc. Try something like char a[1-!STATEMENT] instead. If statement holds, it declares a to be of zero size. Else, it declares a of negative size which is illegal.Wanderoo
J
5

You can use the Boost static assertions to do this. Look at the Use at namespace scope example.

Jari answered 15/4, 2009 at 15:48 Comment(0)
C
1

See this post for a similar problem and a non-boost compile time assertion called CCASSERT.

Cotopaxi answered 15/4, 2009 at 18:13 Comment(0)
F
0

For compilers supporting C11 or C++11, I use something similar to @EvanTeran's:

#include <assert.h> // defines macro static_assert in C11 

static_assert(sizeof(double) * CHAR_BIT == 64, "64-bit double is assumed.");

In C++11 or later, static_assert is a keyword.

Furey answered 15/5, 2022 at 13:44 Comment(0)
N
0

The lack of fixed-width floating point types has been resolved in C++23 with stdfloat:

#include <stdfloat>
 
int main() {
    std::float64_t value = 0.1f64;
}

See the reference here. The latest GCC supports this feature.

Naphthol answered 16/4, 2024 at 21:11 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.