Skip to content

Commit

Permalink
Add pythagorean-triplet exercise
Browse files Browse the repository at this point in the history
  • Loading branch information
keiravillekode committed Nov 3, 2024
1 parent f12eac4 commit d8a446d
Show file tree
Hide file tree
Showing 12 changed files with 3,648 additions and 0 deletions.
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,14 @@
"prerequisites": [],
"difficulty": 6
},
{
"slug": "pythagorean-triplet",
"name": "Pythagorean Triplet",
"uuid": "31534ce6-3e89-47b4-9246-3928e9d22589",
"practices": [],
"prerequisites": [],
"difficulty": 8
},
{
"slug": "rectangles",
"name": "Rectangles",
Expand Down
23 changes: 23 additions & 0 deletions exercises/practice/pythagorean-triplet/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Instructions

A Pythagorean triplet is a set of three natural numbers, {a, b, c}, for which,

```text
a² + b² = c²
```

and such that,

```text
a < b < c
```

For example,

```text
3² + 4² = 5².
```

Given an input integer N, find all Pythagorean triplets for which `a + b + c = N`.

For example, with N = 1000, there is exactly one Pythagorean triplet for which `a + b + c = 1000`: `{200, 375, 425}`.
19 changes: 19 additions & 0 deletions exercises/practice/pythagorean-triplet/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"authors": [
"keiravillekode"
],
"files": {
"solution": [
"pythagorean_triplet.s"
],
"test": [
"pythagorean_triplet_test.c"
],
"example": [
".meta/example.s"
]
},
"blurb": "There exists exactly one Pythagorean triplet for which a + b + c = 1000. Find the triplet.",
"source": "Problem 9 at Project Euler",
"source_url": "https://projecteuler.net/problem=9"
}
34 changes: 34 additions & 0 deletions exercises/practice/pythagorean-triplet/.meta/example.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
.text
.globl triplets_with_sum

/* extern size_t triplets_with_sum(uint64_t n, uint64_t* a, uint64_t* b, uint64_t* c); */
triplets_with_sum:
mov x5, #0
mov x4, x0 /* n */
mov x0, #0 /* number of tuples */
cmp x4, #2
blo .return /* stop when n < 2 */

.next:
add x5, x5, #1 /* a */
sub x9, x4, x5 /* n - a */
sub x10, x9, x5 /* n - 2*a */
lsl x11, x9, #1 /* 2*n - 2*a */
mul x10, x4, x10 /* n*n - 2*n*a */

udiv x6, x10, x11 /* b */
msub x12, x6, x11, x10 /* remainder */
cmp x5, x6
bhs .return /* stop when a >= b */

cbnz x12, .next

sub x7, x9, x6
str x5, [x1], #8
str x6, [x2], #8
str x7, [x3], #8
add x0, x0, #1
b .next

.return:
ret
31 changes: 31 additions & 0 deletions exercises/practice/pythagorean-triplet/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# 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.

[a19de65d-35b8-4480-b1af-371d9541e706]
description = "triplets whose sum is 12"

[48b21332-0a3d-43b2-9a52-90b2a6e5c9f5]
description = "triplets whose sum is 108"

[dffc1266-418e-4daa-81af-54c3e95c3bb5]
description = "triplets whose sum is 1000"

[5f86a2d4-6383-4cce-93a5-e4489e79b186]
description = "no matching triplets for 1001"

[bf17ba80-1596-409a-bb13-343bdb3b2904]
description = "returns all matching triplets"

[9d8fb5d5-6c6f-42df-9f95-d3165963ac57]
description = "several matching triplets"

[f5be5734-8aa0-4bd1-99a2-02adcc4402b4]
description = "triplets for large number"
36 changes: 36 additions & 0 deletions exercises/practice/pythagorean-triplet/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
AS = aarch64-linux-gnu-as
CC = aarch64-linux-gnu-gcc

CFLAGS = -g -Wall -Wextra -pedantic -Werror
LDFLAGS =

