🎉 Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io 🎉
Avatar of Zorica

Zorica's solution

to All Your Base in the Delphi Pascal Track

Published at Oct 30 2018 · 0 comments
Instructions
Test suite
Solution

Note:

This exercise has changed since this solution was written.

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!

Testing

In order to run the tests for this track, you will need to install DUnitX. Please see the installation instructions for more information.

Loading Exercises into Delphi

If Delphi is properly installed, and *.dpr file types have been associated with Delphi, then double clicking the supplied *.dpr file will start Delphi and load the exercise/project. control + F9 is the keyboard shortcut to compile the project or pressing F9 will compile and run the project.

Alternatively you may opt to start Delphi and load your project via. the File drop down menu.

When Questions Come Up

We monitor the Pascal-Delphi support room on gitter.im to help you with any questions that might arise.

Submitting Exercises

Note that, when trying to submit an exercise, make sure the exercise file you're submitting is in the exercism/delphi/<exerciseName> directory.

For example, if you're submitting ubob.pas for the Bob exercise, the submit command would be something like exercism submit <path_to_exercism_dir>/delphi/bob/ubob.pas.

Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you may receive assistance from a mentor.

uAllYourBaseTest.pas

unit uAllYourBaseTest;

interface
uses
  DUnitX.TestFramework, System.SysUtils;

const
  CanonicalVersion = '2.3.0';

type
  [TestFixture]
  TAllYourBaseTest = class(TObject)
  private
    procedure CompareArrays(Array1, Array2: TArray<integer>);
  public
    [Test]
//    [Ignore('Comment the "[Ignore]" statement to run the test')]
    procedure single_bit_one_to_decimal;

    [Test]
    [Ignore]
    procedure binary_to_single_decimal;

    [Test]
    [Ignore]
    procedure single_decimal_to_binary;

    [Test]
    [Ignore]
    procedure binary_to_multiple_decimal;

    [Test]
    [Ignore]
    procedure decimal_to_binary;

    [Test]
    [Ignore]
    procedure trinary_to_hexadecimal;

    [Test]
    [Ignore]
    procedure hexadecimal_to_trinary;

    [Test]
    [Ignore]
    procedure integer_15_bit;

    [Test]
    [Ignore]
    procedure empty_list;

    [Test]
    [Ignore]
    procedure single_zero;

    [Test]
    [Ignore]
    procedure multiple_zeros;

    [Test]
    [Ignore]
    procedure leading_zeros;

    [Test]
    [Ignore]
    procedure input_base_is_one;

    [Test]
    [Ignore]
    procedure input_base_is_zero;

    [Test]
    [Ignore]
    procedure input_base_is_negative;

    [Test]
    [Ignore]
    procedure negative_digit;

    [Test]
    [Ignore]
    procedure invalid_positive_digit;

    [Test]
    [Ignore]
    procedure output_base_is_one;

    [Test]
    [Ignore]
    procedure output_base_is_zero;

    [Test]
    [Ignore]
    procedure output_base_is_negative;

    [Test]
    [Ignore]
    procedure both_bases_are_negative;
  end;

implementation
uses uAllYourBase;

procedure TAllYourBaseTest.binary_to_multiple_decimal;
begin
  CompareArrays([4, 2], TBase.Rebase(2, [1, 0, 1, 0, 1, 0], 10));
end;

procedure TAllYourBaseTest.binary_to_single_decimal;
begin
  CompareArrays([5], TBase.Rebase(2, [1, 0, 1], 10));
end;

procedure TAllYourBaseTest.both_bases_are_negative;
begin
  Assert.WillRaise(procedure
    begin
      TBase.Rebase(-2, [1], -7);
    end, EArgumentOutOfRangeException, 'input base must be >= 2');
end;

procedure TAllYourBaseTest.CompareArrays(Array1, Array2: TArray<integer>);
var
  i: integer;
begin
  Assert.AreEqual(Length(Array1), Length(Array2), ' - Array lengths must be equal');
  for i := Low(Array1) to High(Array1) do
    Assert.AreEqual(Array1[i], Array2[i], format('Expecting element %d to = %d, Actual = %d',
      [i, Array1[i], Array2[i]]));
end;

procedure TAllYourBaseTest.decimal_to_binary;
begin
  CompareArrays([1, 0, 1, 0, 1, 0], TBase.Rebase(10, [4, 2], 2));
end;

procedure TAllYourBaseTest.empty_list;
begin
  CompareArrays([0], TBase.Rebase(2, [], 10));
end;

procedure TAllYourBaseTest.hexadecimal_to_trinary;
begin
  CompareArrays([1, 1, 2, 0], TBase.Rebase(16, [2, 10], 3));
end;

procedure TAllYourBaseTest.input_base_is_negative;
begin
  Assert.WillRaise(procedure
    begin
      TBase.Rebase(-2, [1], 10);
    end, EArgumentOutOfRangeException, 'input base must be >= 2');
end;

