Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[perfect-numbers] Implementation #669

Merged
merged 9 commits into from Sep 7, 2023
Merged
9 changes: 9 additions & 0 deletions config.json
Expand Up @@ -715,6 +715,15 @@
"prerequisites": [],
"difficulty": 1,
"topics": []
},
{
"slug": "perfect-numbers",
"name": "Perfect Numbers",
"uuid": "0c3e15e2-cb3c-40d3-a9e6-c50f71d9c258",
"practices": [],
"prerequisites": [],
"difficulty": 1,
"topics": []
}
]
},
Expand Down
23 changes: 23 additions & 0 deletions exercises/practice/perfect-numbers/.docs/instructions.md
@@ -0,0 +1,23 @@
# Instructions

Determine if a number is perfect, abundant, or deficient based on Nicomachus' (60 - 120 CE) classification scheme for positive integers.

The Greek mathematician [Nicomachus][nicomachus] devised a classification scheme for positive integers, identifying each as belonging uniquely to the categories of **perfect**, **abundant**, or **deficient** based on their [aliquot sum][aliquot-sum].
The aliquot sum is defined as the sum of the factors of a number not including the number itself.
For example, the aliquot sum of 15 is: (1 + 3 + 5) = 9

- **Perfect**: aliquot sum = number
- 6 is a perfect number because (1 + 2 + 3) = 6
- 28 is a perfect number because (1 + 2 + 4 + 7 + 14) = 28
- **Abundant**: aliquot sum > number
- 12 is an abundant number because (1 + 2 + 3 + 4 + 6) = 16
- 24 is an abundant number because (1 + 2 + 3 + 4 + 6 + 8 + 12) = 36
- **Deficient**: aliquot sum < number
- 8 is a deficient number because (1 + 2 + 4) = 7
- Prime numbers are deficient

Implement a way to determine whether a given number is **perfect**.
Depending on your language track, you may also need to implement a way to determine whether a given number is **abundant** or **deficient**.

[nicomachus]: https://en.wikipedia.org/wiki/Nicomachus
[aliquot-sum]: https://en.wikipedia.org/wiki/Aliquot_sum
22 changes: 22 additions & 0 deletions exercises/practice/perfect-numbers/.meta/config.json
@@ -0,0 +1,22 @@
{
"authors": [
"habere-et-dispertire"
],
"contributors": [
"m-dango"
],
"files": {
"solution": [
"PerfectNumbers.rakumod"
],
"test": [
"perfect-numbers.rakutest"
],
"example": [
".meta/solutions/PerfectNumbers.rakumod"
]
},
"blurb": "Determine if a number is perfect, abundant, or deficient based on Nicomachus' (60 - 120 CE) classification scheme for positive integers.",
"source": "Taken from Chapter 2 of Functional Thinking by Neal Ford.",
"source_url": "https://www.oreilly.com/library/view/functional-thinking/9781449365509/"
}
@@ -0,0 +1,20 @@
unit module PerfectNumbers;

enum AliquotSumType is export (
:Deficient(Less),
:Perfect(Same),
:Abundant(More),
);

sub prime-factors ( $n is copy ) {
gather for grep *.is-prime, flat 2 .. $n.sqrt, $n
-> $prime {
take $n and last if $n.is-prime;
take $prime and $n div= $prime while $n %% $prime
}
}

sub aliquot-sum-type ( Int $n where 1..*, @pf = prime-factors( $n ) --> AliquotSumType ) is export {
return Deficient if @pf == ();
AliquotSumType( @pf.combinations( 1 .. @pf.end ).unique( with => &[eqv] ).map( { [*] $_ } ).sum.succ cmp $n )
}
53 changes: 53 additions & 0 deletions exercises/practice/perfect-numbers/.meta/template-data.yaml
@@ -0,0 +1,53 @@
unit: module

