diff --git a/exercises/practice/perfect-numbers/.docs/instructions.md b/exercises/practice/perfect-numbers/.docs/instructions.md index 689a73c00..b2bc82ca3 100644 --- a/exercises/practice/perfect-numbers/.docs/instructions.md +++ b/exercises/practice/perfect-numbers/.docs/instructions.md @@ -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 diff --git a/exercises/practice/perfect-numbers/.meta/test_template.tera b/exercises/practice/perfect-numbers/.meta/test_template.tera new file mode 100644 index 000000000..0f27541a4 --- /dev/null +++ b/exercises/practice/perfect-numbers/.meta/test_template.tera @@ -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 -%} diff --git a/exercises/practice/perfect-numbers/.meta/tests.toml b/exercises/practice/perfect-numbers/.meta/tests.toml index be690e975..90976e329 100644 --- a/exercises/practice/perfect-numbers/.meta/tests.toml +++ b/exercises/practice/perfect-numbers/.meta/tests.toml @@ -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" diff --git a/exercises/practice/perfect-numbers/tests/perfect-numbers.rs b/exercises/practice/perfect-numbers/tests/perfect-numbers.rs index 3c6590a08..fd29de0d9 100644 --- a/exercises/practice/perfect-numbers/tests/perfect-numbers.rs +++ b/exercises/practice/perfect-numbers/tests/perfect-numbers.rs @@ -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()); }