3

I'm working on a codewars kata and stuck with 2 test cases that are failing.

The kata description is: Convert integers to binary as simple as that. You would be given an integer as a argument and you have to return its binary form. To get an idea about how to convert a decimal number into a binary number, visit here.

Notes: negative numbers should be handled as two's complement; assume all numbers are integers stored using 4 bytes (or 32 bits) in any language.

My code:

def to_binary(n)
  temp_array = []
  if n == 0
    temp_array << 0
  elsif n < 0
    n = n % 256
    while n > 0 do
      temp_array << (n % 2)
      n = (n / 2)
    end
    while temp_array.length < 32 do
      temp_array << 1
    end
  else
    while n > 0 do
      temp_array << (n % 2)
      n = (n / 2)
    end
  end
  binary = temp_array.reverse.join
end

The test cases are:

Test Passed: Value == "10"
Test Passed: Value == "11"
Test Passed: Value == "100"
Test Passed: Value == "101"
Test Passed: Value == "111"
Test Passed: Value == "1010"
Test Passed: Value == "11111111111111111111111111111101"
Test Passed: Value == "0"
Test Passed: Value == "1111101000"
Test Passed: Value == "11111111111111111111111111110001"
Expected: "11111111111111111111110000011000", instead got: "11111111111111111111111111111000"
Expected: "11111111111100001011110111000001", instead got: "11111111111111111111111111000001"
Test Passed: Value == "11110100001000111111"

I suspect the tests that are failing are with negative integers because the first failing test's expected output is 11111111111111111111110000011000 which means that either the positive argument value was 4294966296 or it was negative. If I run to_binary(4294966296) I get the expected output.

6
  • 2
    I assume you want to write the algorithm, even though ruby has a built-in conversion `10.to_s(2) => "1010"' Commented Jul 3, 2015 at 18:02
  • 1
    @500_error except that (-10).to_s(2) => "-1010" Commented Jul 3, 2015 at 18:04
  • @lurker Considering negative binary values don't really exist, that's a reasonable interpretation. A common notation for representing these is Two's Notation but that's hardly the only way to do it. Commented Jul 3, 2015 at 18:17
  • @tadman sure, but I'm saying it doesn't solve the OP's problem looking for a 32-bit 2's complement result. Commented Jul 3, 2015 at 18:18
  • Ah just saw that part. Nothing you can't fix with some manipulation to offset the value prior to to_s(2). Commented Jul 3, 2015 at 18:18

2 Answers 2

8

I am not fond of this approach since I'm sure there's an even more clever and/or compact, Ruby-esque way of accomplishing it. But using your method of loading binary digits into an array, and then joining, what you have can be done in a little more straight-forward fashion:

def to_binary(n)
  return "0" if n == 0

  r = []

  32.times do
    if (n & (1 << 31)) != 0
      r << 1
    else
      (r << 0) if r.size > 0
    end
    n <<= 1
  end

  r.join
end

Or, using @500_error's suggestion:

def to_binary(n)
  if n >= 0
    n.to_s(2)
  else
    31.downto(0).map { |b| n[b] }.join
  end
end

The asymmetry to deal with negative versus non-negative is a little annoying, though. You could do something like:

def to_binary(n)
  31.downto(0).map { |b| n[b] }.join.sub(/^0*/, "")
end
Sign up to request clarification or add additional context in comments.

7 Comments

32.downto(0).map { |n| -4294966296[n] }.join => "100000000000000000000001111101000"
@500_error yes, that's quite nice. The only remaining issue is that, for example, 32.downto(0).map { |n| 2[n] }.join => "00000000000000000000000000000010" but the OP expects "10".
Ya, It's clever, but not sure if it is a good answer for OP's use case. There should be some bit shifting so the conversion is understood.
Thank you @lurker and @500_error, this worked with one minor change: ruby def to_binary(n) if n >= 0 n.to_s(2) else 31.downto(0).map { |b| n[b] }.join end end The original method was allowing the method to return up to 33 bits instead of 32. This method is also way shorter than what I had. I'm still new to ruby and will be dissecting this method to better understand it. :) Thank you!
|
1

This is not a traditional algorithm to generate 2's complement, so I am not sure if it helps you in understanding binary conversion, but you can do this in ruby to help check your answers.

Note: This applies to negative number's only.

32.downto(0).map { |n| -4294966296[n] }.join
=> "100000000000000000000001111101000"

For 2's complement computation, it's best to implement using a lower level language like C, to get a sense of the algorithm. The clever approaches mask the steps and just give you an answer.

Suppose we're working with 8 bits (for simplicity's sake) and suppose we want to find how -28 would be expressed in two's complement notation.

  1. First we write out 28 in binary form. 00011100

  2. Then we invert the digits. 0 becomes 1, 1 becomes 0. 11100011

  3. Then we add 1. 11100100

3 Comments

+1 for that nice expression. 32.downto(0).map { |n| 2[n] }.join => "00000000000000000000000000000010" yields ""00000000000000000000000000000010" instead of "10". Perhaps there's a minor mod to this nice approach that fixes it.
@lurker you could just convert to an integer to squash leading zeros...x = 2; 32.downto(0).map { |n| x[n] }.join.to_i and if you insist on the result being a string, just convert it back x = 2; 32.downto(0).map { |n| x[n] }.join.to_i.to_s
@SteveTurczyn yep, absolutely right. I'm assuming the OP required a string output (since they wanted the output as a "binary" representation).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.