How to represent Infinity in floating/double values in C++?

Viewed 764

As cppreference says "In IEEE 754, the most common binary representation of floating-point numbers, the positive infinity is the value with all bits of the exponent set and all bits of the fraction cleared.". I tried this code snippet, but I don't see exponent bits set. Am I wrong somewhere?

#include <iostream>
#include <limits>
#include <bitset>
#include <math.h>
using namespace std;
int main() {
    float a = 0b00000000000000000000000000000000;

    double b = std::numeric_limits<double>::infinity();
    bitset<64> x(b);

    cout<<x<<endl;
    return 0;
}

It prints 0000000000000000000000000000000000000000000000000000000000000000 on console.

3 Answers

std::bitset doesn't have a constructor accepting a double. When you pass double, you instead invoke the constructor that accepts unsigned long long and the double is first implicitly converted to unsigned long long.

Problem is, unsigned long long cannot represent infinity, and the behaviour of the program is consequently undefined. Standard says:

[conv.fpint]

A prvalue of a floating-point type can be converted to a prvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type.


To see the bits, you can first "bitcast" the floating point to an integer type, and then pass that integer to bitset:

auto int_b = std::bit_cast<std::uint64_t>(b);
std::bitset<64> x(int_b);

0000000000000000000000000000000000000000000000000000000000000000

Really?

Mine prints

#include <cmath>
#include <iostream>
#include <limits>
#include <bitset>

const char NL = '\n';

int main() {
    typedef union {
        double   d;
        uint64_t u;
    } du;

    du b;
    
    b.d = std::numeric_limits<double>::infinity();
    std::bitset<64> x(b.d);

    std::cout << x << " " << b.u << NL;
    std::cout << std::bitset<64>(b.u) << NL;
    return 0;
}

1000000000000000000000000000000000000000000000000000000000000000 9218868437227405312

and last line prints

0111111111110000000000000000000000000000000000000000000000000000

Yes, UB, I know, I know

The line

bitset<64> x(b);

implicitly converts b to an unsigned long long (or unsigned long prior to C++11) to invoke the bitset(unsigned long long) constructor of std::bitset.

Note that when converting between a floating point type and an integral type, the behavior is undefined if value cannot be represented in the destination type (N4659 7.10/1). So, creating a bitset in this way could lead to anything being printed.

Related