ALL_LDFLAGS = -pie -Wl,--fatal-warnings

ALL_CFLAGS = -std=c99 -fPIE $(CFLAGS)
ALL_LDFLAGS += $(LDFLAGS)

C_OBJS = $(patsubst %.c,%.o,$(wildcard *.c))
AS_OBJS = $(patsubst %.s,%.o,$(wildcard *.s))
ALL_OBJS = $(filter-out example.o,$(C_OBJS) $(AS_OBJS) vendor/unity.o)

CC_CMD = $(CC) $(ALL_CFLAGS) -c -o $@ $<

all: tests
qemu-aarch64 -L /usr/aarch64-linux-gnu ./$<

tests: $(ALL_OBJS)
@$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -o $@ $(ALL_OBJS)

%.o: %.s
@$(AS) -o $@ $<

%.o: %.c
@$(CC_CMD)

vendor/unity.o: vendor/unity.c vendor/unity.h vendor/unity_internals.h
@$(CC_CMD)

clean:
@rm -f *.o vendor/*.o tests

.PHONY: all clean
5 changes: 5 additions & 0 deletions exercises/practice/pythagorean-triplet/pythagorean_triplet.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.text
.globl triplets_with_sum

triplets_with_sum:
ret
141 changes: 141 additions & 0 deletions exercises/practice/pythagorean-triplet/pythagorean_triplet_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#include "vendor/unity.h"

#include <stddef.h>
#include <stdint.h>

#define MAX_ARRAY_SIZE 120
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

extern size_t triplets_with_sum(uint64_t n, uint64_t* a, uint64_t* b, uint64_t* c);

void setUp(void) {
}

void tearDown(void) {
}

void test_triplets_whose_sum_is_12(void) {
const uint64_t expected_a[] = {3};
const uint64_t expected_b[] = {4};
const uint64_t expected_c[] = {5};
uint64_t actual_a[MAX_ARRAY_SIZE];
uint64_t actual_b[MAX_ARRAY_SIZE];
uint64_t actual_c[MAX_ARRAY_SIZE];
const size_t size = triplets_with_sum(12, actual_a, actual_b, actual_c);
TEST_ASSERT_EQUAL_UINT(ARRAY_SIZE(expected_a), size);
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_a, actual_a, size, "a");
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_b, actual_b, size, "b");
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_c, actual_c, size, "c");
}

void test_triplets_whose_sum_is_108(void) {
TEST_IGNORE();
const uint64_t expected_a[] = {27};
const uint64_t expected_b[] = {36};
const uint64_t expected_c[] = {45};
uint64_t actual_a[MAX_ARRAY_SIZE];
uint64_t actual_b[MAX_ARRAY_SIZE];
uint64_t actual_c[MAX_ARRAY_SIZE];
const size_t size = triplets_with_sum(108, actual_a, actual_b, actual_c);
TEST_ASSERT_EQUAL_UINT(ARRAY_SIZE(expected_a), size);
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_a, actual_a, size, "a");
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_b, actual_b, size, "b");
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_c, actual_c, size, "c");
}

void test_triplets_whose_sum_is_1000(void) {
TEST_IGNORE();
const uint64_t expected_a[] = {200};
const uint64_t expected_b[] = {375};
const uint64_t expected_c[] = {425};
uint64_t actual_a[MAX_ARRAY_SIZE];
uint64_t actual_b[MAX_ARRAY_SIZE];
uint64_t actual_c[MAX_ARRAY_SIZE];
const size_t size = triplets_with_sum(1000, actual_a, actual_b, actual_c);
TEST_ASSERT_EQUAL_UINT(ARRAY_SIZE(expected_a), size);
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_a, actual_a, size, "a");
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_b, actual_b, size, "b");
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_c, actual_c, size, "c");
}

void test_no_matching_triplets_for_1001(void) {
TEST_IGNORE();
uint64_t actual_a[MAX_ARRAY_SIZE];
uint64_t actual_b[MAX_ARRAY_SIZE];
uint64_t actual_c[MAX_ARRAY_SIZE];
const size_t size = triplets_with_sum(1001, actual_a, actual_b, actual_c);
TEST_ASSERT_EQUAL_UINT(0U, size);
}

void test_returns_all_matching_triplets(void) {
TEST_IGNORE();
const uint64_t expected_a[] = {9, 15};
const uint64_t expected_b[] = {40, 36};
const uint64_t expected_c[] = {41, 39};
uint64_t actual_a[MAX_ARRAY_SIZE];
uint64_t actual_b[MAX_ARRAY_SIZE];
uint64_t actual_c[MAX_ARRAY_SIZE];
const size_t size = triplets_with_sum(90, actual_a, actual_b, actual_c);
TEST_ASSERT_EQUAL_UINT(ARRAY_SIZE(expected_a), size);
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_a, actual_a, size, "a");
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_b, actual_b, size, "b");
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_c, actual_c, size, "c");
}

void test_several_matching_triplets(void) {
TEST_IGNORE();
const uint64_t expected_a[] = {40, 56, 105, 120, 140, 168, 210, 240};
const uint64_t expected_b[] = {399, 390, 360, 350, 336, 315, 280, 252};
const uint64_t expected_c[] = {401, 394, 375, 370, 364, 357, 350, 348};
uint64_t actual_a[MAX_ARRAY_SIZE];
uint64_t actual_b[MAX_ARRAY_SIZE];
uint64_t actual_c[MAX_ARRAY_SIZE];
const size_t size = triplets_with_sum(840, actual_a, actual_b, actual_c);
TEST_ASSERT_EQUAL_UINT(ARRAY_SIZE(expected_a), size);
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_a, actual_a, size, "a");
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_b, actual_b, size, "b");
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_c, actual_c, size, "c");
}

void test_triplets_for_large_number(void) {
TEST_IGNORE();
const uint64_t expected_a[] = {1200, 1875, 5000, 6000, 7500};
const uint64_t expected_b[] = {14375, 14000, 12000, 11250, 10000};
const uint64_t expected_c[] = {14425, 14125, 13000, 12750, 12500};
uint64_t actual_a[MAX_ARRAY_SIZE];
uint64_t actual_b[MAX_ARRAY_SIZE];
uint64_t actual_c[MAX_ARRAY_SIZE];
const size_t size = triplets_with_sum(30000, actual_a, actual_b, actual_c);
TEST_ASSERT_EQUAL_UINT(ARRAY_SIZE(expected_a), size);
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_a, actual_a, size, "a");
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_b, actual_b, size, "b");
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_c, actual_c, size, "c");
}

void test_triplets_for_very_large_number(void) {
TEST_IGNORE();
const uint64_t expected_a[] = {68145};
const uint64_t expected_b[] = {71672};
const uint64_t expected_c[] = {98897};
uint64_t actual_a[MAX_ARRAY_SIZE];
uint64_t actual_b[MAX_ARRAY_SIZE];
uint64_t actual_c[MAX_ARRAY_SIZE];
const size_t size = triplets_with_sum(238714, actual_a, actual_b, actual_c);
TEST_ASSERT_EQUAL_UINT(ARRAY_SIZE(expected_a), size);
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_a, actual_a, size, "a");
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_b, actual_b, size, "b");
TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected_c, actual_c, size, "c");
}

int main(void) {
UNITY_BEGIN();
RUN_TEST(test_triplets_whose_sum_is_12);
RUN_TEST(test_triplets_whose_sum_is_108);
RUN_TEST(test_triplets_whose_sum_is_1000);
RUN_TEST(test_no_matching_triplets_for_1001);
RUN_TEST(test_returns_all_matching_triplets);
RUN_TEST(test_several_matching_triplets);
RUN_TEST(test_triplets_for_large_number);
RUN_TEST(test_triplets_for_very_large_number);
return UNITY_END();
}
Loading

0 comments on commit d8a446d

Please sign in to comment.