Skip to content

Commit

Permalink
Merge pull request #2 from rocher/develop
Browse files Browse the repository at this point in the history
Add gcd and lcm functions
  • Loading branch information
rocher authored Dec 8, 2023
2 parents abbebcb + 9aa8fb9 commit e7bbfe0
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 4 deletions.
2 changes: 1 addition & 1 deletion alire.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "euler_tools"
description = "Assortment of mathematical functions to solve Project Euler problems."
version = "1.2.1"
version = "1.3.0"

authors = ["Francesc Rocher"]
maintainers = ["Francesc Rocher <[email protected]>"]
Expand Down
66 changes: 66 additions & 0 deletions src/euler_package.adb
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,40 @@ package body Euler_Package is
return Term_N;
end Fibonacci_Next;

-----------------------------
-- Greatest_Common_Divisor --
-----------------------------

function Greatest_Common_Divisor (A, B : Int_Type) return Int_Type is
Zero : Int_Type := Int_Type'Min (A, B);
Tmp : Int_Type;
begin
return Gcd : Int_Type := Int_Type'Max (A, B) do
loop
exit when Zero = 0;
Tmp := Zero;
Zero := Gcd mod Zero;
Gcd := Tmp;
end loop;
end return;
end Greatest_Common_Divisor;

-----------------------------
-- Greatest_Common_Divisor --
-----------------------------

function Greatest_Common_Divisor (List : List_Type) return Int_Type is
Cursor : List_Package.Cursor := List.First.Next;
begin
return Gcd : Int_Type := List.First_Element do
loop
exit when not Cursor.Has_Element;
Gcd := Greatest_Common_Divisor (Gcd, Cursor.Element);
Cursor := Cursor.Next;
end loop;
end return;
end Greatest_Common_Divisor;

--------------
-- Hundreds --
--------------
Expand Down Expand Up @@ -350,6 +384,38 @@ package body Euler_Package is
return True;
end Is_Prime;

---------------------------
-- Least_Common_Multiple --
---------------------------

function Least_Common_Multiple (A, B : Int_Type) return Int_Type is
Min : constant Int_Type := Int_Type'Min (A, B);
Max : constant Int_Type := Int_Type'Max (A, B);
Gcd : constant Int_Type := Greatest_Common_Divisor (A, B);
begin
return Lcm : Int_Type := Min do
if Gcd /= 0 then
Lcm := Min * (Max / Gcd);
end if;
end return;
end Least_Common_Multiple;

---------------------------
-- Least_Common_Multiple --
---------------------------

function Least_Common_Multiple (List : List_Type) return Int_Type is
Cursor : List_Package.Cursor := List.First;
begin
return Lcm : Int_Type := List.First_Element do
loop
exit when not Cursor.Has_Element;
Lcm := Least_Common_Multiple (Lcm, Cursor.Element);
Cursor := Cursor.Next;
end loop;
end return;
end Least_Common_Multiple;

----------
-- Left --
----------
Expand Down
17 changes: 17 additions & 0 deletions src/euler_package.ads
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,14 @@ package Euler_Package is
function Fibonacci_Next return Int_Type;
-- Returns the next Fibonacci number.

function Greatest_Common_Divisor (A, B : Int_Type) return Int_Type;
-- Returns the greatest common divisor of A, B, also known as Gcd (A, B).

function Greatest_Common_Divisor (List : List_Type) return Int_Type with
Pre => not List.Is_Empty;
-- Returns the Gcd of all numbers in the list using the formula
-- Gcd ({Ai}) = Gcd (A1, Gcd (A2, Gcd ( ... ))).

function Hundreds (Number : Int_Type) return Int_Type;
-- Returns the hundreds of Number.

Expand Down Expand Up @@ -176,6 +184,15 @@ package Euler_Package is
function Is_Prime (Number : Int_Type) return Boolean;
-- Returns True if Number is prime.

function Least_Common_Multiple (A, B : Int_Type) return Int_Type;
-- Returns the least common multiple computed with the formula
-- Lcm (A, B) = Min (A, B) * (Max (A, B) / Gcd(A, B))

function Least_Common_Multiple (List : List_Type) return Int_Type with
Pre => not List.Is_Empty;
-- Returns the leas common multiple of all numbers in the list using the
-- formula Lcm ({Ai}}) = Lcm (A1, Lcm (A2, Lcm ( ... ))).

function Left (Number : Int_Type; Positions : Positive) return Int_Type;
-- Returns the number formed by the leftmost digit Positions of Number.