properties:
classify:
test: |-
if %case<expected><error>:exists {
sprintf(q:to/END/, %case<input><number>, %case<description>.raku);
dies-ok(
{ aliquot-sum-type(%s) },
%s,
);
END
}
else {
sprintf(q:to/END/, %case<input><number>, %case<expected>.tc, %case<description>.raku);
cmp-ok(
aliquot-sum-type(%s),
"eqv",
%s,
%s,
);
END
}

example: |-
enum AliquotSumType is export (
:Deficient(Less),
:Perfect(Same),
:Abundant(More),
);

sub prime-factors ( $n is copy ) {
gather for grep *.is-prime, flat 2 .. $n.sqrt, $n
-> $prime {
take $n and last if $n.is-prime;
take $prime and $n div= $prime while $n %% $prime
}
}

sub aliquot-sum-type ( Int $n where 1..*, @pf = prime-factors( $n ) --> AliquotSumType ) is export {
return Deficient if @pf == ();
AliquotSumType( @pf.combinations( 1 .. @pf.end ).unique( with => &[eqv] ).map( { [*] $_ } ).sum.succ cmp $n )
}

stub: |-
enum AliquotSumType is export (
:Deficient(Less),
:Perfect(Same),
:Abundant(More),
);

sub aliquot-sum-type ( $n --> AliquotSumType ) is export {
}
49 changes: 49 additions & 0 deletions exercises/practice/perfect-numbers/.meta/tests.toml
@@ -0,0 +1,49 @@
# This is an auto-generated file.
#
# Regenerating this file via `configlet sync` will:
# - Recreate every `description` key/value pair
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
# - Preserve any other key/value pair
#
# As user-added comments (using the # character) will be removed when this file
# is regenerated, comments can be added via a `comment` key.

[163e8e86-7bfd-4ee2-bd68-d083dc3381a3]
description = "Perfect numbers -> Smallest perfect number is classified correctly"

[169a7854-0431-4ae0-9815-c3b6d967436d]
description = "Perfect numbers -> Medium perfect number is classified correctly"

[ee3627c4-7b36-4245-ba7c-8727d585f402]
description = "Perfect numbers -> Large perfect number is classified correctly"

[80ef7cf8-9ea8-49b9-8b2d-d9cb3db3ed7e]
description = "Abundant numbers -> Smallest abundant number is classified correctly"

[3e300e0d-1a12-4f11-8c48-d1027165ab60]
description = "Abundant numbers -> Medium abundant number is classified correctly"

[ec7792e6-8786-449c-b005-ce6dd89a772b]
description = "Abundant numbers -> Large abundant number is classified correctly"

[e610fdc7-2b6e-43c3-a51c-b70fb37413ba]
description = "Deficient numbers -> Smallest prime deficient number is classified correctly"

[0beb7f66-753a-443f-8075-ad7fbd9018f3]
description = "Deficient numbers -> Smallest non-prime deficient number is classified correctly"

[1c802e45-b4c6-4962-93d7-1cad245821ef]
description = "Deficient numbers -> Medium deficient number is classified correctly"

[47dd569f-9e5a-4a11-9a47-a4e91c8c28aa]
description = "Deficient numbers -> Large deficient number is classified correctly"

[a696dec8-6147-4d68-afad-d38de5476a56]
description = "Deficient numbers -> Edge case (no factors other than itself) is classified correctly"

[72445cee-660c-4d75-8506-6c40089dc302]
description = "Invalid inputs -> Zero is rejected (as it is not a positive integer)"

[2d72ce2c-6802-49ac-8ece-c790ba3dae13]
description = "Invalid inputs -> Negative integer is rejected (as it is not a positive integer)"
10 changes: 10 additions & 0 deletions exercises/practice/perfect-numbers/PerfectNumbers.rakumod
@@ -0,0 +1,10 @@
unit module PerfectNumbers;

enum AliquotSumType is export (
:Deficient(Less),
:Perfect(Same),
:Abundant(More),
);

sub aliquot-sum-type ( $n --> AliquotSumType ) is export {
}
93 changes: 93 additions & 0 deletions exercises/practice/perfect-numbers/perfect-numbers.rakutest
@@ -0,0 +1,93 @@
#!/usr/bin/env raku
use Test;
use lib $?FILE.IO.dirname;
use PerfectNumbers;

