# alkhulaifi's solution

## to All Your Base in the Elixir Track

Published at Jul 07 2020 · 0 comments
Instructions
Test suite
Solution

Convert a number, represented as a sequence of digits in one base, to any other base.

Implement general base conversion. Given a number in base a, represented as a sequence of digits, convert it to base b.

## Note

• Try to implement the conversion yourself. Do not use something else to perform the conversion for you.

## About Positional Notation

In positional notation, a number in base b can be understood as a linear combination of powers of b.

The number 42, in base 10, means:

(4 * 10^1) + (2 * 10^0)

The number 101010, in base 2, means:

(1 * 2^5) + (0 * 2^4) + (1 * 2^3) + (0 * 2^2) + (1 * 2^1) + (0 * 2^0)

The number 1120, in base 3, means:

(1 * 3^3) + (1 * 3^2) + (2 * 3^1) + (0 * 3^0)

I think you got the idea!

Yes. Those three numbers above are exactly the same. Congratulations!

## Running tests

Execute the tests with:

``````\$ mix test
``````

### Pending tests

In the test suites, all but the first test have been skipped.

Once you get a test passing, you can unskip the next one by commenting out the relevant `@tag :pending` with a `#` symbol.

For example:

``````# @tag :pending
test "shouting" do
assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end
``````

Or, you can enable all the tests by commenting out the `ExUnit.configure` line in the test suite.

``````# ExUnit.configure exclude: :pending, trace: true
``````

If you're stuck on something, it may help to look at some of the available resources out there where answers might be found.

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

### all_your_base_test.exs

``````defmodule AllYourBaseTest do
use ExUnit.Case

test "convert single bit one to decimal" do
assert AllYourBase.convert([1], 2, 10) == [1]
end

@tag :pending
test "convert binary to single decimal" do
assert AllYourBase.convert([1, 0, 1], 2, 10) == [5]
end

@tag :pending
test "convert single decimal to binary" do
assert AllYourBase.convert([5], 10, 2) == [1, 0, 1]
end

@tag :pending
test "convert binary to multiple decimal" do
assert AllYourBase.convert([1, 0, 1, 0, 1, 0], 2, 10) == [4, 2]
end

@tag :pending
test "convert decimal to binary" do
assert AllYourBase.convert([4, 2], 10, 2) == [1, 0, 1, 0, 1, 0]
end

@tag :pending
test "convert trinary to hexadecimal" do
assert AllYourBase.convert([1, 1, 2, 0], 3, 16) == [2, 10]
end

@tag :pending
test "convert hexadecimal to trinary" do
assert AllYourBase.convert([2, 10], 16, 3) == [1, 1, 2, 0]
end

@tag :pending
test "convert 15-bit integer" do
assert AllYourBase.convert([3, 46, 60], 97, 73) == [6, 10, 45]
end

@tag :pending
test "convert empty list" do
assert AllYourBase.convert([], 2, 10) == nil
end

@tag :pending
test "convert single zero" do
assert AllYourBase.convert([0], 10, 2) == [0]
end

@tag :pending
test "convert multiple zeros" do
assert AllYourBase.convert([0, 0, 0], 10, 2) == [0]
end

@tag :pending
test "convert leading zeros" do
assert AllYourBase.convert([0, 6, 0], 7, 10) == [4, 2]
end

@tag :pending
test "convert first base is one" do
assert AllYourBase.convert([0], 1, 10) == nil
end

@tag :pending
test "convert first base is zero" do
assert AllYourBase.convert([], 0, 10) == nil
end

@tag :pending
test "convert first base is negative" do
assert AllYourBase.convert([1], -2, 10) == nil
end

@tag :pending
test "convert negative digit" do
assert AllYourBase.convert([1, -1, 1, 0, 1, 0], 2, 10) == nil
end

@tag :pending
test "convert invalid positive digit" do
assert AllYourBase.convert([1, 2, 1, 0, 1, 0], 2, 10) == nil
end

@tag :pending
test "convert second base is one" do
assert AllYourBase.convert([1, 0, 1, 0, 1, 0], 2, 1) == nil
end

@tag :pending
test "convert second base is zero" do
assert AllYourBase.convert([7], 10, 0) == nil
end

@tag :pending
test "convert second base is negative" do
assert AllYourBase.convert([1], 2, -7) == nil
end

@tag :pending
test "convert both bases are negative" do
assert AllYourBase.convert([1], -2, -7) == nil
end
end``````

### test_helper.exs

``````ExUnit.start()
ExUnit.configure(exclude: :pending, trace: true)``````
``````defmodule AllYourBase do
@doc """
Given a number in base a, represented as a sequence of digits, converts it to base b,
or returns nil if either of the bases are less than 2
"""

@spec convert(list, integer, integer) :: list | nil
def convert(digits, base_a, base_b) when base_a > 1 and base_b > 1 and length(digits) > 0 do
digits
|> to_integer(base_a)
|> to_digits(base_b)
end

@spec convert(list, integer, integer) :: list | nil
def convert(_, _, _) do nil end

@spec to_integer(integer, integer) :: list | nil
def to_integer(digits, base) do
if Enum.any?(digits, &(&1<0)) or Enum.any?(digits, &(&1>=base)) do
nil
else
digits
|> Enum.reverse()
|> Enum.zip(0..length(digits))
|> Enum.reduce(0, fn {x,n}, acc -> trunc(x*:math.pow(base,n)) + acc end)
end
end

@spec to_digits(integer, integer, integer) :: list | nil
def to_digits(number, base, n \\ 1)

def to_digits(nil, _, _) do nil end

def to_digits(number, base, n) do
p = trunc(:math.pow(base,n))
x = div(number, p)
r = div(rem(number, p), trunc(:math.pow(base,n-1)))
if x == 0 do
[r]
else
to_digits(number-r,base,n+1) ++ [r]
end
end

end``````