Skip to content

Commit

Permalink
Add collatz-conjecture exercise (#67)
Browse files Browse the repository at this point in the history
  • Loading branch information
keiravillekode authored Oct 19, 2024
1 parent 8be5c39 commit 8a52e84
Show file tree
Hide file tree
Showing 13 changed files with 3,573 additions and 5 deletions.
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@
"strings"
]
},
{
"slug": "collatz-conjecture",
"name": "Collatz Conjecture",
"uuid": "926ee852-050e-4d4e-81c2-122a564dd664",
"practices": [],
"prerequisites": [],
"difficulty": 2
},
{
"slug": "leap",
"name": "Leap",
Expand Down
29 changes: 29 additions & 0 deletions exercises/practice/collatz-conjecture/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Instructions

The Collatz Conjecture or 3x+1 problem can be summarized as follows:

Take any positive integer n.
If n is even, divide n by 2 to get n / 2.
If n is odd, multiply n by 3 and add 1 to get 3n + 1.
Repeat the process indefinitely.
The conjecture states that no matter which number you start with, you will always reach 1 eventually.

Given a number n, return the number of steps required to reach 1.

## Examples

Starting with n = 12, the steps would be as follows:

0. 12
1. 6
2. 3
3. 10
4. 5
5. 16
6. 8
7. 4
8. 2
9. 1

Resulting in 9 steps.
So for input n = 12, the return value would be 9.
19 changes: 19 additions & 0 deletions exercises/practice/collatz-conjecture/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"authors": [
"keiravillekode"
],
"files": {
"solution": [
"collatz_conjecture.s"
],
"test": [
"collatz_conjecture_test.c"
],
"example": [
".meta/example.s"
]
},
"blurb": "Calculate the number of steps to reach 1 using the Collatz conjecture.",
"source": "An unsolved problem in mathematics named after mathematician Lothar Collatz",
"source_url": "https://en.wikipedia.org/wiki/3x_%2B_1_problem"
}
32 changes: 32 additions & 0 deletions exercises/practice/collatz-conjecture/.meta/example.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.text
.globl steps

/* extern int steps(int number); */
steps:
mov x1, #1
cmp x0, x1
blt .invalid

mov x2, x0 /* current number */
mov x3, #3
mov x0, #0 /* step count */

.loop:
cmp x2, x1
beq .return

tbz x2, #0, .even /* jump ahead if low bit is clear */

madd x2, x3, x2, x1 /* 3 * number + 1 */
add x0, x0, #1 /* increment step count */

.even:
lsr x2, x2, #1 /* number / 2 */
add x0, x0, #1 /* increment step count */
b .loop

.invalid:
mov x0, #-1

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

[540a3d51-e7a6-47a5-92a3-4ad1838f0bfd]
description = "zero steps for one"

[3d76a0a6-ea84-444a-821a-f7857c2c1859]
description = "divide if even"

[754dea81-123c-429e-b8bc-db20b05a87b9]
description = "even and odd steps"

[ecfd0210-6f85-44f6-8280-f65534892ff6]
description = "large number of even and odd steps"

[7d4750e6-def9-4b86-aec7-9f7eb44f95a3]
description = "zero is an error"
include = false

[2187673d-77d6-4543-975e-66df6c50e2da]
description = "zero is an error"
reimplements = "7d4750e6-def9-4b86-aec7-9f7eb44f95a3"

[c6c795bf-a288-45e9-86a1-841359ad426d]
description = "negative value is an error"
include = false

[ec11f479-56bc-47fd-a434-bcd7a31a7a2e]
description = "negative value is an error"
reimplements = "c6c795bf-a288-45e9-86a1-841359ad426d"
36 changes: 36 additions & 0 deletions exercises/practice/collatz-conjecture/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/collatz-conjecture/collatz_conjecture.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.text
.globl steps

steps:
ret
65 changes: 65 additions & 0 deletions exercises/practice/collatz-conjecture/collatz_conjecture_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include "vendor/unity.h"

#include <stdint.h>

#define ERROR_VALUE -1

extern int steps(int64_t number);

void setUp(void) {
}

void tearDown(void) {
}

void test_zero_steps_for_one(void) {
TEST_ASSERT_EQUAL_INT(0, steps(1));
}

void test_divide_if_even(void) {
TEST_IGNORE();
TEST_ASSERT_EQUAL_INT(4, steps(16));
}

void test_even_and_odd_steps(void) {
TEST_IGNORE();
TEST_ASSERT_EQUAL_INT(9, steps(12));
}

void test_large_number_of_even_and_odd_steps(void) {
TEST_IGNORE();
TEST_ASSERT_EQUAL_INT(152, steps(1000000));
}

void test_zero_is_an_error(void) {
TEST_IGNORE();
TEST_ASSERT_EQUAL_INT(-1, steps(0));
}

void test_negative_value_is_an_error(void) {
TEST_IGNORE();
TEST_ASSERT_EQUAL_INT(-1, steps(-15));
}

void test_large_positive(void) {
TEST_IGNORE();
TEST_ASSERT_EQUAL_INT(817, steps(2037066081));
}

void test_large_negative(void) {
TEST_IGNORE();
TEST_ASSERT_EQUAL_INT(-1, steps(-7001002003));
}

int main(void) {
UNITY_BEGIN();
RUN_TEST(test_zero_steps_for_one);
RUN_TEST(test_divide_if_even);
RUN_TEST(test_even_and_odd_steps);
RUN_TEST(test_large_number_of_even_and_odd_steps);
RUN_TEST(test_zero_is_an_error);
RUN_TEST(test_negative_value_is_an_error);
RUN_TEST(test_large_positive);
RUN_TEST(test_large_negative);
return UNITY_END();
}
Loading

0 comments on commit 8a52e84

Please sign in to comment.