Significand of IEEE float as an integer

I want a function like frexp, but that returns an integer (of the same size of the floating point) and an exponent. Currently I have tried the following implementation:

julia> inexp(x::T) where T <: Base.Math.IEEEFloat = begin
           m, ex = frexp(x)
           b = Base.Math.significand_bits(T)
           mi = trunc(Integer, m * exp2(b))
           return mi, ex - b
inexp (generic function with 1 method)

julia> inexp(2.3)
(2589569785738035, -50)

I am not too familiar with floating points, so I wonder if there anything I should look out for that I am not handling properly in my implementation here.

This seems to always return Int, not “integers of the same size of the floating point”.

Also, I think you’re losing one bit of the significand. For positive, non-denormal, non-NaN, non-Inf, this will give your mi shifted one step left, and with one more bit of information.

Base.significand_mask(T) & reinterpret(Unsigned, x) | 1 << Base.significand_bits(T)
1 Like
import Base: sign_mask, significand_mask, exponent_mask, Math.significand_bits, Math.exponent_bias

function inexp(x::T) where {T}
    xu = reinterpret(Unsigned, x)
    xs = xu & ~sign_mask(T)
    xs >= exponent_mask(T) && return throw(DomainError())

    k = Int(xs >> significand_bits(T))
    if k == 0 # x is subnormal
        m = leading_zeros(xs) - exponent_bits(T)
        xs <<= unsigned(m)
        xu = xs | (xu & sign_mask(T))
        k = 1 - m
    k -= exponent_bias(T)
    k -= significand_bits(T)

    xm = xu  & significand_mask(T)
    int = Int(xm | 1 << significand_bits(T))
    return (signbit(x) ? -int : int), k

which handles NaN and denormals :slight_smile:

x =  realmin(Float64)/2
ret,k = inexp(x)
x == Float64(ret*big(2.0)^k)  # true