procedure TAllYourBaseTest.input_base_is_one;
begin
  Assert.WillRaise(procedure
    begin
      TBase.Rebase(1, [0], 10);
    end, EArgumentOutOfRangeException, 'input base must be >= 2');
end;

procedure TAllYourBaseTest.input_base_is_zero;
begin
  Assert.WillRaise(procedure
    begin
      TBase.Rebase(0, [0], 10);
    end, EArgumentOutOfRangeException, 'input base must be >= 2');
end;

procedure TAllYourBaseTest.integer_15_bit;
begin
  CompareArrays([6, 10, 45], TBase.Rebase(97, [3, 46, 60], 73));
end;

procedure TAllYourBaseTest.invalid_positive_digit;
begin
  Assert.WillRaise(procedure
    begin
      TBase.Rebase(2, [1, 2, 1, 0, 1, 0], 10);
    end, EArgumentOutOfRangeException, 'all digits must satisfy 0 <= d < input base');
end;

procedure TAllYourBaseTest.leading_zeros;
begin
  CompareArrays([4, 2], TBase.Rebase(7, [0, 6, 0], 10));
end;

procedure TAllYourBaseTest.multiple_zeros;
begin
  CompareArrays([0], TBase.Rebase(10, [0, 0, 0], 2));
end;

procedure TAllYourBaseTest.negative_digit;
begin
  Assert.WillRaise(procedure
    begin
      TBase.Rebase(2, [1, -1, 1, 0, 1, 0], 10);
    end, EArgumentOutOfRangeException, 'all digits must satisfy 0 <= d < input base');
end;

procedure TAllYourBaseTest.output_base_is_negative;
begin
  Assert.WillRaise(procedure
    begin
      TBase.Rebase(2, [1], -7);
    end, EArgumentOutOfRangeException, 'output base must be >= 2');
end;

procedure TAllYourBaseTest.output_base_is_one;
begin
  Assert.WillRaise(procedure
    begin
      TBase.Rebase(2, [1, 0, 1, 0, 1, 0], 1);
    end, EArgumentOutOfRangeException, 'output base must be >= 2');
end;

procedure TAllYourBaseTest.output_base_is_zero;
begin
  Assert.WillRaise(procedure
    begin
      TBase.Rebase(10, [7], 0);
    end, EArgumentOutOfRangeException, 'output base must be >= 2');
end;

procedure TAllYourBaseTest.single_bit_one_to_decimal;
begin
  CompareArrays([1], TBase.Rebase(2, [1], 10));
end;

procedure TAllYourBaseTest.single_decimal_to_binary;
begin
  CompareArrays([1, 0, 1], TBase.Rebase(10, [5], 2));
end;

procedure TAllYourBaseTest.single_zero;
begin
  CompareArrays([0], TBase.Rebase(10, [0], 2));
end;

procedure TAllYourBaseTest.trinary_to_hexadecimal;
begin
  CompareArrays([2, 10], TBase.Rebase(3, [1, 1, 2, 0], 16));
end;

initialization
  TDUnitX.RegisterTestFixture(TAllYourBaseTest);
end.
unit uAllYourBase;

interface

uses
  System.SysUtils,System.Generics.Collections, System.math;

type
  EArgumentOutOfRangeException = class(Exception);

  TBase = class
  public
    class function Rebase(AInpBase : Integer; ADigits : TArray<Integer>; AOutBase : integer) : TArray<Integer>;
  end;

implementation

{ TBase }

class function TBase.Rebase(AInpBase : Integer; ADigits : TArray<Integer>; AOutBase : integer): TArray<Integer>;
var
  i: Integer;
  Dig : Integer;
  a : TList<integer>;
begin
  if AOutBase < 2 then
    raise EArgumentOutOfRangeException.Create('output base must be >= 2');
  if not (AInpBase >= 2) then
    raise EArgumentOutOfRangeException.Create('input base must be >= 2');
  dig := 0;
  for I := low(ADigits) to high(ADigits) do
  begin
    if (ADigits[i] < 0) or (ADigits[i] >= AInpBase)  then
    raise EArgumentOutOfRangeException.Create('all digits must satisfy 0 <= d < input base');
    Dig := Round(dig + ADigits[i] * Power(AInpBase, (High(ADigits)- i)));
  end;
  if (Length(ADigits) = 0) or (dig = 0)  then
  begin
    Result := [0];
    exit
  end;
  a := TList<Integer>.Create;
  while dig > 0 do
  begin
    a.Add(dig mod AOutBase);
    dig := dig div AOutBase;
  end;
  a.Reverse;
  Result := a.ToArray;
end;

end.

Community comments

Find this solution interesting? Ask the author a question to learn more.

What can you learn from this solution?

A huge amount can be learned from reading other people’s code. This is why we wanted to give exercism users the option of making their solutions public.

Here are some questions to help you reflect on this solution and learn the most from it.

  • What compromises have been made?
  • Are there new concepts here that you could read more about to improve your understanding?