Dazbo's Advent of Code solutions, written in Python
binary and hexadecimalString format
If you’re not familiar with binary, hexadecimal, and bases in general, then I’d suggest you first checkout this friendly page.
a_num = 20
bin_as_str = bin(20)
print(f"bin_as_str: {bin_as_str}")
print(f"bin component: {bin_as_str[2:]}")
oct_as_str = oct(20)
print(f"bin_as_str: {oct_as_str}")
print(f"bin component: {oct_as_str[2:]}")
hex_as_str = hex(20)
print(f"bin_as_str: {hex_as_str}")
print(f"bin component: {hex_as_str[2:]}")
Output:
bin_as_str: 0b10100
bin component: 10100
bin_as_str: 0o24
bin component: 24
bin_as_str: 0x14
bin component: 14
# bin to dec
print(int("01101001", 2))
print(int("0b01101001", 2))
# hex to dec
print(int("ff", 16))
Output:
105
105
255
hex_str = "7bff9"
# To get bin value without leading zeroes, just convert from hex to dec - with int(),
# and then from dec to bin - with bin()
bin_val = bin(int(hex_str, 16))
print(bin_val)
# And now using the 'b' format specifier to go from dec to bin with leading zeroes
bin_len = 4*len(hex_str)
bin_val = "{0:0{width}b}".format(int(hex_str, 16), width=bin_len)
print(bin_val)
The first conversion is just using the int() and bin() functions that we’ve already seen.
The second conversion:
int(value, base)
, where base=16
.format spec
, where:
{0}
is the first parameter to the format()
method, i.e. the decimal value;:0{width}b
tells format()
to convert to binary
type, and then pad with 0
in order to achieve the desired overall length.In general, when using a format spec, the format is:
{fill}{align}{width}{type}
Output:
0b1111011111111111001
01111011111111111001
Operation | Operator | Example |
---|---|---|
Bit shift left y places | x « y | Each shift left results in a doubling of the value. E.g. 0b110 < 2 = 0b11000 |
Bit shift right y places | x » y | E.g. shift right results in an integer division by 2. E.g. 0b11000 » 3 = 0b11 |
Bitwise AND | x & y | 1 only if both are 1. |
Bitwise OR | x | y | 1 if either is 1 |
Complement / NOT | ~x | Switch each 0 for 1, and each 1 for 0. |
Exclusive OR (XOR) | x ^ y | 1 where one or other, but not both |
BIN_VAL_AS_STR = "0b0110"
bin_val_as_dec = int(BIN_VAL_AS_STR, 2)
print(f"bin_val as str: {BIN_VAL_AS_STR}'; as decimal: {bin_val_as_dec}")
bin_digit_len = len(str(BIN_VAL_AS_STR)[2:])
print(f"\nbin digits length: {bin_digit_len}")
# This is useful for getting a binary number with leading zeros.
# Results in "#06b"
# The "#" means "include 0b prefix"
# The 0 means include leading zeros
# The 6 means total length of digits (including the 0b)
format_specifier = "#0"+str(int(bin_digit_len)+2)+"b"
print(f"Format specifier: {format_specifier}")
bin_val_as_bin_str = bin(int(BIN_VAL_AS_STR, 2))
print(f"bin_val no leading zeroes: {bin_val_as_bin_str}")
BIN_VAL_AS_STR_with_leading_zeros = format(bin_val_as_dec, format_specifier)
print(f"bin_val as bin with leading zeroes: {BIN_VAL_AS_STR_with_leading_zeros}")
print("\nOperations...")
shift_left = bin_val_as_dec << 2
print(f"shift {bin(bin_val_as_dec)} left by 2 as bin: {bin(shift_left)}; as dec: {shift_left}")
shift_right = shift_left >> 3
print(f"shift {bin(shift_left)} right by 3 as bin: {bin(shift_right)}; as dec: {shift_right}")
complement = ~bin_val_as_dec
print(f"complement of {BIN_VAL_AS_STR} as dec: {complement}")
ones_mask = "0b"+"1"*bin_digit_len
print(f"Ones mask using bin length: {ones_mask}")
complement_positive = ~bin_val_as_dec & int(ones_mask, 2)
print(f"Positive complement of {BIN_VAL_AS_STR} as bin: {bin(complement_positive)}")
print(f"Positive complement of {BIN_VAL_AS_STR} as dec: {complement_positive}")
Output:
bin_val as str: 0b0110'; as decimal: 6
bin digits length: 4
Format specifier: #06b
bin_val no leading zeroes: 0b110
bin_val as bin with leading zeroes: 0b0110
Operations...
shift 0b110 left by 2 as bin: 0b11000; as dec: 24
shift 0b11000 right by 3 as bin: 0b11; as dec: 3
complement of 0b0110 as dec: -7
Ones mask using bin length: 0b1111
Positive complement of 0b0110 as bin: 0b1001
Positive complement of 0b0110 as dec: 9
The complement operation is worth noting. When we take the complement of 6, we end up with -7. This is because negative numbers - in Python - are represented by setting the most significant (leftmost) bit to 1. Thus, if we have a binary number that has a leading 0 and complement it, we will always end up with a negative number. But often that’s not what we want. A neat trick is to perform a bitwise &
with the complement of a binary number, using a mask that is set to all 1s. If we do this, then we will successfully invert all the bits, but in the form of a positive number.