Created
August 23, 2015 21:47
-
-
Save Redchards/7f3492d5c2bcbd3f1a25 to your computer and use it in GitHub Desktop.
A bunch of helper functions to quickly extract information about floating point value. Used mainly for learning. Not production ready by any mean !
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import struct | |
# I do not support Decimal type in this toy code | |
# This piece of code should just work on python2 and python3 | |
# In general, it will work for single precision, IEEE754 compliant floating point numbers | |
# Dirty function to avoid having to type the condition in each function | |
def throwOnNonFloat(num): | |
if not(type(num) is float): | |
raise ValueError(str(num) + " is not a floating point number !") | |
# Converting float to in bitwise | |
def floatToRaw(num): | |
throwOnNonFloat(num) | |
return struct.unpack("=i", struct.pack("=f", num))[0] | |
# Get precision using b^e-(p-1). | |
# If you want to learn more, you can check the formal definition on wikipedia | |
# https://en.wikipedia.org/wiki/Machine_epsilon#Formal_definition (the part on the spacing) | |
# To explaine a bit more, you can think of it this way : | |
# We know that the mantissa is normalized in the IEEE754 standard. So, if the mantissa is p bits wide, | |
# the minimal value of the mantissa is when it is filled with 0s, but the last bit. There is no "1" in front of | |
# the mantissa, because of the hidden bit. The, the minimal value the mantissa alone can represent is b^-(p-1) | |
# So, the minimal value mantissa*(b^e) can represent is (b^-(p-1))*b^e = b^(e-(p-1)), hence the function here. | |
# We have b = 2, p = 24 (defined by IEEE754 standard). | |
def floatPrecision(num): | |
throwOnNonFloat(num) | |
tmp = getExponent(num) | |
return 2**(tmp-24+1) | |
# This function extracts each bits and build a string representing the binary representation of a float number. | |
def floatToBin(num): | |
throwOnNonFloat(num) | |
return bin(floatToRaw(num))[2:] | |
# Same as above, but without using the bin function, extracting bit by bit. No interest in itself, other to show | |
# another method. | |
def floatToBin2(num): | |
throwOnNonFloat(num) | |
numStr = "" | |
tmp = floatToRaw(num) | |
#tmp = cast(pointer(c_float(num)), POINTER(c_int32)).contents.value | |
for i in range(31, -1, -1): | |
numStr += str((tmp & (1 << i)) >> i) | |
return numStr | |
# All the methods presented here are used to extract some datas from the floating point number. | |
# The first three functions are considered "Dumb". Indeed, the extraction method is using the string | |
# provided by the function "floatToBin". Despite being very intuitive, everybody is familiar with string | |
# manipulations, its a very dumb way to extract datas. A more clever, but counter intuitive way for those | |
# who don't know there way through bitwise operations, is the three other functions. They present the | |
# canonic way to do data extraction on int. | |
# Get the exponent with bias. | |
def getBiasedExponentDumb(num): | |
throwOnNonFloat(num) | |
tmpStr = floatToBin(num) | |
tmp = 0 | |
for i in range(1, 9): | |
tmp |= (int(tmpStr[9-i]) << (i-1)) | |
return tmp | |
# Apply bias to get the real exponent | |
def getExponentDumb(num): | |
return getBiasedExponentDumb(num)-127 | |
# Retrieve the mantissa | |
def getMantissaDumb(num): | |
throwOnNonFloat(num) | |
tmpStr = floatToBin(num) | |
tmp = 0 | |
for i in range(1, 24): | |
tmp |= (int(tmpStr[32-i]) << (i-1)) | |
return tmp | |
# Here are more standards functions. We first convert float to int representation, using the fact that both are | |
# 32 bits in python, and using the safe struct packing. We then extract datas as if it were simple integers ! | |
# The functions give strictly the same results as the functions above. | |
def getExponentBiased(num): | |
throwOnNonFloat(num) | |
return (floatToRaw(num) >> 23) & ((0xff)) | |
def getExponent(num): | |
return getBiasedExponent(num)-127 | |
def getMantissa(num): | |
throwOnNonFloat(num) | |
return (floatToRaw(num) & ((1<<24)-1)) | |
# Retrieve the sign bit using the standard method. | |
def getSign(num): | |
return ((floatToRaw(num) & (1<<31)) >> 31) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment