Suite à l'article précédent, j'ai mis sur le dépôt GitHub un petit utilitaire Python qui reproduit les conversions entre la valeur du nombre et son codage en 4 octets.
Parfois, voir du code est plus simple qu'un long discours.
Et parce qu'on ne sait jamais trop quel sera la vie future du dépôt, voici le code des deux principales fonctions de l'outil.
import math
def get_byte(number):
"""Takes the current number, and returns the next byte encoding it with the reminder of the number to encode. """
number *= 256
result = int(number)
return result, (number - result)
def encode(number):
"""Gets a number, returns it's encoded four bytes (memory layout, so exponent at the end)."""
# If the number is zero, the encoding is immediate.
# In fact, only the exponent has to be 0.
if number == 0:
return [0, 0, 0, 0]
# Gets the sign from the number for later encoding
sign = 0x80 if number < 0 else 0
# We encode only positive numbers
number = abs(number)
# Shift the number so that the first fractional part bit
# of the mantissa is 1 (0.1 binary is 0.5 decimal)
exp = 0
while number >= 0.5:
number /= 2
exp += 1
while number < 0.5:
number *= 2
exp -= 1
# Gets the three bytes encoding the mantissa
o1, number = get_byte(number)
o2, number = get_byte(number)
o3, number = get_byte(number)
# Clears the most significant bit
# and replace it by the sign bit
o1 &= 0x7F
o1 |= sign
# Encode exponent
exp += 128
# Returns an array (Z80 memory layout)
return [o3, o2, o1, exp]
def decode(encoded):
""" Takes four encoded bytes in the memory layout, and returns the decoded value. """
# Gets the exponent
exp = encoded[3]
# If it's 0, we're done. The value is 0.
if exp == 0:
return 0
# Extract value from the exponent
exp -= 128
# Extract the sign bit from MSB
sign = encoded[2] & 0x80
# Sets the most significant bit implied 1 in the mantissa
encoded[2] = encoded[2] | 0x80
# Reconstruct the mantissa
mantissa = encoded[2]
mantissa *= 256
mantissa += encoded[1]
mantissa *= 256
mantissa += encoded[0]
# Divide the number by the mantissa, corrected
# by the 24 bits we just shifted while reconstructing it
mantissa /= math.pow(2, 24 - exp)
# Apply the sign to the whole value
if sign:
mantissa = -mantissa
return mantissa