Created
May 16, 2019 16:06
-
-
Save kms70847/38f404708ec58c3cb955c69c4ffc428b to your computer and use it in GitHub Desktop.
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 | |
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") |
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
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