Asserting that a number is in binary

Viewed 105

Im working on my homework and encountered a problem. I had to string numbers in binary back to back. Lets say we have joined(1, 3) - 1 is the starting number and 3 says that Im gonna work with 2 more numbers (if i had joined(5, 4), id work with 5, 6, 7 and 8) 1 1 2 10 3 11 result 11011

def num_to_2(number):
    num2 = 0
    exp = 0
    while number >= 1:
        num2 += (number % 2) * (10 ** exp)
        number = number // 2
        exp += 1
    return num2


def num_lenght(number):
    if number == 0:
        return 0
    lenght = 0
    while number >= 1:
        number /= 10
        lenght += 1
    return lenght


def joined(start, count):
    result = 0
    end = start + count - 1
    for i in range(end, start - 1, -1):
        number = num_to_2(i)
        res_lenght = num_lenght(result)
        result += number * (10 ** res_lenght)
    return result


def main():
    assert joined(1, 3) == 0b11011
    assert joined(10, 4) == 0b1010101111001101
    assert joined(8, 5) == 0b10001001101010111100
    assert joined(99, 2) == 0b11000111100100
    assert joined(999, 3) == 0b111110011111111010001111101001
    assert joined(1111, 1) == 0b10001010111

The function works properly but it gives me results without the 0b prefix, which i need in order to pass the asserts. How do i add it there? and also: i cant use strings.

Thanks in advance!

Edit: i added the rest of my code so it makes more sense

4 Answers

Well, it's unclear what your teachers mean with "don't use strings". I found this a very strange homework, so I did it, without strings.

I'm not sure what you are supposed to learn from it, but here it is:

def to_binary(number):
    b = 0
    while number >= 2**(b+1):
        b += 1
        
    while True:
        if number >= 2**b:
            yield 1
            number -= 2**b
        else:
            yield 0
        b -= 1
        if b < 0:
            return


def joined(start, count):
    result = 0
    for i in range(start, start + count):
        for digit in to_binary(i):
            result = (result << 1) + digit
    return result
    

def main():
    assert joined(1, 3) == 0b11011
    assert joined(10, 4) == 0b1010101111001101
    assert joined(8, 5) == 0b10001001101010111100
    assert joined(99, 2) == 0b11000111100100
    assert joined(999, 3) == 0b111110011111111010001111101001
    assert joined(1111, 1) == 0b10001010111

It implements a to_binary() function that will yield a sequence of integers. Then the join function will binary shift the result to the left, and add that one or zero.

No strings attached...

I already solved my problem, what i had to do was "manually" convert the pseudo-binary number into base 10 number. this is my code now:

def convert_to_2(number):
    num2 = 0
    exp = 0
    while number >= 1:
        num2 += (number % 2) * (10 ** exp)
        number = number // 2
        exp += 1
    return num2


def num_lenght(number):
    if number == 0:
        return 0
    lenght = 0
    while number >= 1:
        number /= 10
        lenght += 1
    return lenght


def joined(start, count):
    result = 0
    end = start + count - 1
    for i in range(end, start - 1, -1):
        number = convert_to_2(i)
        res_lenght = num_lenght(result)
        result += number * (10 ** res_lenght)
    result = convert_to_10(result)
    return result


def convert_to_10(number):
    num10 = 0
    exp = 0
    while number >= 1:
        num10 += (number % 10) * (2 ** exp)
        number = number // 10
        exp += 1
    return num10


def main():
    assert joined(1, 3) == 0b11011
    assert joined(10, 4) == 0b1010101111001101
    assert joined(8, 5) == 0b10001001101010111100
    assert joined(99, 2) == 0b11000111100100
    assert joined(999, 3) == 0b111110011111111010001111101001
    assert joined(1111, 1) == 0b10001010111


if __name__ == "__main__":
    main()

thank you so much for your help(:

Here is a bit-shifting version which passes all assertions:

from math import ceil, log2
from functools import reduce

def join2(a,b):
    n = ceil(log2(b+1))
    return (a<<n) | b

def joined(start, count):
    return reduce(join2,range(start,start+count))

def main():
    assert joined(1, 3) == 0b11011
    assert joined(10, 4) == 0b1010101111001101
    assert joined(8, 5) == 0b10001001101010111100
    assert joined(99, 2) == 0b11000111100100
    assert joined(999, 3) == 0b111110011111111010001111101001
    assert joined(1111, 1) == 0b10001010111

You don't need to worry about the 0b prefix, it is merely a way to express numeric literals in Python source code. They could have written 27 or 0x1b instead of 0b11011 but the binary form makes it clearer what bit pattern is expected in the integer value returned by joined().

You can use the integer's .bit_length() method to know how many bits are used to represent a number. This should make the function a bit simpler.

def joined(start,count):
    result = 0
    for n in range(start,start+count):
        result <<= n.bit_length()       # offset by the number of bits
        result  |= n                    # add the number's bits
    return result

if you're not allowed to use that method, you can write your own function to do it:

def bitLength(N): return 0 if not N else bitLength(N//2)+1

If you're also not allowed to use bit-wise operators, you can do it with multiplications and additions:

def joined(start,count):
    result = 0
    for n in range(start,start+count):
        result  *= 2**bitLength(n)      # offset by the number of bits
        result  += n                    # add the number's bits
    return result
Related