Simple way to print binary numbers in groups of nibbles
Question:
To improve readability, I would like to print a binary number in groups of 4 (nibbles), that are separated by an underscore.
For example:
9 => "1001"
60 => "0011_1100"
100 => "0110_0100"
63000 => "1111_0110_0001_1000"
I was wondering if there was perhaps a simple way of doing this?
Answers:
I have come up with this function:
import math
def bin_nibble(val):
num_bits = len(format(val, "b"))
return "_".join(reversed([format((val>>shift*4)&0x0F, "04b")
for shift in range(math.ceil(num_bits/4))]))
Try:
def bin_nibble(val):
b = bin(val)[2:]
new_b = '_'.join([b[::-1][i:i+4][::-1] for i in range(0, len(b), 4)][::-1])
If you want to add leading zeros:
def bin_nibble(val):
b = bin(val)[2:]
new_b = '_'.join([b[::-1][i:i+4][::-1] for i in range(0, len(b), 4)][::-1])
return ''.join(['0']*(4 - len(b) % 4 if len(b) % 4 != 0 else 0) + [new_b])
Splitting the logic into generating groups of 4 and joining.
def gen(x):
while x:
yield bin(x % 16)[2:].zfill(4)
x >>= 4
def nibble(x):
return "_".join(gen(x))
Highest to lowest:
def binNibble(num):
nibb = bin(num)[2:]
k = 0 if len(nibb)%4 == 0 else 4-len(nibb)%4 # needs zeros?
nibb = "0"*k + nibb # add them here
return '_'.join(nibb[i:i+4] for i in range(0,len(nibb),4) ) # put _ in
for i in range(0,1152,127):
print(i,": ",binNibble(i))
Output:
0 : 0000
127 : 0111_1111
254 : 1111_1110
381 : 0001_0111_1101
508 : 0001_1111_1100
635 : 0010_0111_1011
762 : 0010_1111_1010
889 : 0011_0111_1001
1016 : 0011_1111_1000
1143 : 0100_0111_0111
Your examples:
9 : 1001
60 : 0011_1100
100 : 0110_0100
63000 : 1111_0110_0001_1000
Another approach using str.format
:
def bin_nibble(a, pad=4):
b = '{:b}'.format(a)
if len(b) % pad:
b = '0' * (pad - (len(b) % pad)) + b
return '_'.join(b[k:k+pad] for k in range(0, len(b), pad))
tests = [9, 60, 100, 63000]
for k in tests:
print(bin_nibble(k))
Output:
1001
0011_1100
0110_0100
1111_0110_0001_1000
@Tjaart, based on your inputs and expected outputs, the following code will work as expected.
Please try it and let me know if it fails for any of your input.
"""
INPUTS AND EXPECTED OUTPUTS:-
9 => "1001"
60 => "0011_1100"
100 => "0110_0100"
63000 => "1111_0110_0001_1000"
"""
def get_binary(n):
s = bin(n)[2:]; # Getting binary string
strs = [];
while s:
l = len(s); # Finding lenght of binary string
if l > 4:
strs.insert(0, s[l-4:]);
s = s[:l-4];
else:
l = len(s);
s = "0"*(4-l) + s; # If length is not equal to 4 (modify it by adding 0s to front)
strs.insert(0, s);
s = "";
return "_".join(strs);
# EXAMPLE 1
a = 9;
print(get_binary(a)); # 1001
# EXAMPLE 2
b = 60;
print(get_binary(b)); # 0011_1100
# EXAMPLE 3
c = 100;
print(get_binary(c)); # 0110_0100
# EXAMPLE 4
d = 63000;
print(get_binary(d)); # 1111_0110_0001_1000
I believe the simplest way is with format (or f-strings which use format).
>>> format(63000, '019_b')
'1111_0110_0001_1000'
the 019_b
means 0-padded, 19-char, "_" nibble separated, binary
If you want the fewest number of nibbles, you may need to do a bit of math to replace the 19 in the formatting or add more padding and string replace any 0000_
with empty string.
E.g. using 039_b
for any 32-bit numbers. For 64-bit you would use 079_b
and so on.
>>> format(100, '039_b').replace('0000_', '')
'0110_0100
To improve readability, I would like to print a binary number in groups of 4 (nibbles), that are separated by an underscore.
For example:
9 => "1001"
60 => "0011_1100"
100 => "0110_0100"
63000 => "1111_0110_0001_1000"
I was wondering if there was perhaps a simple way of doing this?
I have come up with this function:
import math
def bin_nibble(val):
num_bits = len(format(val, "b"))
return "_".join(reversed([format((val>>shift*4)&0x0F, "04b")
for shift in range(math.ceil(num_bits/4))]))
Try:
def bin_nibble(val):
b = bin(val)[2:]
new_b = '_'.join([b[::-1][i:i+4][::-1] for i in range(0, len(b), 4)][::-1])
If you want to add leading zeros:
def bin_nibble(val):
b = bin(val)[2:]
new_b = '_'.join([b[::-1][i:i+4][::-1] for i in range(0, len(b), 4)][::-1])
return ''.join(['0']*(4 - len(b) % 4 if len(b) % 4 != 0 else 0) + [new_b])
Splitting the logic into generating groups of 4 and joining.
def gen(x):
while x:
yield bin(x % 16)[2:].zfill(4)
x >>= 4
def nibble(x):
return "_".join(gen(x))
Highest to lowest:
def binNibble(num):
nibb = bin(num)[2:]
k = 0 if len(nibb)%4 == 0 else 4-len(nibb)%4 # needs zeros?
nibb = "0"*k + nibb # add them here
return '_'.join(nibb[i:i+4] for i in range(0,len(nibb),4) ) # put _ in
for i in range(0,1152,127):
print(i,": ",binNibble(i))
Output:
0 : 0000
127 : 0111_1111
254 : 1111_1110
381 : 0001_0111_1101
508 : 0001_1111_1100
635 : 0010_0111_1011
762 : 0010_1111_1010
889 : 0011_0111_1001
1016 : 0011_1111_1000
1143 : 0100_0111_0111
Your examples:
9 : 1001
60 : 0011_1100
100 : 0110_0100
63000 : 1111_0110_0001_1000
Another approach using str.format
:
def bin_nibble(a, pad=4):
b = '{:b}'.format(a)
if len(b) % pad:
b = '0' * (pad - (len(b) % pad)) + b
return '_'.join(b[k:k+pad] for k in range(0, len(b), pad))
tests = [9, 60, 100, 63000]
for k in tests:
print(bin_nibble(k))
Output:
1001
0011_1100
0110_0100
1111_0110_0001_1000
@Tjaart, based on your inputs and expected outputs, the following code will work as expected.
Please try it and let me know if it fails for any of your input.
"""
INPUTS AND EXPECTED OUTPUTS:-
9 => "1001"
60 => "0011_1100"
100 => "0110_0100"
63000 => "1111_0110_0001_1000"
"""
def get_binary(n):
s = bin(n)[2:]; # Getting binary string
strs = [];
while s:
l = len(s); # Finding lenght of binary string
if l > 4:
strs.insert(0, s[l-4:]);
s = s[:l-4];
else:
l = len(s);
s = "0"*(4-l) + s; # If length is not equal to 4 (modify it by adding 0s to front)
strs.insert(0, s);
s = "";
return "_".join(strs);
# EXAMPLE 1
a = 9;
print(get_binary(a)); # 1001
# EXAMPLE 2
b = 60;
print(get_binary(b)); # 0011_1100
# EXAMPLE 3
c = 100;
print(get_binary(c)); # 0110_0100
# EXAMPLE 4
d = 63000;
print(get_binary(d)); # 1111_0110_0001_1000
I believe the simplest way is with format (or f-strings which use format).
>>> format(63000, '019_b')
'1111_0110_0001_1000'
the 019_b
means 0-padded, 19-char, "_" nibble separated, binary
If you want the fewest number of nibbles, you may need to do a bit of math to replace the 19 in the formatting or add more padding and string replace any 0000_
with empty string.
E.g. using 039_b
for any 32-bit numbers. For 64-bit you would use 079_b
and so on.
>>> format(100, '039_b').replace('0000_', '')
'0110_0100