Skip to content

Commit

Permalink
Add perfect-numbers (#250)
Browse files Browse the repository at this point in the history
  • Loading branch information
BNAndras authored Jun 4, 2024
1 parent 13ec903 commit 6e1b743
Show file tree
Hide file tree
Showing 12 changed files with 248 additions and 0 deletions.
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,14 @@
"prerequisites": [],
"difficulty": 2
},
{
"slug": "perfect-numbers",
"name": "Perfect Numbers",
"uuid": "659d24f5-1e6d-4622-a2dc-177aecc10fae",
"practices": [],
"prerequisites": [],
"difficulty": 2
},
{
"slug": "resistor-color",
"name": "Resistor Color",
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
11 changes: 11 additions & 0 deletions exercises/practice/perfect-numbers/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## -*- conf -*-
.rebar3
_build/
ebin/
erl_crash.dump
rebar3.crashdump

tmp
bin/configlet
bin/configlet.exe
CHECKLIST
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": [
"BNAndras"
],
"files": {
"solution": [
"src/perfect-numbers.lfe"
],
"test": [
"test/perfect-numbers-tests.lfe"
],
"example": [
".meta/example.lfe"
]
},
"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/"
}
21 changes: 21 additions & 0 deletions exercises/practice/perfect-numbers/.meta/example.lfe
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
(defmodule perfect-numbers
(export (classify 1)))

(defun classify (number)
(if (=< number 0)
'false
(let ((sum-of-factors (lists:sum (factors-of number))))
(label number sum-of-factors))))

(defun factors-of (number)
(lists:filter (lambda (x) (=:= 0 (rem number x)))
(lists:seq 1 (div number 2))))

(defun label
((number number)
'perfect)
((number sum) (when (< number sum))
'abundant)
((number sum) (when (> number sum))
'deficient))

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)"
21 changes: 21 additions & 0 deletions exercises/practice/perfect-numbers/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
ERL := $(shell which erl)
REBAR3 := $(shell which rebar3)

null :=
space := $(null) #
comma := ,

ifeq ($(ERL),)
$(error Can't find Erlang executable 'erl')
else ifeq ($(REBAR3),)
$(error Can't find rebar3)
endif

compile: ; $(REBAR3) compile

clean: ; $(REBAR3) clean

.PHONY: test
test:
$(REBAR3) eunit \
-m $(subst $(space),$(comma),$(basename $(notdir $(wildcard test/*.lfe))))
11 changes: 11 additions & 0 deletions exercises/practice/perfect-numbers/rebar.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{plugins, [{rebar3_lfe, "0.4.10"}]}.

{provider_hooks, [{post, [{compile, {lfe, compile}}]}]}.

{deps, [{lfe, "2.1.3"}]}.

{profiles,
[{test,
[{eunit_compile_opts, [{src_dirs, ["src", "test"]}]},
{deps,
[{ltest, "0.13.8"}]}]}]}.
8 changes: 8 additions & 0 deletions exercises/practice/perfect-numbers/rebar.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{"1.2.0",
[{<<"lfe">>,{pkg,<<"lfe">>,<<"2.1.3">>},0}]}.
[
{pkg_hash,[
{<<"lfe">>, <<"6EFCB2BBC1FFC21DC5D1C092F00EFDB397EAC889474AC5C86EDF78A3557CC730">>}]},
{pkg_hash_ext,[
{<<"lfe">>, <<"4E4BAD515A169AE418FEB7374EA1C8D741FAEA9D95E266CE343B45BCC377F55B">>}]}
].
11 changes: 11 additions & 0 deletions exercises/practice/perfect-numbers/src/perfect-numbers.app.src
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
%% -*- erlang -*-
{application, 'perfect-numbers',
[{description, ""},
{vsn, "0.0.1"},
{modules,
['perfect-numbers']},
{registered, []},
{applications,
[kernel, stdlib]},
{included_applications, []},
{env, []}]}.
5 changes: 5 additions & 0 deletions exercises/practice/perfect-numbers/src/perfect-numbers.lfe
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
(defmodule perfect-numbers
(export (classify 1)))

; Please implement the 'classify' function

45 changes: 45 additions & 0 deletions exercises/practice/perfect-numbers/test/perfect-numbers-tests.lfe
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
(defmodule perfect-numbers-tests
(behaviour ltest-unit)
(export all))

(include-lib "ltest/include/ltest-macros.lfe")

(deftest smallest-perfect-number
(is-equal 'perfect (perfect-numbers:classify 6)))

(deftest medium-perfect-number
(is-equal 'perfect (perfect-numbers:classify 28)))

(deftest large-perfect-number
(is-equal 'perfect (perfect-numbers:classify 33550336)))

(deftest smallest-abundant-number
(is-equal 'abundant (perfect-numbers:classify 12)))

(deftest medium-abundant-number
(is-equal 'abundant (perfect-numbers:classify 30)))

(deftest large-abundant-number
(is-equal 'abundant (perfect-numbers:classify 33550335)))

(deftest smallest-prime-deficient-number
(is-equal 'deficient (perfect-numbers:classify 2)))

(deftest smallest-non-prime-deficient-number
(is-equal 'deficient (perfect-numbers:classify 4)))

(deftest medium-deficient-number
(is-equal 'deficient (perfect-numbers:classify 32)))

(deftest large-deficient-number
(is-equal 'deficient (perfect-numbers:classify 33550337)))

(deftest edge-case-number-no-factors-other-than-self
(is-equal 'deficient (perfect-numbers:classify 1)))

(deftest zero-is-rejected
(is-not (perfect-numbers:classify 0)))

(deftest negative-integer-is-rejected
(is-not (perfect-numbers:classify -1)))

0 comments on commit 6e1b743

Please sign in to comment.