cmp-ok( # begin: 163e8e86-7bfd-4ee2-bd68-d083dc3381a3
aliquot-sum-type(6),
"eqv",
Perfect,
"Perfect numbers: Smallest perfect number is classified correctly",
); # end: 163e8e86-7bfd-4ee2-bd68-d083dc3381a3

cmp-ok( # begin: 169a7854-0431-4ae0-9815-c3b6d967436d
aliquot-sum-type(28),
"eqv",
Perfect,
"Perfect numbers: Medium perfect number is classified correctly",
); # end: 169a7854-0431-4ae0-9815-c3b6d967436d

cmp-ok( # begin: ee3627c4-7b36-4245-ba7c-8727d585f402
aliquot-sum-type(33550336),
"eqv",
Perfect,
"Perfect numbers: Large perfect number is classified correctly",
); # end: ee3627c4-7b36-4245-ba7c-8727d585f402

cmp-ok( # begin: 80ef7cf8-9ea8-49b9-8b2d-d9cb3db3ed7e
aliquot-sum-type(12),
"eqv",
Abundant,
"Abundant numbers: Smallest abundant number is classified correctly",
); # end: 80ef7cf8-9ea8-49b9-8b2d-d9cb3db3ed7e

cmp-ok( # begin: 3e300e0d-1a12-4f11-8c48-d1027165ab60
aliquot-sum-type(30),
"eqv",
Abundant,
"Abundant numbers: Medium abundant number is classified correctly",
); # end: 3e300e0d-1a12-4f11-8c48-d1027165ab60

cmp-ok( # begin: ec7792e6-8786-449c-b005-ce6dd89a772b
aliquot-sum-type(33550335),
"eqv",
Abundant,
"Abundant numbers: Large abundant number is classified correctly",
); # end: ec7792e6-8786-449c-b005-ce6dd89a772b

cmp-ok( # begin: e610fdc7-2b6e-43c3-a51c-b70fb37413ba
aliquot-sum-type(2),
"eqv",
Deficient,
"Deficient numbers: Smallest prime deficient number is classified correctly",
); # end: e610fdc7-2b6e-43c3-a51c-b70fb37413ba

cmp-ok( # begin: 0beb7f66-753a-443f-8075-ad7fbd9018f3
aliquot-sum-type(4),
"eqv",
Deficient,
"Deficient numbers: Smallest non-prime deficient number is classified correctly",
); # end: 0beb7f66-753a-443f-8075-ad7fbd9018f3

cmp-ok( # begin: 1c802e45-b4c6-4962-93d7-1cad245821ef
aliquot-sum-type(32),
"eqv",
Deficient,
"Deficient numbers: Medium deficient number is classified correctly",
); # end: 1c802e45-b4c6-4962-93d7-1cad245821ef

cmp-ok( # begin: 47dd569f-9e5a-4a11-9a47-a4e91c8c28aa
aliquot-sum-type(33550337),
"eqv",
Deficient,
"Deficient numbers: Large deficient number is classified correctly",
); # end: 47dd569f-9e5a-4a11-9a47-a4e91c8c28aa

cmp-ok( # begin: a696dec8-6147-4d68-afad-d38de5476a56
aliquot-sum-type(1),
"eqv",
Deficient,
"Deficient numbers: Edge case (no factors other than itself) is classified correctly",
); # end: a696dec8-6147-4d68-afad-d38de5476a56

dies-ok( # begin: 72445cee-660c-4d75-8506-6c40089dc302
{ aliquot-sum-type(0) },
"Invalid inputs: Zero is rejected (as it is not a positive integer)",
); # end: 72445cee-660c-4d75-8506-6c40089dc302

dies-ok( # begin: 2d72ce2c-6802-49ac-8ece-c790ba3dae13
{ aliquot-sum-type(-1) },
"Invalid inputs: Negative integer is rejected (as it is not a positive integer)",
); # end: 2d72ce2c-6802-49ac-8ece-c790ba3dae13

done-testing;