# 4d47's solution

## to All Your Base in the Perl 6 Track

Published at Jul 13 2018 · 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.

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!

## Resources

Remember to check out the Perl 6 documentation and resources pages for information, tips, and examples if you get stuck.

## Running the tests

There is a test suite and module included with the exercise. The test suite (a file with the extension `.t`) will attempt to run routines from the module (a file with the extension `.pm6`). Add/modify routines in the module so that the tests will pass! You can view the test data by executing the command `perl6 --doc *.t` (* being the name of the test suite), and run the test suite for the exercise by executing the command `prove6 .` in the exercise directory.

## Submitting Incomplete Solutions

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

### all-your-base.t

``````#!/usr/bin/env perl6
use v6;
use Test;
use JSON::Fast;
use lib \$?FILE.IO.dirname;
use AllYourBase;
plan 21;

my \$c-data = from-json \$=pod.pop.contents;
for \$c-data<cases>.values -> \$case {
sub call-convert-base {
convert-base(
bases  => %(<from to> Z=> .<input><inputBase outputBase>),
digits => .<input><digits>,
) given \$case;
}

given \$case {
if .<expected><error> {
throws-like {call-convert-base}, Exception, .<description>;
}
else {
cmp-ok call-convert-base, ‘~~’, |.<expected description>;
}
}
}

=begin code
{
"exercise": "all-your-base",
"version": "2.3.0",
"This canonical data makes the following choices:",
"1. Zero is always represented in outputs as [0] instead of [].",
"2. In no other instances are leading zeroes present in any outputs.",
"3. Leading zeroes are accepted in inputs.",
"4. An empty sequence of input digits is considered zero, rather than an error.",
"",
"Tracks that wish to make different decisions for these choices may translate appropriately.",
"",
"All your numeric-base are belong to [2..]. :)"
],
"cases": [
{
"description": "single bit one to decimal",
"property": "rebase",
"input": {
"inputBase": 2,
"digits": [1],
"outputBase": 10
},
"expected": [1]
},
{
"description": "binary to single decimal",
"property": "rebase",
"input": {
"inputBase": 2,
"digits": [1, 0, 1],
"outputBase": 10
},
"expected": [5]
},
{
"description": "single decimal to binary",
"property": "rebase",
"input": {
"inputBase": 10,
"digits": [5],
"outputBase": 2
},
"expected": [1, 0, 1]
},
{
"description": "binary to multiple decimal",
"property": "rebase",
"input": {
"inputBase": 2,
"digits": [1, 0, 1, 0, 1, 0],
"outputBase": 10
},
"expected": [4, 2]
},
{
"description": "decimal to binary",
"property": "rebase",
"input": {
"inputBase": 10,
"digits": [4, 2],
"outputBase": 2
},
"expected": [1, 0, 1, 0, 1, 0]
},
{
"property": "rebase",
"input": {
"inputBase": 3,
"digits": [1, 1, 2, 0],
"outputBase": 16
},
"expected": [2, 10]
},
{
"property": "rebase",
"input": {
"inputBase": 16,
"digits": [2, 10],
"outputBase": 3
},
"expected": [1, 1, 2, 0]
},
{
"description": "15-bit integer",
"property": "rebase",
"input": {
"inputBase": 97,
"digits": [3, 46, 60],
"outputBase": 73
},
"expected": [6, 10, 45]
},
{
"description": "empty list",
"property": "rebase",
"input": {
"inputBase": 2,
"digits": [],
"outputBase": 10
},
"expected": [0]
},
{
"description": "single zero",
"property": "rebase",
"input": {
"inputBase": 10,
"digits": [0],
"outputBase": 2
},
"expected": [0]
},
{
"description": "multiple zeros",
"property": "rebase",
"input": {
"inputBase": 10,
"digits": [0, 0, 0],
"outputBase": 2
},
"expected": [0]
},
{
"property": "rebase",
"input": {
"inputBase": 7,
"digits": [0, 6, 0],
"outputBase": 10
},
"expected": [4, 2]
},
{
"description": "input base is one",
"property": "rebase",
"input": {
"inputBase": 1,
"digits": [0],
"outputBase": 10
},
"expected": {"error": "input base must be >= 2"}
},
{
"description": "input base is zero",
"property": "rebase",
"input": {
"inputBase": 0,
"digits": [],
"outputBase": 10
},
"expected": {"error": "input base must be >= 2"}
},
{
"description": "input base is negative",
"property": "rebase",
"input": {
"inputBase": -2,
"digits": [1],
"outputBase": 10
},
"expected": {"error": "input base must be >= 2"}
},
{
"description": "negative digit",
"property": "rebase",
"input": {
"inputBase": 2,
"digits": [1, -1, 1, 0, 1, 0],
"outputBase": 10
},
"expected": {"error": "all digits must satisfy 0 <= d < input base"}
},
{
"description": "invalid positive digit",
"property": "rebase",
"input": {
"inputBase": 2,
"digits": [1, 2, 1, 0, 1, 0],
"outputBase": 10
},
"expected": {"error": "all digits must satisfy 0 <= d < input base"}
},
{
"description": "output base is one",
"property": "rebase",
"input": {
"inputBase": 2,
"digits": [1, 0, 1, 0, 1, 0],
"outputBase": 1
},
"expected": {"error": "output base must be >= 2"}
},
{
"description": "output base is zero",
"property": "rebase",
"input": {
"inputBase": 10,
"digits": [7],
"outputBase": 0
},
"expected": {"error": "output base must be >= 2"}
},
{
"description": "output base is negative",
"property": "rebase",
"input": {
"inputBase": 2,
"digits": [1],
"outputBase": -7
},
"expected": {"error": "output base must be >= 2"}
},
{
"description": "both bases are negative",
"property": "rebase",
"input": {
"inputBase": -2,
"digits": [1],
"outputBase": -7
},
"expected": {"error": "input base must be >= 2"}
}
]
}
=end code``````
``````unit module AllYourBase:ver<2>;

sub convert-base(Int:D \$input-base, List \$digits, Int:D \$output-base --> List) is export {
die if \$input-base < 2;
return \$digits if not \$digits;
to-digits(from-digits(\$digits, \$input-base), \$output-base)
}

sub from-digits(List \$digits, Int \$base --> Int) {
die if not \$digits;
die if \$digits.grep( * < 0 );
die if \$digits.grep( * >= \$base );
(\$digits.values Z \$digits.keys.reverse).flat.map({ \$^a * \$base ** \$^b }).sum
}

sub to-digits(Int \$n is copy, Int \$base --> List) {
my \$digits = [];
while \$n > 0 {
\$digits.unshift: \$n % \$base;
\$n div= \$base;
}
\$digits || [0]
}``````