Extracting floating-point significand and exponent in NumPy

4.6k views Asked by At

I would like to be able to extract the significand and exponent of floating-point numbers in NumPy. Getting the exponent as an integer is fine and ok for the significand. Getting the significand as a bitfield would be even more convienient.

I am aware that Python floats have a hex method; however, I wish to use numpy.float32, numpy arrays, and ufuncs. I am also aware of the numpy view method that allows me to see the float as an integer and thus as a binary string:

>>> import numpy as np

>>> b = bin(np.float32(1.23456789).view(np.int32))
'0b111111100111100000011001010010'

>>> b[-23:] # extract last 23 bits of IEEE 754 binary32 float, is significand
'00111100000011001010010'

Extracting the exponent and sign in this way is not convenient, as leading 0s are dropped by bin. (I could left-pad to 32 bits with 0s though…)

In any case, because bin is not a ufunc, this is not convenient and I would have to iterate over the array.

Isn't there any more convenient approach to doing what I want?

1

There are 1 answers

0
equaeghe On BEST ANSWER

GPhilio's comment triggered a more thorough search on SO which resulted in the following solution, based on an answer to “extracting mantissa and exponent from double in c#”:

import numpy as np

def decompose(x: np.float32): 
    """decomposes a float32 into negative, exponent, and significand"""
    negative = x < 0
    n = np.abs(x).view(np.int32) # discard sign (MSB now 0),
                                 # view bit string as int32
    exponent = (n >> 23) - 127 # drop significand, correct exponent offset
                               # 23 and 127 are specific to float32
    significand = n & np.int32(2**23 - 1) # second factor provides mask
                                          # to extract significand
    return (negative, exponent, significand)

This approach with bit-level operations of integers is actually more convenient that going to the actual bitstring itself.