Expand Down
4 changes: 4 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ Traceability matrix of library functions / unit tests.
| function Fibonacci_Start return Int_Type; | [Fibonacci tests](src/fibonacci_tests.adb) |
| function Fibonacci_Start (A, B : Int_Type) return Int_Type; | [Fibonacci tests](src/fibonacci_tests.adb) |
| function Fibonacci_Next return Int_Type; | [Fibonacci tests](src/fibonacci_tests.adb) |
| function Greatest_Common_Divisor (A, B : Int_Type) return Int_Type; | [divisors tests](src/divisors_tests.adb) |
| function Greatest_Common_Divisor (List : List_Type) return Int_Type; | [divisors tests](src/divisors_tests.adb) |
| function Hundreds (Number : Int_Type) return Int_Type; | [numeric tests](src/numeric_tests.adb) |
| function Is_Abundant (Number : Int_Type) return Boolean; | [divisors tests](src/divisors_tests.adb) |
| function Is_Deficient (Number : Int_Type) return Boolean; | [divisors tests](src/divisors_tests.adb) |
Expand All @@ -38,6 +40,8 @@ Traceability matrix of library functions / unit tests.
| function Is_Palindrome (Number : Int_Type) return Boolean; | [numeric tests](src/numeric_tests.adb) |
| function Is_Perfect (Number : Int_Type) return Boolean; | [divisors tests](src/divisors_tests.adb) |
| function Is_Prime (Number : Int_Type) return Boolean; | [prime tests](src/prime_tests.adb) |
| function Least_Common_Multiple (A, B : Int_Type) return Int_Type; | [divisors tests](src/divisors_tests.adb) |
| function Least_Common_Multiple (List : List_Type) return Int_Type; | [divisors tests](src/divisors_tests.adb) |
| function Left (Number : Int_Type; Positions : Positive) return Int_Type; | [numeric tests](src/numeric_tests.adb) |
| function Length (Number : Crumbled_Natural) return Natural; | *length of* `Ada.Containers.Vector` |
| function Length (Number : Integer_Type) return Natural; | [numeric tests](src/numeric_tests.adb) |
Expand Down
6 changes: 3 additions & 3 deletions tests/alire.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "euler_tools_tests"
description = "Euler Tools - Unit tests"
version = "1.1.1"
version = "1.3.0"

