HCI Data Representation Practice Question 2

(a) Decimal numbers to binary numbers

Non-Recursive

# Non-Recursive
def dec_to_bin(number):
    # Special case
    if number == 0:
        return "0"
 
    answer = ""
 
    while number > 0:
        # Remainder becomes the next binary digit
        remainder = str(number % 2)
        # Put the remainder at the front of the answer
        answer = remainder + answer
        # Update number to the quotient so the loop progresses
        number = number // 2
    return answer
 

Recursive

# Recursive
def dec_to_bin(number):
	# base case
	if number < 2:
		return str(number)
	
	return dec_to_bin(number // 2) + str(number % 2)

(b) Decimal numbers to hexadecimal numbers

Non-Recursive

# Non-Recursive
HEX_DIGITS = "0123456789ABCDEF"
 
def dec_to_hex(number):
    if number == 0:
        return "0"
 
    answer = ""
 
    while number > 0:
        # Remainder is an integer from 0 to 15
        remainder = number % 16
 
        # Convert it to the corresponding hexadecimal character
        hex_digit = HEX_DIGITS[remainder]
 
        # Add the digit to the front
        answer = hex_digit + answer
 
        # Continue converting the quotient
        number = number // 16
 
    return answer
 

Recursive

# Recursive
HEX_DIGITS = "0123456789ABCDEF"
 
def dec_to_hex(number):
    # base case
    if number < 16:
        return HEX_DIGITS[number]
 
    # recursive case
    return dec_to_hex(number // 16) + HEX_DIGITS[number % 16]
 
 
# Example
dec_to_hex(2748)
= dec_to_hex(171) + "C"
= dec_to_hex(10) + "B" + "C"
= "A" + "B" + "C"
= "ABC"

(c) Binary numbers to decimal numbers

Non-Recursive

# Non-Recursive
def bin_to_dec(number):
    answer = 0
    no_of_bin = len(number)
 
    for digit in number:
        answer = answer + int(digit) * 2 ** (no_of_bin - 1)
        no_of_bin -= 1
 
    return answer
ChatGPT Ver:
def bin_to_dec(number):
    answer = 0
 
    for i in number:
        answer = answer * 2 + int(i)
 
    return answer

Recursive

# Recursive
def bin_to_dec(number):
	# base case
    if len(number) == 1:
        return int(number)
    
    # recursive case
     return bin_to_dec(number[:-1]) * 2 + int(number[-1])
Trace "1101"
bin_to_dec("1101")
= bin_to_dec("110") × 2 + 1
bin_to_dec("110")
= bin_to_dec("11") × 2 + 0
bin_to_dec("11")
= bin_to_dec("1") × 2 + 1

到达 base case

bin_to_dec("1") = 1

开始返回:

bin_to_dec("11")
= 1 × 2 + 1
= 3
bin_to_dec("110")
= 3 × 2 + 0
= 6
bin_to_dec("1101")
= 6 × 2 + 1
= 13

(d) Hexadecimal numbers to decimal numbers

Non-Recursive

# Non-Recursive
HEX_DIGITS = "0123456789ABCDEF"
 
def hex_to_dec(number):
    answer = 0
 
    for i in number:
        value = HEX_DIGITS.index(i)
        answer = answer * 16 + value
 
    return answer

Recursive

# Recursive
HEX_DIGITS = "0123456789ABCDEF"
 
def hex_to_dec(number):
    # base case
    if len(number) == 1:
        return HEX_DIGITS.index(number)
 
    # recursive case
    return hex_to_dec(number[:-1]) * 16 + HEX_DIGITS.index(number[-1])

(e) Binary numbers to hexadecimal numbers

Use Mapping:

since there are only 16 variations

HEX_DIGITS = "0123456789ABCDEF"
 
BINARY_NIBBLES = [
    "0000", "0001", "0010", "0011",
    "0100", "0101", "0110", "0111",
    "1000", "1001", "1010", "1011",
    "1100", "1101", "1110", "1111"
]
 

Non-Recursive

# Non-Recursive
 
# Mapping
HEX_DIGITS = "0123456789ABCDEF"
 
BINARY_NIBBLES = [
    "0000", "0001", "0010", "0011",
    "0100", "0101", "0110", "0111",
    "1000", "1001", "1010", "1011",
    "1100", "1101", "1110", "1111"
]
 
# Code
def bin_to_hex(number):
    # Step 1: add leading zeroes
    while len(number) % 4 != 0:
        number = "0" + number
 
    answer = ""
 
    # Step 2: process four digits at a time
    for i in range(0, len(number), 4):
        nibble = number[i:i + 4]
 
        # Step 3: convert the nibble into a value 
        # (value is a digit 0-15)
        value = BINARY_NIBBLES.index(nibble)
 
        # Step 4: convert the value into a hexadecimal digit
        hex_digit = HEX_DIGITS[value]
 
        # Step 5: add the digit to the answer
        answer = answer + hex_digit
 
    return answer
 
Trace "101101"

使用 bin_to_hex("101101") 作为 test case。

Step 1 — Add leading zeroes

"101101" 的 length 是 6,不是 4 的倍数,所以 while loop 在左边加入 leading zeroes:

101101    length 6
0101101   length 7
00101101  length 8

现在 8 % 4 == 0,所以 while loop 停止,number"00101101"

Step 2 — Initialise the accumulator

answer = ""

answer 是 accumulator,用来逐个储存转换完成的 hexadecimal digits。

Step 3 — Process one nibble per iteration

for i in range(0, len(number), 4):

此时相当于 range(0, 8, 4),所以 i 依次是 04number[i:i + 4] 从 index i 开始读取四个 digits;ending index 不包括在 slice 内。

iterationinumber[i:i + 4]valuehex_digitanswer
10"0010"2"2""2"
24"1101"13"D""2D"

First iteration:

number = 0 0 1 0 1 1 0 1
index    0 1 2 3 4 5 6 7
         └─────┘
          "0010"
 
BINARY_NIBBLES.index("0010") = 2
HEX_DIGITS[2] = "2"
answer = "" + "2" = "2"

Second iteration:

BINARY_NIBBLES.index("1101") = 13
HEX_DIGITS[13] = "D"
answer = "2" + "D" = "2D"

Final result

101101₂ → 0010 1101₂ → 2D₁₆

因此 return answer 返回 "2D"

Recursive

# Recursive
HEX_DIGITS = "0123456789ABCDEF"
 
BINARY_NIBBLES = [
    "0000", "0001", "0010", "0011",
    "0100", "0101", "0110", "0111",
    "1000", "1001", "1010", "1011",
    "1100", "1101", "1110", "1111"
]
 
def bin_to_hex_recursive(number):
    # base case
    if len(number) <= 4:
        nibble = number.zfill(4) # zfill(4) add leading 0
        value = BINARY_NIBBLES.index(nibble)
        return HEX_DIGITS[value]
    
    # recursive case
    previous_digits = number[:-4]
    last_nibble = number[-4:]
    
	value = BINARY_NIBBLES.index(last_nibble)
    hex_digit = HEX_DIGITS[value] 
    
    return bin_to_hex_recursive(previous_digits) + hex_digit

(f) Hexadecimal numbers to binary numbers

Non-Recursive

# Non-Recursive
 
# Mapping
HEX_DIGITS = "0123456789ABCDEF"
 
BINARY_NIBBLES = [
    "0000", "0001", "0010", "0011",
    "0100", "0101", "0110", "0111",
    "1000", "1001", "1010", "1011",
    "1100", "1101", "1110", "1111"
]
 
answer = "" # DONT FORGET THIS
 
def hex_to_bin(number):
	for i in number:
		value = HEX_DIGITS.index(i)
		answer = answer + BINARY_NIBBLES[value]
	return answer

Recursive

# Recursive
HEX_DIGITS = "0123456789ABCDEF"
 
BINARY_NIBBLES = [
    "0000", "0001", "0010", "0011",
    "0100", "0101", "0110", "0111",
    "1000", "1001", "1010", "1011",
    "1100", "1101", "1110", "1111"
]
 
def hex_to_bin(number):
	# base case
	if len(number) == 1:
		value = HEX_DIGITS.index(number)
		return BINARY_NIBBLES[value]
 
	# recursive case
    previous_digits = number[:-1] # how it reduces to the base case by kicking out the last digit
    last_digit = number[-1]
    value = HEX_DIGITS.index(last_digit)
 
    return hex_to_bin(previous_digits) + BINARY_NIBBLES[value]
		
 
Trace hex_to_bin("2AF")
Call 1
hex_to_bin("2AF")

检查 base case

len("2AF") == 1  # False

执行 recursive case

previous_digits = "2A"
last_digit = "F"
value = 15

因此:

hex_to_bin("2AF")
= hex_to_bin("2A") + "1111"

hex_to_bin("2A") 还没有答案,所以这个 function call 会在 call stack 中等待。

Call 2
hex_to_bin("2A")

检查:

len("2A") == 1  # False

执行:

previous_digits = "2"
last_digit = "A"
value = 10

因此:

hex_to_bin("2A")
= hex_to_bin("2") + "1010"

它也要等待 hex_to_bin("2") 的答案。

Call 3:到达 base case
hex_to_bin("2")

检查:

len("2") == 1  # True

所以:

value = HEX_DIGITS.index("2")  # 2
return BINARY_NIBBLES[2]       # "0010"

现在不再产生新的 recursive call,开始返回答案。

call stack 返回

hex_to_bin("2") 返回:

"0010"

所以等待中的 hex_to_bin("2A") 可以完成:

hex_to_bin("2A")
= hex_to_bin("2") + "1010"
= "0010" + "1010"
= "00101010"

然后最外层也可以完成:

hex_to_bin("2AF")
= hex_to_bin("2A") + "1111"
= "00101010" + "1111"
= "001010101111"

最终答案:

hex_to_bin("2AF")  # "001010101111"
整个过程的简写
hex_to_bin("2AF")
= hex_to_bin("2A") + "1111"
= hex_to_bin("2") + "1010" + "1111"
= "0010" + "1010" + "1111"
= "001010101111"