Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- 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")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement