Skip to content

Commit 5944926

Browse files
committed
Add Zeckendorf in Algol68
1 parent 6c4f90a commit 5944926

File tree

1 file changed

+152
-0
lines changed

1 file changed

+152
-0
lines changed

archive/a/algol68/zeckendorf.alg

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
# Number of Fibonacci numbers before the math overflows #
2+
INT max fibonaccis = 43;
3+
4+
MODE PARSEINT_RESULT = STRUCT(BOOL valid, INT value, STRING leftover);
5+
6+
PROC parse int = (REF STRING s) PARSEINT_RESULT:
7+
(
8+
BOOL valid := FALSE;
9+
REAL r := 0.0;
10+
INT n := 0;
11+
STRING leftover;
12+
13+
# Associate string with a file #
14+
FILE f;
15+
associate(f, s);
16+
17+
# On end of input, exit if valid number not seen. Otherwise ignore it #
18+
on logical file end(f, (REF FILE dummy) BOOL:
19+
(
20+
IF NOT valid THEN done FI;
21+
TRUE
22+
)
23+
);
24+
25+
# Exit if value error #
26+
on value error(f, (REF FILE dummy) BOOL: done);
27+
28+
# Convert string to real number #
29+
get(f, r);
30+
31+
# If real number is in range of an integer, convert to integer. Indicate integer is valid if same as real #
32+
IF ABS r <= max int
33+
THEN
34+
n := ENTIER(r);
35+
valid := (n = r)
36+
FI;
37+
38+
# Get leftover string #
39+
get(f, leftover);
40+
41+
done:
42+
close(f);
43+
PARSEINT_RESULT(valid, n, leftover)
44+
);
45+
46+
PROC usage = VOID: printf(($gl$, "Usage: please input a non-negative integer"));
47+
48+
COMMENT
49+
fib(n) = fib(n - 1) + fib(n - 2)
50+
where:
51+
- fib(0) = 0
52+
- fib(1) = 1
53+
- fib(2) = 1
54+
- fib(3) = 2
55+
COMMENT
56+
MODE FIBSTATE = STRUCT(INT prev, INT result);
57+
PROC init fib = FIBSTATE: FIBSTATE(1, 2);
58+
OP FIB = (FIBSTATE state) FIBSTATE: (result OF state, prev OF state + result OF state);
59+
OP FIBRESULT = (FIBSTATE state) INT: prev OF state;
60+
61+
PROC fibonacci up to = (INT n) REF [] INT:
62+
(
63+
# Temporary array that can handle Fibonacci numbers #
64+
REF [] INT temp results = HEAP [1:max fibonaccis] INT;
65+
66+
# Initialize Fibonacci state #
67+
FIBSTATE state := init fib;
68+
69+
# Collect all Fibonacci numbers up to the specified value #
70+
INT idx := 0;
71+
WHILE FIBRESULT state <= n AND idx < max fibonaccis
72+
DO
73+
idx +:= 1;
74+
temp results[idx] := FIBRESULT state;
75+
state := FIB state
76+
OD;
77+
78+
# Resize results #
79+
REF [] INT results := HEAP [1:idx] INT;
80+
results := temp results[1:idx];
81+
results
82+
);
83+
84+
PROC zeckendorf = (INT n) REF [] INT:
85+
(
86+
# Get Fibonacci numbers up to and including n #
87+
REF [] INT fibs = fibonacci up to(n);
88+
89+
# Allocate temporary space for Zeckendorf values #
90+
INT num fibs := UPB fibs;
91+
REF [] INT temp results := HEAP [1:num fibs] INT;
92+
93+
# Going from largest to smallest, repeat until no more Fibonacci numbers #
94+
# left or sum of Fibonacci numbers is equal to n #
95+
INT fib idx := num fibs;
96+
INT zeck idx := 0;
97+
INT remaining := n;
98+
WHILE fib idx > 0 AND remaining > 0
99+
DO
100+
# If this Fibonacci number is less than or equal to n, use it and skip the #
101+
# previous Fibonacci number. Otherwise, go to previous Fibonacci number #
102+
INT fib = fibs[fib idx];
103+
IF fib <= remaining
104+
THEN
105+
zeck idx +:= 1;
106+
temp results [zeck idx] := fib;
107+
fib idx -:= 2;
108+
remaining -:= fib
109+
ELSE
110+
fib idx -:= 1
111+
FI
112+
OD;
113+
114+
# Resize results #
115+
REF [] INT results := HEAP [1:zeck idx] INT;
116+
results := temp results[1:zeck idx];
117+
results
118+
);
119+
120+
PROC show list values = (REF []INT values) VOID:
121+
(
122+
INT n = UPB values;
123+
FOR k TO n
124+
DO
125+
IF k > 1
126+
THEN
127+
print(", ")
128+
FI;
129+
130+
print(whole(values[k], 0))
131+
OD;
132+
133+
IF n > 0
134+
THEN
135+
print(newline)
136+
FI
137+
);
138+
139+
# Parse 1st command-line argument #
140+
STRING s := argv(4);
141+
PARSEINT_RESULT result := parse int(s);
142+
143+
# If invalid or extra characters or negative number, exit #
144+
INT n := value OF result;
145+
IF NOT (valid OF result) OR (leftover OF result) /= "" OR n < 0
146+
THEN
147+
usage;
148+
stop
149+
FI;
150+
151+
REF [] INT results := zeckendorf(n);
152+
show list values(results)

0 commit comments

Comments
 (0)