Deterministic Base Conversion with Logarithms
Tags: ruby, programming, algorithms, tutorial
Published: 2022-05-14 05:38:35

##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 base`num /= 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.
```ruby
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.
````ruby
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|`.
```ruby
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.