Skip to content

Commit 3563dd1

Browse files
Add perfect-numbers exercise
1 parent 5cacf54 commit 3563dd1

File tree

12 files changed

+3663
-0
lines changed

12 files changed

+3663
-0
lines changed

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,14 @@
234234
"prerequisites": [],
235235
"difficulty": 4
236236
},
237+
{
238+
"slug": "perfect-numbers",
239+
"name": "Perfect Numbers",
240+
"uuid": "f3a67356-dca2-4cd6-87dc-8e7558d31381",
241+
"practices": [],
242+
"prerequisites": [],
243+
"difficulty": 4
244+
},
237245
{
238246
"slug": "phone-number",
239247
"name": "Phone Number",
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Instructions
2+
3+
Determine if a number is perfect, abundant, or deficient based on Nicomachus' (60 - 120 CE) classification scheme for positive integers.
4+
5+
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].
6+
The _aliquot sum_ is defined as the sum of the factors of a number not including the number itself.
7+
For example, the aliquot sum of `15` is `1 + 3 + 5 = 9`.
8+
9+
## Perfect
10+
11+
A number is perfect when it equals its aliquot sum.
12+
For example:
13+
14+
- `6` is a perfect number because `1 + 2 + 3 = 6`
15+
- `28` is a perfect number because `1 + 2 + 4 + 7 + 14 = 28`
16+
17+
## Abundant
18+
19+
A number is abundant when it is less than its aliquot sum.
20+
For example:
21+
22+
- `12` is an abundant number because `1 + 2 + 3 + 4 + 6 = 16`
23+
- `24` is an abundant number because `1 + 2 + 3 + 4 + 6 + 8 + 12 = 36`
24+
25+
## Deficient
26+
27+
A number is deficient when it is greater than its aliquot sum.
28+
For example:
29+
30+
- `8` is a deficient number because `1 + 2 + 4 = 7`
31+
- Prime numbers are deficient
32+
33+
## Task
34+
35+
Implement a way to determine whether a given number is [perfect](#perfect).
36+
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).
37+
38+
[nicomachus]: https://en.wikipedia.org/wiki/Nicomachus
39+
[aliquot-sum]: https://en.wikipedia.org/wiki/Aliquot_sum
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"authors": [
3+
"keiravillekode"
4+
],
5+
"files": {
6+
"solution": [
7+
"perfect_numbers.s"
8+
],
9+
"test": [
10+
"perfect_numbers_test.c"
11+
],
12+
"example": [
13+
".meta/example.s"
14+
]
15+
},
16+
"blurb": "Determine if a number is perfect, abundant, or deficient based on Nicomachus' (60 - 120 CE) classification scheme for positive integers.",
17+
"source": "Taken from Chapter 2 of Functional Thinking by Neal Ford.",
18+
"source_url": "https://www.oreilly.com/library/view/functional-thinking/9781449365509/"
19+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
.equ DEFICIENT, 1
2+
.equ PERFECT, 2
3+
.equ ABUNDANT, 3
4+
.equ INVALID, -1
5+
6+
.text
7+
.globl classify
8+
9+
/* extern int classify(int64_t number); */
10+
classify:
11+
cmp x0, #1
12+
ble .le_one
13+
14+
mov x1, #1 /* product of factors */
15+
mov x2, #1
16+
lsl x4, x0, #1 /* 2 * number */
17+
18+
.next:
19+
add x2, x2, #1 /* candidate factor */
20+
mov x5, #1 /* sum of powers of factor */
21+
mul x3, x2, x2
22+
cmp x3, x0
23+
csel x2, x0, x2, hi /* if x2*x2 exceeds x0, then set x2 to x0 */
24+
25+
udiv x6, x0, x2 /* quotient */
26+
msub x7, x6, x2, x0 /* remainder */
27+
cbnz x7, .next
28+
29+
.repeat:
30+
mul x5, x5, x2
31+
add x5, x5, #1
32+
mov x0, x6
33+
34+
udiv x6, x0, x2 /* quotient */
35+
msub x7, x6, x2, x0 /* remainder */
36+
cbz x7, .repeat
37+
38+
mul x1, x1, x5
39+
cmp x0, #1
40+
bne .next
41+
42+
cmp x1, x4
43+
beq .perfect
44+
blo .deficient
45+
46+
.abundant:
47+
mov x0, ABUNDANT
48+
ret
49+
50+
.perfect:
51+
mov x0, PERFECT
52+
ret
53+
54+
.deficient:
55+
mov x0, DEFICIENT
56+
ret
57+
58+
.le_one:
59+
beq .deficient
60+
61+
mov x0, INVALID
62+
ret
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[163e8e86-7bfd-4ee2-bd68-d083dc3381a3]
13+
description = "Perfect numbers -> Smallest perfect number is classified correctly"
14+
15+
[169a7854-0431-4ae0-9815-c3b6d967436d]
16+
description = "Perfect numbers -> Medium perfect number is classified correctly"
17+
18+
[ee3627c4-7b36-4245-ba7c-8727d585f402]
19+
description = "Perfect numbers -> Large perfect number is classified correctly"
20+
21+
[80ef7cf8-9ea8-49b9-8b2d-d9cb3db3ed7e]
22+
description = "Abundant numbers -> Smallest abundant number is classified correctly"
23+
24+
[3e300e0d-1a12-4f11-8c48-d1027165ab60]
25+
description = "Abundant numbers -> Medium abundant number is classified correctly"
26+
27+
[ec7792e6-8786-449c-b005-ce6dd89a772b]
28+
description = "Abundant numbers -> Large abundant number is classified correctly"
29+
30+
[e610fdc7-2b6e-43c3-a51c-b70fb37413ba]
31+
description = "Deficient numbers -> Smallest prime deficient number is classified correctly"
32+
33+
[0beb7f66-753a-443f-8075-ad7fbd9018f3]
34+
description = "Deficient numbers -> Smallest non-prime deficient number is classified correctly"
35+
36+
[1c802e45-b4c6-4962-93d7-1cad245821ef]
37+
description = "Deficient numbers -> Medium deficient number is classified correctly"
38+
39+
[47dd569f-9e5a-4a11-9a47-a4e91c8c28aa]
40+
description = "Deficient numbers -> Large deficient number is classified correctly"
41+
42+
[a696dec8-6147-4d68-afad-d38de5476a56]
43+
description = "Deficient numbers -> Edge case (no factors other than itself) is classified correctly"
44+
45+
[72445cee-660c-4d75-8506-6c40089dc302]
46+
description = "Invalid inputs -> Zero is rejected (as it is not a positive integer)"
47+
48+
[2d72ce2c-6802-49ac-8ece-c790ba3dae13]
49+
description = "Invalid inputs -> Negative integer is rejected (as it is not a positive integer)"
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
AS = aarch64-linux-gnu-as
2+
CC = aarch64-linux-gnu-gcc
3+
4+
CFLAGS = -g -Wall -Wextra -pedantic -Werror
5+
LDFLAGS =
6+
7+
ALL_LDFLAGS = -pie -Wl,--fatal-warnings
8+
9+
ALL_CFLAGS = -std=c99 -fPIE $(CFLAGS)
10+
ALL_LDFLAGS += $(LDFLAGS)
11+
12+
C_OBJS = $(patsubst %.c,%.o,$(wildcard *.c))
13+
AS_OBJS = $(patsubst %.s,%.o,$(wildcard *.s))
14+
ALL_OBJS = $(filter-out example.o,$(C_OBJS) $(AS_OBJS) vendor/unity.o)
15+
16+
CC_CMD = $(CC) $(ALL_CFLAGS) -c -o $@ $<
17+
18+
all: tests
19+
qemu-aarch64 -L /usr/aarch64-linux-gnu ./$<
20+
21+
tests: $(ALL_OBJS)
22+
@$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -o $@ $(ALL_OBJS)
23+
24+
%.o: %.s
25+
@$(AS) -o $@ $<
26+
27+
%.o: %.c
28+
@$(CC_CMD)
29+
30+
vendor/unity.o: vendor/unity.c vendor/unity.h vendor/unity_internals.h
31+
@$(CC_CMD)
32+
33+
clean:
34+
@rm -f *.o vendor/*.o tests
35+
36+
.PHONY: all clean
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.equ DEFICIENT, 1
2+
.equ PERFECT, 2
3+
.equ ABUNDANT, 3
4+
.equ INVALID, -1
5+
6+
.text
7+
.globl classify
8+
9+
classify:
10+
ret
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#include "vendor/unity.h"
2+
3+
#include <stdint.h>
4+
5+
#define DEFICIENT 1
6+
#define PERFECT 2
7+
#define ABUNDANT 3
8+
#define INVALID -1
9+
10+
extern int classify(int64_t number);
11+
12+
void setUp(void) {
13+
}
14+
15+
void tearDown(void) {
16+
}
17+
18+
void test_smallest_perfect_number_is_classified_correctly(void) {
19+
TEST_ASSERT_EQUAL_INT(PERFECT, classify(6));
20+
}
21+
22+
void test_medium_perfect_number_is_classified_correctly(void) {
23+
TEST_IGNORE();
24+
TEST_ASSERT_EQUAL_INT(PERFECT, classify(28));
25+
}
26+
27+
void test_large_perfect_number_is_classified_correctly(void) {
28+
TEST_IGNORE();
29+
TEST_ASSERT_EQUAL_INT(PERFECT, classify(33550336));
30+
}
31+
32+
void test_smallest_abundant_number_is_classified_correctly(void) {
33+
TEST_IGNORE();
34+
TEST_ASSERT_EQUAL_INT(ABUNDANT, classify(12));
35+
}
36+
37+
void test_medium_abundant_number_is_classified_correctly(void) {
38+
TEST_IGNORE();
39+
TEST_ASSERT_EQUAL_INT(ABUNDANT, classify(30));
40+
}
41+
42+
void test_large_abundant_number_is_classified_correctly(void) {
43+
TEST_IGNORE();
44+
TEST_ASSERT_EQUAL_INT(ABUNDANT, classify(33550335));
45+
}
46+
47+
void test_smallest_prime_deficient_number_is_classified_correctly(void) {
48+
TEST_IGNORE();
49+
TEST_ASSERT_EQUAL_INT(DEFICIENT, classify(2));
50+
}
51+
52+
void test_smallest_nonprime_deficient_number_is_classified_correctly(void) {
53+
TEST_IGNORE();
54+
TEST_ASSERT_EQUAL_INT(DEFICIENT, classify(4));
55+
}
56+
57+
void test_medium_deficient_number_is_classified_correctly(void) {
58+
TEST_IGNORE();
59+
TEST_ASSERT_EQUAL_INT(DEFICIENT, classify(32));
60+
}
61+
62+
void test_large_deficient_number_is_classified_correctly(void) {
63+
TEST_IGNORE();
64+
TEST_ASSERT_EQUAL_INT(DEFICIENT, classify(33550337));
65+
}
66+
67+
void test_edge_case_no_factors_other_than_itself_is_classified_correctly(void) {
68+
TEST_IGNORE();
69+
TEST_ASSERT_EQUAL_INT(DEFICIENT, classify(1));
70+
}
71+
72+
void test_zero_is_rejected_as_it_is_not_a_positive_integer(void) {
73+
TEST_IGNORE();
74+
TEST_ASSERT_EQUAL_INT(INVALID, classify(0));
75+
}
76+
77+
void test_negative_integer_is_rejected_as_it_is_not_a_positive_integer(void) {
78+
TEST_IGNORE();
79+
TEST_ASSERT_EQUAL_INT(INVALID, classify(-1));
80+
}
81+
82+
void test_large_negative_is_rejected(void) {
83+
TEST_IGNORE();
84+
TEST_ASSERT_EQUAL_INT(INVALID, classify(-7001002003));
85+
}
86+
87+
int main(void) {
88+
UNITY_BEGIN();
89+
RUN_TEST(test_smallest_perfect_number_is_classified_correctly);
90+
RUN_TEST(test_medium_perfect_number_is_classified_correctly);
91+
RUN_TEST(test_large_perfect_number_is_classified_correctly);
92+
RUN_TEST(test_smallest_abundant_number_is_classified_correctly);
93+
RUN_TEST(test_medium_abundant_number_is_classified_correctly);
94+
RUN_TEST(test_large_abundant_number_is_classified_correctly);
95+
RUN_TEST(test_smallest_prime_deficient_number_is_classified_correctly);
96+
RUN_TEST(test_smallest_nonprime_deficient_number_is_classified_correctly);
97+
RUN_TEST(test_medium_deficient_number_is_classified_correctly);
98+
RUN_TEST(test_large_deficient_number_is_classified_correctly);
99+
RUN_TEST(test_edge_case_no_factors_other_than_itself_is_classified_correctly);
100+
RUN_TEST(test_zero_is_rejected_as_it_is_not_a_positive_integer);
101+
RUN_TEST(test_negative_integer_is_rejected_as_it_is_not_a_positive_integer);
102+
RUN_TEST(test_large_negative_is_rejected);
103+
return UNITY_END();
104+
}

0 commit comments

Comments
 (0)