1

I need to write a Python script that will convert and number x in base 10 to binary with up to n values after the decimal point. And I can't just use bin(x)! Here's what I have:

def decimal_to_binary(x, n):
    x = float(x)
    test_str = str(x)
    dec_at = test_str.find('.')

    #This section will work with numbers in front of the decimal
    p=0
    binary_equivalent = [0]
    c=0
    for m in range(0,100):
        if 2**m <= int(test_str[0:dec_at]):
            c += 1
        else:
            break

    for i in range(c, -1, -1):
        if 2**i + p <= (int(test_str[0:dec_at])):
            binary_equivalent.append(1)
            p = p + 2**i
        else:
            binary_equivalent.append(0)
    binary_equivalent.append('.')

    #This section will work with numbers after the decimal
    q=0
    for j in range(-1, -n-1, -1):
        if 2**j + q <= (int(test_str[dec_at+1:])):
            binary_equivalent.append(1)
            q = q + 2**j
        else:
            binary_equivalent.append(0)

    print float((''.join(map(str, binary_equivalent))))

So say you call the function by decimal_to_binary(123.456, 4) it should convert 123.456 to binary with 4 places after the decimal, yielding 1111011.0111.

The first portion is fine - it will take the numbers in front of the decimal, in this case 123, and convert it to binary, outputting 1111011

However, the second portion, which deals with values after the decimal, is not doing what I think it should. The output it gives is not .0111, but rather .1111

I ran through the code with pen and paper writing down the value for each variable and it should work. But it doesn't. Can anyone help me fix this?

I call the function as decimal_to_binary(123.456, 4) and it prints out 1111011.1111

dvanny
  • 17
  • 1
  • 5

1 Answers1

0

You're close, but there's an issue with your comparison when you go beyond the decimal:

if 2**j + q <= (int(test_str[dec_at+1:])):

What you're doing here is comparing a fractional value (since j is always negative) to a whole integer value. This comparison will, for all practical purposes, always be true.

Based on the surrounding logic, my guess would be that you're attempting to compare it to the actual decimal value here. Using your data, that would be 0.4 on the first iteration, so you expect the statement to be evaluated as:

0.5 <= 0.4

The actual comparison in your code is:

0.5 <= 4

There are two separate issues here:

  1. You're taking all of the numbers after the decimal point, but not actually including the decimal point itself in your extraction. This is primarily why you are getting whole numbers in your test incorrectly. This is fixed simply by referencing test_str[dec_at:] rather than test_str[dec_at+1:]
  2. You're casting to int. Even if you applied the change in the first point, your code would still not run correctly. However, in that case it would be because the cast would truncate the value down to 0 on every iteration. Cast to a float instead: float(test_str[dec_at:])

Your comparison line thus becomes if 2**j + q <= (float(test_str[dec_at:])):, which provides the correct output on my machine.

Note that floating point comparisons can be "finicky" in some situations, depending on rounding and the like. There are ways to mitigate this if needed.

Community
  • 1
  • 1
eldarerathis
  • 35,455
  • 10
  • 90
  • 93