authors = ["Francesc Rocher"]
maintainers = ["Francesc Rocher <[email protected]>"]
Expand All @@ -10,8 +10,8 @@ executables = ["euler_tools_tests"]
[[depends-on]]
aunit = "^23.0.0"
[[depends-on]]
euler_tools = ">=1.1.1"
euler_tools = ">=1.3.0"
[[pins]]
euler_tools = { path='..' }
euler_tools = { path = '..' }
[[depends-on]]
gnat = ">=2021 | (>=12 & <2000)"
84 changes: 84 additions & 0 deletions tests/src/divisors_tests.adb
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@ package body Divisors_Tests is
begin
Register_Routine (T, Test_All_Divisors'Access, "All_Divisors");
Register_Routine (T, Test_Are_Amicable'Access, "Are_Amicable");
Register_Routine (T, Test_Greatest_Common_Divisor'Access, "GCD");
Register_Routine (T, Test_Is_Abundant'Access, "Is_Abundant");
Register_Routine (T, Test_Is_Deficient'Access, "Is_Deficient");
Register_Routine (T, Test_Is_Divisor'Access, "Is_Divisor");
Register_Routine (T, Test_Is_Perfect'Access, "Is_Perfect");
Register_Routine (T, Test_Least_Common_Divisor'Access, "LCM");
Register_Routine (T, Test_Proper_Divisors'Access, "Proper_Divisors");
Register_Routine (T, Test_Int3_Is_Perfect'Access, "Is_Perfect (Int3)");
end Register_Tests;
Expand Down Expand Up @@ -122,6 +124,42 @@ package body Divisors_Tests is
Assert (not Are_Amicable (672, 716), "672 and 716 are not amicable");
end Test_Are_Amicable;

----------------------------------
-- Test_Greatest_Common_Divisor --
----------------------------------

procedure Test_Greatest_Common_Divisor (T : in out Test_Case'Class) is
use Euler_Tools;
List : List_Type;
begin
Assert (Greatest_Common_Divisor (1, 0) = 1, "gcd (1, 0) is 1");
Assert (Greatest_Common_Divisor (1, 1) = 1, "gcd (1, 1) is 1");
Assert (Greatest_Common_Divisor (1, 2) = 1, "gcd (1, 2) is 1");
Assert (Greatest_Common_Divisor (1, 3) = 1, "gcd (1, 3) is 1");
Assert (Greatest_Common_Divisor (2, 2) = 2, "gcd (2, 2) is 2");
Assert (Greatest_Common_Divisor (3, 3) = 3, "gcd (3, 3) is 3");
Assert (Greatest_Common_Divisor (3, 4) = 1, "gcd (3, 4) is 1");
Assert (Greatest_Common_Divisor (30, 40) = 10, "gcd (30, 40) is 10");
Assert (Greatest_Common_Divisor (350, 450) = 50, "gcd (350, 450) is 50");
Assert
(Greatest_Common_Divisor (7_700, 9_900) = 1_100,
"gcd (7700, 9900) is 1100");

List := [1];
Assert (Greatest_Common_Divisor (List) = 1, "gcd ([1]) is 1");

List := [2];
Assert (Greatest_Common_Divisor (List) = 2, "gcd ([2]) is 2");

List := [20, 30, 40];
Assert (Greatest_Common_Divisor (List) = 10, "gcd ([20, 30, 40]) is 2");

List := [7_072, 10_592, 14_112];
Assert
(Greatest_Common_Divisor (List) = 32,
"gcd ([7072, 10592, 14112]) is 32");
end Test_Greatest_Common_Divisor;

----------------------
-- Test_Is_Abundant --
----------------------
Expand Down Expand Up @@ -300,6 +338,52 @@ package body Divisors_Tests is
Assert (not Is_Perfect (30), "30 is not a perfect number");
end Test_Is_Perfect;

-------------------------------
-- Test_Least_Common_Divisor --
-------------------------------

procedure Test_Least_Common_Divisor (T : in out Test_Case'Class) is
use Euler_Tools;
List : List_Type;
begin
Assert (Least_Common_Multiple (0, 0) = 0, "lcm (0, 0) is 0");
Assert (Least_Common_Multiple (1, 0) = 0, "lcm (1, 0) is 0");
Assert (Least_Common_Multiple (1, 2) = 2, "lcm (1, 2) is 2");
Assert (Least_Common_Multiple (2, 2) = 2, "lcm (2, 2) is 2");
Assert (Least_Common_Multiple (2, 3) = 6, "lcm (2, 3) is 6");
Assert (Least_Common_Multiple (3, 3) = 3, "lcm (3, 3) is 3");
Assert (Least_Common_Multiple (3, 4) = 12, "lcm (3, 4) is 12");
Assert (Least_Common_Multiple (30, 40) = 120, "lcm (30, 40) is 120");

List := [0];
Assert (Least_Common_Multiple (List) = 0, "lcm ([0]) is 0");

List := [1];
Assert (Least_Common_Multiple (List) = 1, "lcm ([1]) is 1");

List := [1, 0];
Assert (Least_Common_Multiple (List) = 0, "lcm ([1, 0]) is 0");

List := [2, 4];
Assert (Least_Common_Multiple (List) = 4, "lcm ([2, 4]) is 4");

List := [2, 4, 6];
Assert (Least_Common_Multiple (List) = 12, "lcm ([2, 4, 6]) is 12");

List := [2, 4, 6, 8];
Assert (Least_Common_Multiple (List) = 24, "lcm ([2, 4, 6, 8]) is 24");

List := [2, 4, 6, 8, 10, 12, 14, 16, 18, 20];
Assert
(Least_Common_Multiple (List) = 5_040,
"lcm ([2, 4, 6, 8, 10, 12, 14, 16, 18, 20]) is 5040");

List := [12, 14, 16, 18, 110, 112, 114, 116, 118, 120];
Assert
(Least_Common_Multiple (List) = 1_802_298_960,
"lcm ([12, 14, 16, 18, 110, 112, 114, 116, 118, 120]) is 1802298960");
end Test_Least_Common_Divisor;

--------------------------
-- Test_Proper_Divisors --
--------------------------
Expand Down
2 changes: 2 additions & 0 deletions tests/src/divisors_tests.ads
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ package Divisors_Tests is

procedure Test_All_Divisors (T : in out Test_Case'Class);
procedure Test_Are_Amicable (T : in out Test_Case'Class);
procedure Test_Greatest_Common_Divisor (T : in out Test_Case'Class);
procedure Test_Is_Abundant (T : in out Test_Case'Class);
procedure Test_Is_Deficient (T : in out Test_Case'Class);
procedure Test_Is_Divisor (T : in out Test_Case'Class);
procedure Test_Is_Perfect (T : in out Test_Case'Class);
procedure Test_Least_Common_Divisor (T : in out Test_Case'Class);
procedure Test_Proper_Divisors (T : in out Test_Case'Class);

procedure Test_Int3_Is_Perfect (T : in out Test_Case'Class);
Expand Down

0 comments on commit e7bbfe0

Please sign in to comment.