Coding Challenge: Converting Integers to Binary String Representations in Ruby
Lately I've been trying to challenge myself by taking a stab at some common coding questions asked in software engineering job interviews. After years of working on apps you would think that this kind of thing comes easy, but software development in the modern age comes with a heavy side of Googling and lookup, so challenging your brain in this way to implement an algorithm or process from just its definition is good practice to keep you sharp.
I had come across a practice coding question which required me to compare integers and binary strings, and I realized that I had forgotten how to convert an integer to binary. Looking it up, the algoritm is pretty simple:
To convert integer to binary, start with the integer in question and divide it by 2 keeping notice of the quotient and the remainder. Continue dividing the quotient by 2 until you get a quotient of zero. Then just write out the remainders in the reverse order.
Angular in Depth
Here's how I implemented that in ruby.
Basically, we need to keep dividing by 2 and record the remainder, so this sounds to me like a while
loop, or even a recursive function. I'll implement both
here, and at the end, I'll show you an even easier method to use with built-in ruby methods. We will only deal with integers >= 0
, and output a string
representation of the integer written in binary. For example, an input of 9
would output "1001"
, and an input of 1337
would output "10100111001"
.
Starting with a simple test case to prove our results are correct:
Running that of course is going to fail:
So let's get to work implementing the while method. We want to take the input n and divide it by 2, but how do we do that while "keeping notice of the quotient and the remainder"? We can
get the quotient by simply running a standard divide by the integer 2, as ruby will always round down. If we divide by a float 2.0, ruby would provide a float return and we could see if the portion
to the right of the decimal was > 0
or not, but I think there is a better way using the mod
operator: %
. This mod operator only returns the remainder as an integer, not as
a fraction. Because we are dividing by 2, the remainder will always be either 1 or 0, and thus the mod will always return either 1 or 0, already conveniently in base2, or binary representation.
Line by line, we first initialize an empty array to hold the binary digits. We do a while loop over integer
while it is sill larger than 0, and on each iteration we add the remainder of a mod operation to the
empty binary array, then divide our integer by 2 for the next iteration. After we have hit 0, the binary
array will be holding all of our digits, but in the wrong order, and as integers. So we reverse
the array, then join it, which will automatically convert each array value to a string and concatenate them.
Running this through the test gives:
Ok so this works, is easy to understand, and is relatively short. Let's try to make it recursive. Whatever is in the while loop should be able to be pulled out and recursed upon. The base case would be when we have
an integer of 0 or 1, we can simply return that integer. Because we can combine the elements in the correct order as part of our recursive step, we don't need an array, and will call to_s
on the base
case and the remainder to always return a correct binary string representation.
Running this through the test also gives correct results:
Let's expand our testing a little bit by checking all numbers 0 through n
, and testing them out. How can we test for correctness without manually typing out each value's string representation? Here
is where I show you the much easier built-in method for converting that already exists in ruby. Are you ready for it?
A ruby Integer
has the ability to change its base through the to_s
method. To convert an integer to binary, being base 2, you simply call .to_s(2)
to get the binary string representation.
Knowing this, we can write a test suite to check the correctness of our method much more exhaustively, with over 1 million checks.
Running this, we spot an error! Turns out the while loop method fails for 0. Let's add a simple check for that edge case:
Running the fix, we are all good now.
So, the recursive method is about twice as fast as the iterative one, but how does they compare to the native method? Let's add a third method convert_to_binary_native
and run the tests again.
Ruby's implementation is faster by an order of magnitude. Their implementation of to_s
on a Fixnum
bubbles down a couple of lower level methods until it hits a core
C
function in the numeric.c source. It's been awhile since I've worked in C
, but
it appears that there is a base case when the number is 0, then a do/while loop which the current digit is shifted and modded by the base. This method is essentially what we have in our convert_to_binary
method as defined above, but is obviously much faster as it is written in pure C
.
Was this page helpful for you? Buy me a slice of 🍕 to say thanks!
Comments