Skip to content

Commit bc11ff5

Browse files
Add sieve exercise (#109)
1 parent 4522731 commit bc11ff5

File tree

13 files changed

+3584
-0
lines changed

13 files changed

+3584
-0
lines changed

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,14 @@
282282
"prerequisites": [],
283283
"difficulty": 5
284284
},
285+
{
286+
"slug": "sieve",
287+
"name": "Sieve",
288+
"uuid": "4ca13a1c-d296-4b5c-b5f7-7242b2b8f54b",
289+
"practices": [],
290+
"prerequisites": [],
291+
"difficulty": 5
292+
},
285293
{
286294
"slug": "knapsack",
287295
"name": "Knapsack",
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Instructions
2+
3+
Your task is to create a program that implements the Sieve of Eratosthenes algorithm to find all prime numbers less than or equal to a given number.
4+
5+
A prime number is a number larger than 1 that is only divisible by 1 and itself.
6+
For example, 2, 3, 5, 7, 11, and 13 are prime numbers.
7+
By contrast, 6 is _not_ a prime number as it not only divisible by 1 and itself, but also by 2 and 3.
8+
9+
To use the Sieve of Eratosthenes, you first create a list of all the numbers between 2 and your given number.
10+
Then you repeat the following steps:
11+
12+
1. Find the next unmarked number in your list (skipping over marked numbers).
13+
This is a prime number.
14+
2. Mark all the multiples of that prime number as **not** prime.
15+
16+
You keep repeating these steps until you've gone through every number in your list.
17+
At the end, all the unmarked numbers are prime.
18+
19+
~~~~exercism/note
20+
The tests don't check that you've implemented the algorithm, only that you've come up with the correct list of primes.
21+
To check you are implementing the Sieve correctly, a good first test is to check that you do not use division or remainder operations.
22+
~~~~
23+
24+
## Example
25+
26+
Let's say you're finding the primes less than or equal to 10.
27+
28+
- List out 2, 3, 4, 5, 6, 7, 8, 9, 10, leaving them all unmarked.
29+
- 2 is unmarked and is therefore a prime.
30+
Mark 4, 6, 8 and 10 as "not prime".
31+
- 3 is unmarked and is therefore a prime.
32+
Mark 6 and 9 as not prime _(marking 6 is optional - as it's already been marked)_.
33+
- 4 is marked as "not prime", so we skip over it.
34+
- 5 is unmarked and is therefore a prime.
35+
Mark 10 as not prime _(optional - as it's already been marked)_.
36+
- 6 is marked as "not prime", so we skip over it.
37+
- 7 is unmarked and is therefore a prime.
38+
- 8 is marked as "not prime", so we skip over it.
39+
- 9 is marked as "not prime", so we skip over it.
40+
- 10 is marked as "not prime", so we stop as there are no more numbers to check.
41+
42+
You've examined all numbers and found 2, 3, 5, and 7 are still unmarked, which means they're the primes less than or equal to 10.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Introduction
2+
3+
You bought a big box of random computer parts at a garage sale.
4+
You've started putting the parts together to build custom computers.
5+
6+
You want to test the performance of different combinations of parts, and decide to create your own benchmarking program to see how your computers compare.
7+
You choose the famous "Sieve of Eratosthenes" algorithm, an ancient algorithm, but one that should push your computers to the limits.
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+
"sieve.s"
8+
],
9+
"test": [
10+
"sieve_test.c"
11+
],
12+
"example": [
13+
".meta/example.s"
14+
]
15+
},
16+
"blurb": "Use the Sieve of Eratosthenes to find all the primes from 2 up to a given number.",
17+
"source": "Sieve of Eratosthenes at Wikipedia",
18+
"source_url": "https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes"
19+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
.text
2+
.globl sieve
3+
4+
/* extern size_t sieve(uint64_t* primes, uint64_t limit); */
5+
sieve:
6+
add x2, x1, #16
7+
and x2, x2, #-16 /* limit, rounded up to the next multiple of 16 */
8+
mov x3, sp
9+
sub sp, sp, x2 /* allocate space on stack */
10+
mov x4, #-1
11+
mov x5, sp
12+
13+
.fill:
14+
stp x4, x4, [x3, #-16]! /* store pair, pre-decrement */
15+
cmp x3, x5
16+
bne .fill
17+
18+
mov x3, x0 /* output pointer */
19+
mov x4, #1
20+
21+
.search:
22+
add x4, x4, #1 /* candidate prime */
23+
cmp x1, x4
24+
blo .exit /* unsigned < */
25+
26+
ldrb w5, [sp, x4]
27+
cbz w5, .search /* if composite, move on to next candidate */
28+
29+
str x4, [x3], #8
30+
mul x5, x4, x4 /* multiple of prime */
31+
32+
.mark:
33+
cmp x1, x5
34+
blo .search /* unsigned < */
35+
36+
strb wzr, [sp, x5] /* mark as composite */
37+
add x5, x5, x4
38+
b .mark
39+
40+
.exit:
41+
sub x0, x3, x0
42+
lsr x0, x0, #3 /* number of primes */
43+
add sp, sp, x2 /* restore original stack pointer */
44+
ret
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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+
[88529125-c4ce-43cc-bb36-1eb4ddd7b44f]
13+
description = "no primes under two"
14+
15+
[4afe9474-c705-4477-9923-840e1024cc2b]
16+
description = "find first prime"
17+
18+
[974945d8-8cd9-4f00-9463-7d813c7f17b7]
19+
description = "find primes up to 10"
20+
21+
[2e2417b7-3f3a-452a-8594-b9af08af6d82]
22+
description = "limit is prime"
23+
24+
[92102a05-4c7c-47de-9ed0-b7d5fcd00f21]
25+
description = "find primes up to 1000"

exercises/practice/sieve/Makefile

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

exercises/practice/sieve/sieve.s

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.text
2+
.globl sieve
3+
4+
sieve:
5+
ret

exercises/practice/sieve/sieve_test.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#include "vendor/unity.h"
2+
3+
#include <stddef.h>
4+
#include <stdint.h>
5+
6+
#define MAX_ARRAY_SIZE 200
7+
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
8+
9+
extern size_t sieve(uint64_t* primes, uint64_t limit);
10+
11+
void setUp(void) {
12+
}
13+
14+
void tearDown(void) {
15+
}
16+
17+
void test_no_primes_under_two(void) {
18+
uint64_t actual[MAX_ARRAY_SIZE];
19+
const size_t size = sieve(actual, 1);
20+
TEST_ASSERT_EQUAL_UINT(0U, size);
21+
}
22+
23+
void test_find_first_prime(void) {
24+
TEST_IGNORE();
25+
const uint64_t expected[] = {2};
26+
uint64_t actual[MAX_ARRAY_SIZE];
27+
const size_t size = sieve(actual, 2);
28+
TEST_ASSERT_EQUAL_UINT(ARRAY_SIZE(expected), size);
29+
TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, size);
30+
}
31+
32+
void test_find_primes_up_to_10(void) {
33+
TEST_IGNORE();
34+
const uint64_t expected[] = {2, 3, 5, 7};
35+
uint64_t actual[MAX_ARRAY_SIZE];
36+
const size_t size = sieve(actual, 10);
37+
TEST_ASSERT_EQUAL_UINT(ARRAY_SIZE(expected), size);
38+
TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, size);
39+
}
40+
41+
void test_limit_is_prime(void) {
42+
TEST_IGNORE();
43+
const uint64_t expected[] = {2, 3, 5, 7, 11, 13};
44+
uint64_t actual[MAX_ARRAY_SIZE];
45+
const size_t size = sieve(actual, 13);
46+
TEST_ASSERT_EQUAL_UINT(ARRAY_SIZE(expected), size);
47+
TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, size);
48+
}
49+
50+
void test_find_primes_up_to_1000(void) {
51+
TEST_IGNORE();
52+
const uint64_t expected[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997};
53+
uint64_t actual[MAX_ARRAY_SIZE];
54+
const size_t size = sieve(actual, 1000);
55+
TEST_ASSERT_EQUAL_UINT(ARRAY_SIZE(expected), size);
56+
TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, size);
57+
}
58+
59+
int main(void) {
60+
UNITY_BEGIN();
61+
RUN_TEST(test_no_primes_under_two);
62+
RUN_TEST(test_find_first_prime);
63+
RUN_TEST(test_find_primes_up_to_10);
64+
RUN_TEST(test_limit_is_prime);
65+
RUN_TEST(test_find_primes_up_to_1000);
66+
return UNITY_END();
67+
}

0 commit comments

Comments
 (0)