Skip to content

Instantly share code, notes, and snippets.

@kms70847
Created May 16, 2019 16:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kms70847/38f404708ec58c3cb955c69c4ffc428b to your computer and use it in GitHub Desktop.
Save kms70847/38f404708ec58c3cb955c69c4ffc428b to your computer and use it in GitHub Desktop.
import struct
import math
import decimal
from fractions import Fraction
def float_to_bits(f):
bits = [(b>>i)%2 for b in struct.pack(">d", f) for i in range(7, -1, -1)]
return "".join(str(b) for b in bits)
def bits_to_float(bits):
result = 0
for b in bits:
result <<= 1
result += int(b)
return struct.unpack("d", struct.pack("Q", result))[0]
EXPONENT_OFFSET = 1023
BASE = 2
PRECISION = 53
regions = {
"sign": slice(0, 1),
"exponent": slice(1, 12),
"mantissa": slice(12, 64)
}
#normals
test_cases = [math.pi, 1.0, 0.25, 123.456, -777.0]
#denormals
test_cases += [0.0, -0.0, 1.1125369292536007e-308]
#specials
test_cases += [float("nan"), float("inf"), float("-inf")]
for idx, f in enumerate(test_cases,1):
print(f"Example #{idx}: {f}")
bits = float_to_bits(f)
print(f" Stored in memory as {bits}")
for name, s in regions.items():
label = f" {name} bit{'s' if s.stop-s.start>1 else ''}:"
padding = " " * (20 + s.start - len(label))
print(label, padding, bits[s])
sign = 1 if bits[0] == "0" else -1
raw_exponent = int(bits[regions["exponent"]], 2)
if raw_exponent == 0b11111111111:
print(" an exponent of 0b11111111111 signals that the number is special -- either NAN or an infinity")
if bits[regions["mantissa"]][0] == "1":
print(" If the mantissa's leftmost bit is 1, the value is NaN.")
else:
print(" If the mantissa's leftmost bit is 0, the value is an infinity.")
print(f" Taking the sign bit into account, the value is {'positive' if sign == 1 else 'negative'} infinity.")
print("\n\n")
continue
normal = raw_exponent != 0
if normal:
print(f" mantissa with implied `1` bit: 1{bits[regions['mantissa']]}")
else:
print(f" mantissa with implied `0` bit: 0{bits[regions['mantissa']]}")
print(f" raw exponent: {raw_exponent}")
if normal:
exponent_bias = EXPONENT_OFFSET
if not normal:
exponent_bias = EXPONENT_OFFSET - 1
print(f" a raw exponent of 00000000000 signals that the float is DENORMAL.")
print(f" exponent bias for denormal numbers is {exponent_bias} instead of the usual {EXPONENT_OFFSET}")
exponent = raw_exponent - exponent_bias
print(f" actual exponent (subtracting exponent bias {exponent_bias} from raw): {exponent}")
# mantissa = sum([Fraction(1, 2**i) for i, bit in enumerate(raw_mantissa,1) if bit=="1"], Fraction(1))
# print(f" raw mantissa: 0b1.{raw_mantissa} \n calculated mantissa: {mantissa}")
# value = mantissa * Fraction(BASE)**adjusted_exponent
# print(f" final value: {value} ~= {float(value)}")
raw_mantissa = int(bits[regions["mantissa"]], 2)
if normal:
mantissa = raw_mantissa + 2**(PRECISION-1)
else:
mantissa = raw_mantissa
print(f" mantissa with implied bit: {mantissa}")
print(f" final value formula: sign * (mantissa / b^(p-1)) * b^exponent")
print(f" b (aka base) = {BASE}")
print(f" p (aka precision) = {PRECISION}")
print(f" final value = {sign} * ({mantissa} / {BASE}^{PRECISION-1}) * {BASE}^{exponent}")
print(f" final value = {sign} * ({mantissa} / {BASE**(PRECISION-1)}) * {Fraction(BASE)**exponent}")
result = sign * Fraction(mantissa, BASE**(PRECISION-1)) * Fraction(BASE)**exponent
print(f" final value = {result}")
if str(result) != str(decimal.Decimal(f)):
print(f" final value = {decimal.Decimal(f)}")
if str(float(result)) != str(decimal.Decimal(f)):
print(f" final value ~= {float(result)}")
print("\n\n")
Example #1: 3.141592653589793
Stored in memory as 0100000000001001001000011111101101010100010001000010110100011000
sign bit: 0
exponent bits: 10000000000
mantissa bits: 1001001000011111101101010100010001000010110100011000
mantissa with implied `1` bit: 11001001000011111101101010100010001000010110100011000
raw exponent: 1024
actual exponent (subtracting exponent bias 1023 from raw): 1
mantissa with implied bit: 7074237752028440
final value formula: sign * (mantissa / b^(p-1)) * b^exponent
b (aka base) = 2
p (aka precision) = 53
final value = 1 * (7074237752028440 / 2^52) * 2^1
final value = 1 * (7074237752028440 / 4503599627370496) * 2
final value = 884279719003555/281474976710656
final value = 3.141592653589793115997963468544185161590576171875
final value ~= 3.141592653589793
Example #2: 1.0
Stored in memory as 0011111111110000000000000000000000000000000000000000000000000000
sign bit: 0
exponent bits: 01111111111
mantissa bits: 0000000000000000000000000000000000000000000000000000
mantissa with implied `1` bit: 10000000000000000000000000000000000000000000000000000
raw exponent: 1023
actual exponent (subtracting exponent bias 1023 from raw): 0
mantissa with implied bit: 4503599627370496
final value formula: sign * (mantissa / b^(p-1)) * b^exponent
b (aka base) = 2
p (aka precision) = 53
final value = 1 * (4503599627370496 / 2^52) * 2^0
final value = 1 * (4503599627370496 / 4503599627370496) * 1
final value = 1
final value ~= 1.0
Example #3: 0.25
Stored in memory as 0011111111010000000000000000000000000000000000000000000000000000
sign bit: 0
exponent bits: 01111111101
mantissa bits: 0000000000000000000000000000000000000000000000000000
mantissa with implied `1` bit: 10000000000000000000000000000000000000000000000000000
raw exponent: 1021
actual exponent (subtracting exponent bias 1023 from raw): -2
mantissa with implied bit: 4503599627370496
final value formula: sign * (mantissa / b^(p-1)) * b^exponent
b (aka base) = 2
p (aka precision) = 53
final value = 1 * (4503599627370496 / 2^52) * 2^-2
final value = 1 * (4503599627370496 / 4503599627370496) * 1/4
final value = 1/4
final value = 0.25
Example #4: 123.456
Stored in memory as 0100000001011110110111010010111100011010100111111011111001110111
sign bit: 0
exponent bits: 10000000101
mantissa bits: 1110110111010010111100011010100111111011111001110111
mantissa with implied `1` bit: 11110110111010010111100011010100111111011111001110111
raw exponent: 1029
actual exponent (subtracting exponent bias 1023 from raw): 6
mantissa with implied bit: 8687443681197687
final value formula: sign * (mantissa / b^(p-1)) * b^exponent
b (aka base) = 2
p (aka precision) = 53
final value = 1 * (8687443681197687 / 2^52) * 2^6
final value = 1 * (8687443681197687 / 4503599627370496) * 64
final value = 8687443681197687/70368744177664
final value = 123.4560000000000030695446184836328029632568359375
final value ~= 123.456
Example #5: -777.0
Stored in memory as 1100000010001000010010000000000000000000000000000000000000000000
sign bit: 1
exponent bits: 10000001000
mantissa bits: 1000010010000000000000000000000000000000000000000000
mantissa with implied `1` bit: 11000010010000000000000000000000000000000000000000000
raw exponent: 1032
actual exponent (subtracting exponent bias 1023 from raw): 9
mantissa with implied bit: 6834564278255616
final value formula: sign * (mantissa / b^(p-1)) * b^exponent
b (aka base) = 2
p (aka precision) = 53
final value = -1 * (6834564278255616 / 2^52) * 2^9
final value = -1 * (6834564278255616 / 4503599627370496) * 512
final value = -777
final value ~= -777.0
Example #6: 0.0
Stored in memory as 0000000000000000000000000000000000000000000000000000000000000000
sign bit: 0
exponent bits: 00000000000
mantissa bits: 0000000000000000000000000000000000000000000000000000
mantissa with implied `0` bit: 00000000000000000000000000000000000000000000000000000
raw exponent: 0
a raw exponent of 00000000000 signals that the float is DENORMAL.
exponent bias for denormal numbers is 1022 instead of the usual 1023
actual exponent (subtracting exponent bias 1022 from raw): -1022
mantissa with implied bit: 0
final value formula: sign * (mantissa / b^(p-1)) * b^exponent
b (aka base) = 2
p (aka precision) = 53
final value = 1 * (0 / 2^52) * 2^-1022
final value = 1 * (0 / 4503599627370496) * 1/44942328371557897693232629769725618340449424473557664318357520289433168951375240783177119330601884005280028469967848339414697442203604155623211857659868531094441973356216371319075554900311523529863270738021251442209537670585615720368478277635206809290837627671146574559986811484619929076208839082406056034304
final value = 0
final value ~= 0.0
Example #7: -0.0
Stored in memory as 1000000000000000000000000000000000000000000000000000000000000000
sign bit: 1
exponent bits: 00000000000
mantissa bits: 0000000000000000000000000000000000000000000000000000
mantissa with implied `0` bit: 00000000000000000000000000000000000000000000000000000
raw exponent: 0
a raw exponent of 00000000000 signals that the float is DENORMAL.
exponent bias for denormal numbers is 1022 instead of the usual 1023
actual exponent (subtracting exponent bias 1022 from raw): -1022
mantissa with implied bit: 0
final value formula: sign * (mantissa / b^(p-1)) * b^exponent
b (aka base) = 2
p (aka precision) = 53
final value = -1 * (0 / 2^52) * 2^-1022
final value = -1 * (0 / 4503599627370496) * 1/44942328371557897693232629769725618340449424473557664318357520289433168951375240783177119330601884005280028469967848339414697442203604155623211857659868531094441973356216371319075554900311523529863270738021251442209537670585615720368478277635206809290837627671146574559986811484619929076208839082406056034304
final value = 0
final value = -0
final value ~= 0.0
Example #8: 1.1125369292536007e-308
Stored in memory as 0000000000001000000000000000000000000000000000000000000000000000
sign bit: 0
exponent bits: 00000000000
mantissa bits: 1000000000000000000000000000000000000000000000000000
mantissa with implied `0` bit: 01000000000000000000000000000000000000000000000000000
raw exponent: 0
a raw exponent of 00000000000 signals that the float is DENORMAL.
exponent bias for denormal numbers is 1022 instead of the usual 1023
actual exponent (subtracting exponent bias 1022 from raw): -1022
mantissa with implied bit: 2251799813685248
final value formula: sign * (mantissa / b^(p-1)) * b^exponent
b (aka base) = 2
p (aka precision) = 53
final value = 1 * (2251799813685248 / 2^52) * 2^-1022
final value = 1 * (2251799813685248 / 4503599627370496) * 1/44942328371557897693232629769725618340449424473557664318357520289433168951375240783177119330601884005280028469967848339414697442203604155623211857659868531094441973356216371319075554900311523529863270738021251442209537670585615720368478277635206809290837627671146574559986811484619929076208839082406056034304
final value = 1/89884656743115795386465259539451236680898848947115328636715040578866337902750481566354238661203768010560056939935696678829394884407208311246423715319737062188883946712432742638151109800623047059726541476042502884419075341171231440736956555270413618581675255342293149119973622969239858152417678164812112068608
final value = 1.1125369292536006915451163586662020321096079902311659152766637084436022174069590979271415795062555102820336698655179055025762170807767300544280061926888594105653889967660011652398050737212918180359607825234712518671041876254033253083290794743602455899842958198242503179543850591524373998904438768749747257902258025254576999282912354093225567689679024960579905428830259962166760571761950743978498047956444458014963207555317331566968317387932565146858810236628158907428321754360614143188210224234057038069557385314008449266220550120807237108092835830752700771425423583764509515806613894483648536865616670434944915875339194234630463869889864293298274705456845477030682337843511993391576453404923086054623126983642578125E-308
final value ~= 1.1125369292536007e-308
Example #9: nan
Stored in memory as 0111111111111000000000000000000000000000000000000000000000000000
sign bit: 0
exponent bits: 11111111111
mantissa bits: 1000000000000000000000000000000000000000000000000000
an exponent of 0b11111111111 signals that the number is special -- either NAN or an infinity
If the mantissa's leftmost bit is 1, the value is NaN.
Example #10: inf
Stored in memory as 0111111111110000000000000000000000000000000000000000000000000000
sign bit: 0
exponent bits: 11111111111
mantissa bits: 0000000000000000000000000000000000000000000000000000
an exponent of 0b11111111111 signals that the number is special -- either NAN or an infinity
If the mantissa's leftmost bit is 0, the value is an infinity.
Taking the sign bit into account, the value is positive infinity.
Example #11: -inf
Stored in memory as 1111111111110000000000000000000000000000000000000000000000000000
sign bit: 1
exponent bits: 11111111111
mantissa bits: 0000000000000000000000000000000000000000000000000000
an exponent of 0b11111111111 signals that the number is special -- either NAN or an infinity
If the mantissa's leftmost bit is 0, the value is an infinity.
Taking the sign bit into account, the value is negative infinity.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment