Skip to content

Commit

Permalink
Sync perfect-numbers with problem-specifications
Browse files Browse the repository at this point in the history
  • Loading branch information
senekor committed Dec 17, 2023
1 parent bfbd00f commit 852d025
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 56 deletions.
44 changes: 30 additions & 14 deletions exercises/practice/perfect-numbers/.docs/instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,38 @@

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.
The Greek mathematician [Nicomachus][nicomachus] devised a classification scheme for positive integers, identifying each as belonging uniquely to the categories of [perfect](#perfect), [abundant](#abundant), or [deficient](#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**.
## Perfect

A number is perfect when it equals its aliquot sum.
For example:

- `6` is a perfect number because `1 + 2 + 3 = 6`
- `28` is a perfect number because `1 + 2 + 4 + 7 + 14 = 28`

## Abundant

A number is abundant when it is less than its aliquot sum.
For example:

- `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

A number is deficient when it is greater than its aliquot sum.
For example:

- `8` is a deficient number because `1 + 2 + 4 = 7`
- Prime numbers are deficient

## Task

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

[nicomachus]: https://en.wikipedia.org/wiki/Nicomachus
[aliquot-sum]: https://en.wikipedia.org/wiki/Aliquot_sum
18 changes: 18 additions & 0 deletions exercises/practice/perfect-numbers/.meta/test_template.tera
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use {{ crate_name }}::*;

{% for test in cases %}
#[test]
{% if loop.index != 1 -%}
#[ignore]
{% endif -%}
fn {{ test.description | slugify | replace(from="-", to="_") }}() {
let input = {{ test.input.number | json_encode() }};
let output = {{ fn_names[0] }}(input);
{%- if test.expected is object %}
assert!(output.is_none());
{% else %}
let expected = Some(Classification::{{ test.expected | title }});
assert_eq!(output, expected);
{% endif -%}
}
{% endfor -%}
54 changes: 51 additions & 3 deletions exercises/practice/perfect-numbers/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,51 @@
# This is an auto-generated file. Regular comments will be removed when this
# file is regenerated. Regenerating will not touch any manually added keys,
# so comments can be added in a "comment" key.
# 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)"
include = false
comment = "the input type is u64, which prevents negative numbers at compile time"
145 changes: 106 additions & 39 deletions exercises/practice/perfect-numbers/tests/perfect-numbers.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,107 @@
use perfect_numbers::{classify, Classification};

macro_rules! tests {
($property_test_func:ident {
$( $(#[$attr:meta])* $test_name:ident( $( $param:expr ),* ); )+
}) => {
$(
$(#[$attr])*
#[test]
fn $test_name() {
$property_test_func($( $param ),* )
}
)+
}
}

fn test_classification(num: u64, result: Classification) {
assert_eq!(classify(num), Some(result));
}

#[test]
fn basic() {
assert_eq!(classify(0), None);
}

tests! {
test_classification {
#[ignore] test_1(1, Classification::Deficient);
#[ignore] test_2(2, Classification::Deficient);
#[ignore] test_4(4, Classification::Deficient);
#[ignore] test_6(6, Classification::Perfect);
#[ignore] test_12(12, Classification::Abundant);
#[ignore] test_28(28, Classification::Perfect);
#[ignore] test_30(30, Classification::Abundant);
#[ignore] test_32(32, Classification::Deficient);
#[ignore] test_33550335(33_550_335, Classification::Abundant);
#[ignore] test_33550336(33_550_336, Classification::Perfect);
#[ignore] test_33550337(33_550_337, Classification::Deficient);
}
use perfect_numbers::*;

#[test]
fn smallest_perfect_number_is_classified_correctly() {
let input = 6;
let output = classify(input);
let expected = Some(Classification::Perfect);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn medium_perfect_number_is_classified_correctly() {
let input = 28;
let output = classify(input);
let expected = Some(Classification::Perfect);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn large_perfect_number_is_classified_correctly() {
let input = 33550336;
let output = classify(input);
let expected = Some(Classification::Perfect);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn smallest_abundant_number_is_classified_correctly() {
let input = 12;
let output = classify(input);
let expected = Some(Classification::Abundant);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn medium_abundant_number_is_classified_correctly() {
let input = 30;
let output = classify(input);
let expected = Some(Classification::Abundant);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn large_abundant_number_is_classified_correctly() {
let input = 33550335;
let output = classify(input);
let expected = Some(Classification::Abundant);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn smallest_prime_deficient_number_is_classified_correctly() {
let input = 2;
let output = classify(input);
let expected = Some(Classification::Deficient);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn smallest_non_prime_deficient_number_is_classified_correctly() {
let input = 4;
let output = classify(input);
let expected = Some(Classification::Deficient);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn medium_deficient_number_is_classified_correctly() {
let input = 32;
let output = classify(input);
let expected = Some(Classification::Deficient);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn large_deficient_number_is_classified_correctly() {
let input = 33550337;
let output = classify(input);
let expected = Some(Classification::Deficient);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn edge_case_no_factors_other_than_itself_is_classified_correctly() {
let input = 1;
let output = classify(input);
let expected = Some(Classification::Deficient);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn zero_is_rejected_as_it_is_not_a_positive_integer() {
let input = 0;
let output = classify(input);
assert!(output.is_none());
}

0 comments on commit 852d025

Please sign in to comment.