Intro
This article walks through several solutions for a decimal to octal number convertor coding challenge written in ruby.
Note: These solutions can be generalized for converting decimal to any base less than 10 by adding a second function parameter and replacing all 8's with the given parameter.
Solution 1: Standard Way
One simple way to convert bases is to repeatedly take the modulo of the input number and target base num % 8
then divide the input number by target basenum /= 8
until the number is empty while num > 0
. Each modulo result is either added to an array or summed into a resultant number like in the example below.
def octal_convertor(num)
octal = 0
i = 1
while num > 0
octal += (num % 8) * i
num /= 8
i *= 10
end
return octal
end
This solution uses a variable i = 1
which grows by i *= 10
on each iteration. It is used to multiply num % 8
so it goes in the next whole number place in octal += (num % 8) * i
. You can think of it like slicing off base 8 digits from num
and slotting them into the next whole number place in octal
Solution 2: Deterministic Iteration with Logarithm
The number of places(digits) in a whole number of any base(base 8 in this instance) can be calculated with Math.log(num,8).floor + 1
. This reveals how many digits need to be 'sliced' out with num % 8
, or rather the number of loop iterations required. So there is no need to check if num > 0
, we can just run a loop an exact number of times.
def octal_convertor(num)
octal = 0
(Math.log(num,8).floor + 1).times do |i|
octal += (num % 8) * 10**i
num /= 8
end
return octal
end
The .times
method accepts a block and passes iteration count to |i|
. So in addition to knowing the exact number of iterations in advance the 'i' variable in the previous solutions is provided by .times
. The |i|
increments from zero, so to slot the octal digits in the right place (num % 8)
is multiplied by 10**i
.
Solution 3: Number as an Array
This one-liner works much the same way as above but creates a new array with a length of the octal number (so there is a place for each oct digit). Similar to .times
Array.new
accepts a block where you can fill each value in the array with something, this block receives an index value |i|
.
def octal_convertor(num)
Array.new(Math.log(num,8).floor + 1) {|i| ((num / 8**i) % 8) * 10**i }.sum
end
num
is not mutably divided with num /= 8
, instead, using 'i' we calculate how many times it should have been divided num / 8**i
or rather which octal place value the current iteration is at. 10**i
works exactly the same as previously mentioned. The array now contains all oct digits multiplied by 10**i
, which provides the correct number of zeros added so when summed together they fit in the right place. .sum
adds all numbers in the array together returning the converted number.
Conclusion
Calculating number digit lengths using logarithms provides a means to determine iteration count ahead of time and iterate over enumerable objects(arrays, numbers) instead of using while loops.
Top comments (0)