#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <limits>
#include <utility>


union Float_t
{
    Float_t(float num = 0.0f) : f(num) {}
    
    bool Negative() const { return (i >> 31) != 0; }
    std::int32_t RawMantissa() const { return i & ((1 << 23) - 1); }
    std::int32_t RawExponent() const { return (i >> 23) & 0xFF; }
    
    std::int32_t i;
    float f;
    
    struct
    {
        std::uint32_t mantissa : 23;
        std::uint32_t exponent : 8;
        std::uint32_t sign : 1;
    } parts;
};


template<typename T>
unsigned int ulpDistance(T value1, T value2)
{
    // Simplified version not treating special cases from
    // http://stackoverflow.com/questions/13940316/floating-point-comparison-revisited
    
    int minExponent, maxExponent;
    T minSignificand = std::frexp(value1, &minExponent);
    T maxSignificand = std::frexp(value2, &maxExponent);
    if (minExponent > maxExponent) {
        std::swap(minSignificand, maxSignificand);
        std::swap(minExponent, maxExponent);
    }
    
    const T scaledMinSignificand = std::ldexp(
        minSignificand, minExponent - maxExponent
    );
    
    return 2 * std::abs(maxSignificand - scaledMinSignificand) /
        std::numeric_limits<T>::epsilon();
}


int main(int argc, char **argv)
{
    Float_t first = 1.999999f;
    Float_t number = first.f;
    
    do
    {
        std::printf(
            "float(%1.8e), int(0x%08X), exponent(%d), mantissa(0x%06X)\n",
            number.f, number.i,
            number.parts.exponent, number.parts.mantissa
        );
        
        if (ulpDistance(first.f, number.f) != number.i - first.i) {
            std::printf("  %d != %d\n",
                        ulpDistance(first.f, number.f), number.i - first.i);
        }
        
        number.i += 1;
    } while (number.f < 2.000001f);
    
    return 0;
}
