Skip to content

Commit

Permalink
Added the perfect-numbers exercise
Browse files Browse the repository at this point in the history
  • Loading branch information
gvrooyen committed Sep 8, 2024
1 parent 7a93a99 commit 454f4d8
Show file tree
Hide file tree
Showing 7 changed files with 232 additions and 0 deletions.
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,14 @@
"practices": [],
"prerequisites": [],
"difficulty": 1
},
{
"slug": "perfect-numbers",
"name": "Perfect Numbers",
"uuid": "ab9aa9bd-c6a1-4989-a1a5-b761818f38a3",
"practices": [],
"prerequisites": [],
"difficulty": 1
}
]
},
Expand Down
39 changes: 39 additions & 0 deletions exercises/practice/perfect-numbers/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# 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](#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

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
19 changes: 19 additions & 0 deletions exercises/practice/perfect-numbers/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"authors": [
"gvrooyen"
],
"files": {
"solution": [
"perfect_numbers.odin"
],
"test": [
"perfect_numbers_test.odin"
],
"example": [
".meta/perfect_numbers_example.odin"
]
},
"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/"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package perfect_numbers

import "core:math"

Classification :: enum {
Perfect,
Abundant,
Deficient,
Undefined,
}

// Returns the sum of the divisors of `number` (excluding `number` itself).
// For example, the aliquot sum of 15 is (1 + 3 + 5) = 9
aliquot_sum :: proc(number: uint) -> uint {
if number <= 1 do return 0
result: uint = 1
for i in 2 ..= (number / 2) {
if number % i == 0 do result += i
}
return result
}

// Returns whether `number` is less than, equal to, or greater than its aliquot sum.
// `ok` will be false if invalid input (i.e. 0) is provided.
classify :: proc(number: uint) -> Classification {
using Classification
if number == 0 do return Undefined
sum := aliquot_sum(number)
switch {
case number < sum:
return Abundant
case number > sum:
return Deficient
case:
return Perfect
}
}
49 changes: 49 additions & 0 deletions exercises/practice/perfect-numbers/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -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)"
12 changes: 12 additions & 0 deletions exercises/practice/perfect-numbers/perfect_numbers.odin
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package perfect_numbers

Classification :: enum {
Perfect,
Abundant,
Deficient,
Undefined,
}

classify :: proc(number: uint) -> Classification {
#panic("Please implement the `classify` procedure.")
}
68 changes: 68 additions & 0 deletions exercises/practice/perfect-numbers/perfect_numbers_test.odin
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* These are the unit tests for the exercise. Only the first one is enabled to start with. You can
* enable the other tests by uncommenting the `@(test)` attribute of the test procedure. Your
* solution should pass all tests before it is ready for submission.
*/

package perfect_numbers

import "core:testing"

@(test)
test_smallest_perfect_number :: proc(t: ^testing.T) {
testing.expect_value(t, classify(6), Classification.Perfect)
}

// @(test)
test_medium_perfect_number :: proc(t: ^testing.T) {
testing.expect_value(t, classify(28), Classification.Perfect)
}

// @(test)
test_large_perfect_number :: proc(t: ^testing.T) {
testing.expect_value(t, classify(33550336), Classification.Perfect)
}

// @(test)
test_smallest_abundant_number :: proc(t: ^testing.T) {
testing.expect_value(t, classify(12), Classification.Abundant)
}

// @(test)
test_medium_abundant_number :: proc(t: ^testing.T) {
testing.expect_value(t, classify(30), Classification.Abundant)
}

// @(test)
test_large_abundant_number :: proc(t: ^testing.T) {
testing.expect_value(t, classify(33550335), Classification.Abundant)
}

// @(test)
test_smallest_prime_deficient_number :: proc(t: ^testing.T) {
testing.expect_value(t, classify(2), Classification.Deficient)
}

// @(test)
test_smallest_non_prime_deficient_number :: proc(t: ^testing.T) {
testing.expect_value(t, classify(4), Classification.Deficient)
}

// @(test)
test_medium_deficient_number :: proc(t: ^testing.T) {
testing.expect_value(t, classify(32), Classification.Deficient)
}

// @(test)
test_large_deficient_number :: proc(t: ^testing.T) {
testing.expect_value(t, classify(33550337), Classification.Deficient)
}

// @(test)
test_1_is_edge_case :: proc(t: ^testing.T) {
testing.expect_value(t, classify(1), Classification.Deficient)
}

// @(test)
test_zero_is_undefined :: proc(t: ^testing.T) {
testing.expect_value(t, classify(0), Classification.Undefined)
}

0 comments on commit 454f4d8

Please sign in to comment.