3

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?

6
  • 1
    Have a look at this answer, it might point you in the riht direction Commented Sep 7, 2017 at 11:00
  • 1
    @GPhilo: Thanks. Actually, that answer seems to make it clear that, no, there is no more convenient approach. Commented Sep 7, 2017 at 12:14
  • 2
    Take a look at numpy.frexp Commented Sep 7, 2017 at 12:42
  • @MarkDickinson: numpy.frexp gives a decomposition into exponent and mantissa, not the decomposition into exponent and significand encoded in an IEEE 754 float. (The exponent given by frexp differs by one from the IEEE 754 float exponent.) Commented Sep 7, 2017 at 13:59
  • @equaeghe: Yes, but it's trivial to get from the frexp result to the IEEE 754 decomposition. As you say, the exponent differs by one, so subtract one from the exponent and double the significand. Commented Sep 8, 2017 at 11:40

1 Answer 1

4

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.