This is an exercise on the website Exercism. I am self taught trying to learn C# and C++. This is the information from the readme.
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!
Following script is my solution to the exercise.
using System;
using System.Collections.Generic;
using System.Linq;
public static class AllYourBase
{
private static void RebaseIsException(int inputBase, int[] digits, int outputBase)
{
if (digits is null)
throw new ArgumentNullException(nameof(digits));
if (inputBase <= 1)
throw new ArgumentException(nameof(inputBase));
if (digits.Any(e => e < 0))
throw new ArgumentException(nameof(digits));
if (digits.Any(e => e >= inputBase))
throw new ArgumentException(nameof(inputBase), nameof(digits));
if (outputBase <= 1)
throw new ArgumentException(nameof(outputBase));
if (inputBase <= 0 && outputBase <= 0)
throw new ArgumentException(nameof(inputBase), nameof(outputBase));
}
public static bool RebaseIsDigitsEmptyOrZero(int[] digits) => digits.Sum() == 0;
public static int[] RebaseSolution(int inputBase, int[] digits, int outputBase)
{
int number = 0;
List<int> list = new List<int>();
foreach (int i in digits)
number = number * inputBase + i;
do
{
list.Add(number % outputBase);
} while ((number /= outputBase) != 0);
list.Reverse();
return list.ToArray();
}
public static int[] Rebase(int inputBase, int[] digits, int outputBase)
{
RebaseIsException(inputBase, digits, outputBase);
return RebaseIsDigitsEmptyOrZero(digits) ? new int[] { 0 } : RebaseSolution(inputBase, digits, outputBase);
}
}
Next, is the test case for this exercise.
// This file was auto-generated based on version 2.3.0 of the canonical data.
using System;
using Xunit;
public class AllYourBaseTest
{
[Fact]
public void Single_bit_one_to_decimal()
{
var inputBase = 2;
var digits = new[] { 1 };
var outputBase = 10;
var expected = new[] { 1 };
Assert.Equal(expected, AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Binary_to_single_decimal()
{
var inputBase = 2;
var digits = new[] { 1, 0, 1 };
var outputBase = 10;
var expected = new[] { 5 };
Assert.Equal(expected, AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Single_decimal_to_binary()
{
var inputBase = 10;
var digits = new[] { 5 };
var outputBase = 2;
var expected = new[] { 1, 0, 1 };
Assert.Equal(expected, AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Binary_to_multiple_decimal()
{
var inputBase = 2;
var digits = new[] { 1, 0, 1, 0, 1, 0 };
var outputBase = 10;
var expected = new[] { 4, 2 };
Assert.Equal(expected, AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Decimal_to_binary()
{
var inputBase = 10;
var digits = new[] { 4, 2 };
var outputBase = 2;
var expected = new[] { 1, 0, 1, 0, 1, 0 };
Assert.Equal(expected, AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Trinary_to_hexadecimal()
{
var inputBase = 3;
var digits = new[] { 1, 1, 2, 0 };
var outputBase = 16;
var expected = new[] { 2, 10 };
Assert.Equal(expected, AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Hexadecimal_to_trinary()
{
var inputBase = 16;
var digits = new[] { 2, 10 };
var outputBase = 3;
var expected = new[] { 1, 1, 2, 0 };
Assert.Equal(expected, AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Number_15_bit_integer()
{
var inputBase = 97;
var digits = new[] { 3, 46, 60 };
var outputBase = 73;
var expected = new[] { 6, 10, 45 };
Assert.Equal(expected, AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Empty_list()
{
var inputBase = 2;
var digits = Array.Empty<int>();
var outputBase = 10;
var expected = new[] { 0 };
Assert.Equal(expected, AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Single_zero()
{
var inputBase = 10;
var digits = new[] { 0 };
var outputBase = 2;
var expected = new[] { 0 };
Assert.Equal(expected, AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Multiple_zeros()
{
var inputBase = 10;
var digits = new[] { 0, 0, 0 };
var outputBase = 2;
var expected = new[] { 0 };
Assert.Equal(expected, AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Leading_zeros()
{
var inputBase = 7;
var digits = new[] { 0, 6, 0 };
var outputBase = 10;
var expected = new[] { 4, 2 };
Assert.Equal(expected, AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Input_base_is_one()
{
var inputBase = 1;
var digits = new[] { 0 };
var outputBase = 10;
Assert.Throws<ArgumentException>(() => AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Input_base_is_zero()
{
var inputBase = 0;
var digits = Array.Empty<int>();
var outputBase = 10;
Assert.Throws<ArgumentException>(() => AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Input_base_is_negative()
{
var inputBase = -2;
var digits = new[] { 1 };
var outputBase = 10;
Assert.Throws<ArgumentException>(() => AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Negative_digit()
{
var inputBase = 2;
var digits = new[] { 1, -1, 1, 0, 1, 0 };
var outputBase = 10;
Assert.Throws<ArgumentException>(() => AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Invalid_positive_digit()
{
var inputBase = 2;
var digits = new[] { 1, 2, 1, 0, 1, 0 };
var outputBase = 10;
Assert.Throws<ArgumentException>(() => AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Output_base_is_one()
{
var inputBase = 2;
var digits = new[] { 1, 0, 1, 0, 1, 0 };
var outputBase = 1;
Assert.Throws<ArgumentException>(() => AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Output_base_is_zero()
{
var inputBase = 10;
var digits = new[] { 7 };
var outputBase = 0;
Assert.Throws<ArgumentException>(() => AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Output_base_is_negative()
{
var inputBase = 2;
var digits = new[] { 1 };
var outputBase = -7;
Assert.Throws<ArgumentException>(() => AllYourBase.Rebase(inputBase, digits, outputBase));
}
[Fact]
public void Both_bases_are_negative()
{
var inputBase = -2;
var digits = new[] { 1 };
var outputBase = -7;
Assert.Throws<ArgumentException>(() => AllYourBase.Rebase(inputBase, digits, outputBase));
}
}
I was able to without effort come up with RebaseIsException to pass the test that wants you to throw new ArgumentException. Few other test where passed using RebaseIsDigitsEmptyOrZero. I had to borrow from a few sites to come up with what you see in RebaseSolution. In particular the foreach loop and the do/while loop to get the solution. I kind of stumbled into passing this after a few days of spending a few minutes on it each night, with most the time just in this one function.
Anyhow, I would be grateful and appreciate whatever feedback to help me continue to learn. Thank you!
if (inputBase <= 0 && outputBase <= 0)
Just FYI this can never happen. If the input base is negative it'll already have thrown anArgumentException
, same for the output base. \$\endgroup\$