Commit | Line | Data |
---|---|---|
f4c8a091 JM |
1 | # |
2 | # mal (Make a Lisp) number types | |
3 | # | |
4 | ||
5 | ifndef __mal_numbers_included | |
6 | __mal_numbers_included := true | |
7 | ||
8 | _TOP_DIR := $(dir $(lastword $(MAKEFILE_LIST))) | |
9 | include $(_TOP_DIR)util.mk | |
10 | ||
11 | LIST20_X := x x x x x x x x x x x x x x x x x x x x | |
12 | LIST100_X := $(foreach x,$(LIST20_X),X X X X X) | |
13 | LIST100_0 := $(foreach x,$(LIST20_X),0 0 0 0 0) | |
14 | LIST100_9 := $(foreach x,$(LIST20_X),9 9 9 9 9) | |
15 | ||
16 | ### | |
17 | ### general numeric utility functions | |
18 | ### | |
19 | ||
20 | int_encode = $(strip $(call _reverse,\ | |
21 | $(eval __temp := $(1))\ | |
4c0073a3 | 22 | $(foreach a,- 0 1 2 3 4 5 6 7 8 9,\ |
f4c8a091 JM |
23 | $(eval __temp := $$(subst $$a,$$a$$(SPACE),$(__temp))))$(__temp))) |
24 | ||
25 | int_decode = $(strip $(call _join,$(call _reverse,$(1)))) | |
26 | ||
27 | # trim extaneous zero digits off the end (front of number) | |
28 | _trim_zeros = $(if $(call _EQ,0,$(strip $(1))),0,$(if $(call _EQ,0,$(word 1,$(1))),$(call _trim_zeros,$(wordlist 2,$(words $(1)),$(1))),$(1))) | |
4c0073a3 JM |
29 | trim_zeros = $(strip \ |
30 | $(if $(call _EQ,0,$(strip $(filter-out -,$(1)))),\ | |
31 | $(filter-out -,$(1)),\ | |
32 | $(call _reverse,$(call _trim_zeros,$(call _reverse,$(filter-out -,$(1))))))\ | |
33 | $(if $(filter -,$(1)), -,)) | |
f4c8a091 JM |
34 | |
35 | # drop the last element of a list of words/digits | |
36 | drop_last = $(call _reverse,$(wordlist 2,$(words $(1)),$(call _reverse,$(1)))) | |
37 | ||
38 | ### utility function tests | |
39 | ||
40 | #$(info $(filter-out 1,$(filter 1%,1 132 456))) | |
41 | #$(info (int_encode 13): [$(call int_encode,13)]) | |
42 | #$(info (int_encode 156463): [$(call int_encode,156463)]) | |
4c0073a3 | 43 | #$(info (int_encode -156463): [$(call int_encode,-156463)]) |
f4c8a091 JM |
44 | #$(info (int_decode (int_encode 156463)): [$(call int_decode,$(call int_encode,156463))]) |
45 | ||
46 | #$(info trim_zeros(0 0 0): [$(call trim_zeros,0 0 0)]) | |
4c0073a3 | 47 | #$(info trim_zeros(0 0 0 -): [$(call trim_zeros,0 0 0 -)]) |
f4c8a091 JM |
48 | |
49 | ||
50 | ### | |
51 | ### comparisons | |
52 | ### | |
53 | ||
54 | # compare two digits and return 'true' if digit 1 is less than or | |
55 | # equal to digit 2 | |
56 | _lte_digit = $(strip \ | |
57 | $(if $(call _EQ,$(1),$(2)),\ | |
58 | true,\ | |
59 | $(if $(call _EQ,0,$(1)),\ | |
60 | true,\ | |
61 | $(if $(wordlist $(1),$(2),$(LIST20_X)),\ | |
62 | true,\ | |
63 | )))) | |
64 | ||
65 | # compare two lists of digits (MSB->LSB) of equal length and return | |
66 | # 'true' if number 1 is less than number 2 | |
67 | _lte_digits = $(strip \ | |
68 | $(if $(strip $(1)),\ | |
69 | $(if $(call _EQ,$(word 1,$(1)),$(word 1,$(2))),\ | |
70 | $(call _lte_digits,$(wordlist 2,$(words $(1)),$(1)),$(wordlist 2,$(words $(2)),$(2))),\ | |
71 | $(if $(call _lte_digit,$(word 1,$(1)),$(word 1,$(2))),true,)),\ | |
72 | true)) | |
73 | ||
74 | ### lte/less than or equal to | |
75 | ||
4c0073a3 JM |
76 | _int_lte_encoded = $(strip \ |
77 | $(foreach len1,$(words $(1)),$(foreach len2,$(words $(2)),\ | |
78 | $(if $(call _EQ,$(len1),$(len2)),\ | |
79 | $(call _lte_digits,$(call _reverse,$(1)),$(call _reverse,$(2))),\ | |
80 | $(if $(wordlist $(len1),$(len2),$(LIST100_X)),\ | |
81 | true,\ | |
82 | ))))) | |
83 | ||
f4c8a091 | 84 | int_lte_encoded = $(strip \ |
4c0073a3 JM |
85 | $(if $(filter -,$(1)),\ |
86 | $(if $(filter -,$(2)),\ | |
87 | $(call _int_lte_encoded,$(filter-out -,$(2)),$(filter-out -,$(1))),\ | |
88 | true),\ | |
89 | $(if $(filter -,$(2)),\ | |
90 | ,\ | |
91 | $(call _int_lte_encoded,$(1),$(2))))) | |
f4c8a091 JM |
92 | |
93 | int_lte = $(call int_lte_encoded,$(call int_encode,$(1)),$(call int_encode,$(2))) | |
94 | ||
95 | ### lt/less than | |
96 | ||
97 | int_lt_encoded = $(strip \ | |
98 | $(if $(call _EQ,$(strip $(1)),$(strip $(2))),\ | |
99 | ,\ | |
100 | $(call int_lte_encoded,$(1),$(2)))) | |
101 | ||
102 | int_lt = $(call int_lt_encoded,$(call int_encode,$(1)),$(call int_encode,$(2))) | |
103 | ||
104 | ### gte/greater than or equal to | |
105 | ||
106 | int_gte_encoded = $(strip \ | |
107 | $(if $(call _EQ,$(strip $(1)),$(strip $(2))),\ | |
108 | true,\ | |
109 | $(if $(call int_lte_encoded,$(1),$(2)),,true))) | |
110 | ||
111 | int_gte = $(call int_gte_encoded,$(call int_encode,$(1)),$(call int_encode,$(2))) | |
112 | ||
113 | ### gt/greater than | |
114 | ||
115 | int_gt_encoded = $(strip \ | |
116 | $(if $(call _EQ,$(strip $(1)),$(strip $(2))),\ | |
117 | ,\ | |
118 | $(call int_gte_encoded,$(1),$(2)))) | |
119 | ||
120 | int_gt = $(call int_gt_encoded,$(call int_encode,$(1)),$(call int_encode,$(2))) | |
121 | ||
122 | #$(info _lte_digit,7,8: [$(call _lte_digit,7,8)]) | |
123 | #$(info _lte_digit,8,8: [$(call _lte_digit,8,8)]) | |
124 | #$(info _lte_digit,2,1: [$(call _lte_digit,2,1)]) | |
125 | #$(info _lte_digit,0,0: [$(call _lte_digit,0,0)]) | |
126 | #$(info _lte_digit,0,1: [$(call _lte_digit,0,1)]) | |
127 | #$(info _lte_digit,1,0: [$(call _lte_digit,1,0)]) | |
128 | ||
129 | #$(info _lte_digits,1 2 3,1 2 4: [$(call _lte_digits,1 2 3,1 2 4)]) | |
130 | #$(info _lte_digits,1 2 4,1 2 4: [$(call _lte_digits,1 2 4,1 2 4)]) | |
131 | #$(info _lte_digits,1 2 5,1 2 4: [$(call _lte_digits,1 2 5,1 2 4)]) | |
132 | #$(info _lte_digits,4 1,9 0: [$(call _lte_digits,4 1,9 0)]) | |
133 | ||
4c0073a3 | 134 | # The main comparison operator (others are built on this) |
f4c8a091 JM |
135 | #$(info int_lte_encoded,1,1: [$(call int_lte_encoded,1,1)]) |
136 | #$(info int_lte_encoded,1,2: [$(call int_lte_encoded,1,2)]) | |
137 | #$(info int_lte_encoded,2,1: [$(call int_lte_encoded,2,1)]) | |
138 | #$(info int_lte_encoded,0,3: [$(call int_lte_encoded,0,3)]) | |
139 | #$(info int_lte_encoded,3,0: [$(call int_lte_encoded,3,0)]) | |
140 | #$(info int_lte_encoded,1 4,0 9: [$(call int_lte_encoded,1 4,0 9)]) | |
141 | #$(info int_lte_encoded,4 3 2 1,4 3 2 1: [$(call int_lte_encoded,4 3 2 1,4 3 2 1)]) | |
142 | #$(info int_lte_encoded,5 3 2 1,4 3 2 1: [$(call int_lte_encoded,5 3 2 1,4 3 2 1)]) | |
143 | #$(info int_lte_encoded,4 3 2 1,5 3 2 1: [$(call int_lte_encoded,4 3 2 1,5 3 2 1)]) | |
4c0073a3 JM |
144 | # negative numbers |
145 | #$(info int_lte_encoded,7 -,7: [$(call int_lte_encoded,7 -,7)]) | |
146 | #$(info int_lte_encoded,7,7 -: [$(call int_lte_encoded,7,7 -)]) | |
147 | #$(info int_lte_encoded,7 -,7 -: [$(call int_lte_encoded,7 -,7 -)]) | |
148 | #$(info int_lte_encoded,1 7 -,0 7: [$(call int_lte_encoded,1 7 -,0 7)]) | |
149 | #$(info int_lte_encoded,1 7,0 7 -: [$(call int_lte_encoded,1 7,0 7 -)]) | |
150 | #$(info int_lte_encoded,1 7 -,0 7 -: [$(call int_lte_encoded,1 7 -,0 7 -)]) | |
151 | #$(info int_lte_encoded,4 3 2 1 -,4 3 2 1: [$(call int_lte_encoded,4 3 2 1 -,4 3 2 1)]) | |
152 | #$(info int_lte_encoded,4 3 2 1,4 3 2 1 -: [$(call int_lte_encoded,4 3 2 1,4 3 2 1 -)]) | |
153 | #$(info int_lte_encoded,4 3 2 1 -,4 3 2 1 -: [$(call int_lte_encoded,4 3 2 1 -,4 3 2 1 -)]) | |
f4c8a091 JM |
154 | |
155 | #$(info int_lte,1,1: [$(call int_lte,1,1)]) | |
156 | #$(info int_lte,1,2: [$(call int_lte,1,2)]) | |
157 | #$(info int_lte,2,1: [$(call int_lte,2,1)]) | |
158 | #$(info int_lte,0,3: [$(call int_lte,0,3)]) | |
159 | #$(info int_lte,3,0: [$(call int_lte,3,0)]) | |
160 | #$(info int_lte,1234,1234: [$(call int_lte,1234,1234)]) | |
161 | #$(info int_lte,1235,1234: [$(call int_lte,1235,1234)]) | |
162 | #$(info int_lte,1234,1235: [$(call int_lte,1234,1235)]) | |
4c0073a3 JM |
163 | #$(info int_lte,-1234,1235: [$(call int_lte,-1234,1235)]) |
164 | #$(info int_lte,1234,-1235: [$(call int_lte,1234,-1235)]) | |
165 | #$(info int_lte,-1234,-1235: [$(call int_lte,-1234,-1235)]) | |
166 | ||
f4c8a091 JM |
167 | #$(info int_lt,1,1: [$(call int_lt,1,1)]) |
168 | #$(info int_lt,1,2: [$(call int_lt,1,2)]) | |
169 | #$(info int_lt,2,1: [$(call int_lt,2,1)]) | |
170 | #$(info int_lt,0,3: [$(call int_lt,0,3)]) | |
171 | #$(info int_lt,3,0: [$(call int_lt,3,0)]) | |
172 | #$(info int_lt,1234,1234: [$(call int_lt,1234,1234)]) | |
173 | #$(info int_lt,1235,1234: [$(call int_lt,1235,1234)]) | |
174 | #$(info int_lt,1234,1235: [$(call int_lt,1234,1235)]) | |
175 | # | |
176 | #$(info int_gte,1,1: [$(call int_gte,1,1)]) | |
177 | #$(info int_gte,1,2: [$(call int_gte,1,2)]) | |
178 | #$(info int_gte,2,1: [$(call int_gte,2,1)]) | |
179 | #$(info int_gte,0,3: [$(call int_gte,0,3)]) | |
180 | #$(info int_gte,3,0: [$(call int_gte,3,0)]) | |
181 | #$(info int_gte,1234,1234: [$(call int_gte,1234,1234)]) | |
182 | #$(info int_gte,1235,1234: [$(call int_gte,1235,1234)]) | |
183 | #$(info int_gte,1234,1235: [$(call int_gte,1234,1235)]) | |
184 | # | |
185 | #$(info int_gt,1,1: [$(call int_gt,1,1)]) | |
186 | #$(info int_gt,1,2: [$(call int_gt,1,2)]) | |
187 | #$(info int_gt,2,1: [$(call int_gt,2,1)]) | |
188 | #$(info int_gt,0,3: [$(call int_gt,0,3)]) | |
189 | #$(info int_gt,3,0: [$(call int_gt,3,0)]) | |
190 | #$(info int_gt,1234,1234: [$(call int_gt,1234,1234)]) | |
191 | #$(info int_gt,1235,1234: [$(call int_gt,1235,1234)]) | |
192 | #$(info int_gt,1234,1235: [$(call int_gt,1234,1235)]) | |
4c0073a3 JM |
193 | #$(info int_gt,-1234,1235: [$(call int_gt,-1234,1235)]) |
194 | #$(info int_gt,-1234,-1235: [$(call int_gt,-1234,-1235)]) | |
f4c8a091 JM |
195 | |
196 | ||
197 | ### | |
198 | ### addition | |
199 | ### | |
200 | ||
201 | ||
202 | # add_digits_with_carry | |
203 | _add_digit = $(words $(if $(strip $(1)),$(wordlist 1,$(1),$(LIST20_X)),) \ | |
204 | $(if $(strip $(2)),$(wordlist 1,$(2),$(LIST20_X)),)) | |
205 | ||
206 | # add one to a single digit | |
207 | _inc_digit = $(words $(wordlist 1,$(if $(1),$(1),0),$(LIST20_X)) x) | |
208 | ||
209 | # add two encoded numbers digit by digit without resolving carries | |
210 | # (each digit will be larger than 9 if there is a carry value) | |
211 | _add = $(if $(1)$(2),$(call _add_digit,$(word 1,$(1)),$(word 1,$(2))) $(call _add,$(wordlist 2,$(words $(1)),$(1)),$(wordlist 2,$(words $(2)),$(2))),) | |
212 | ||
213 | # take the result of _add and resolve the carry values digit by digit | |
214 | _resolve_carries = $(strip \ | |
215 | $(if $(1),\ | |
216 | $(foreach num,$(word 1,$(1)),\ | |
217 | $(if $(filter-out 1,$(filter 1%,$(num))),\ | |
218 | $(call _resolve_carries,$(call _inc_digit,$(word 2,$(1))) $(wordlist 3,$(words $(1)),$(1)),$(2) $(patsubst 1%,%,$(num))),\ | |
219 | $(call _resolve_carries,$(wordlist 2,$(words $(1)),$(1)),$(2) $(num)))),\ | |
220 | $(2))) | |
221 | ||
4c0073a3 JM |
222 | _negate = $(strip \ |
223 | $(if $(call _EQ,0,$(strip $(1))),\ | |
224 | 0,\ | |
225 | $(if $(filter -,$(1)),$(filter-out -,$(1)),$(1) -))) | |
226 | ||
f4c8a091 | 227 | # add two encoded numbers, returns encoded number |
4c0073a3 JM |
228 | _int_add_encoded = $(call _resolve_carries,$(call _add,$(1),$(2))) |
229 | ||
230 | int_add_encoded = $(strip \ | |
231 | $(if $(filter -,$(1)),\ | |
232 | $(if $(filter -,$(2)),\ | |
233 | $(call _negate,$(call _int_add_encoded,$(filter-out -,$(1)),$(filter-out -,$(2)))),\ | |
234 | $(call int_sub_encoded,$(2),$(filter-out -,$(1)))),\ | |
235 | $(if $(filter -,$(2)),\ | |
236 | $(call int_sub_encoded,$(1),$(filter-out -,$(2))),\ | |
237 | $(call _int_add_encoded,$(1),$(2))))) | |
f4c8a091 JM |
238 | |
239 | # add two unencoded numbers, returns unencoded number | |
240 | int_add = $(call int_decode,$(call int_add_encoded,$(call int_encode,$(1)),$(call int_encode,$(2)))) | |
241 | ||
242 | ### addition tests | |
243 | ||
244 | #$(info _add_digit(7,6,1): [$(call _add_digit,7,6,1)]) | |
245 | #$(info _add_digit(7,6,0): [$(call _add_digit,7,6,0)]) | |
246 | #$(info _add_digit(7,6,0): [$(call _add_digit,7,6,0)]) | |
247 | #$(info _carries(12 14 15): [$(call _carries,12 14 15)]) | |
248 | #$(info _inc_digit(0): $(call _inc_digit,0)) | |
249 | #$(info _inc_digit(1): $(call _inc_digit,1)) | |
250 | #$(info _inc_digit(9): $(call _inc_digit,9)) | |
251 | #$(info _inc_digit(18): $(call _inc_digit,18)) | |
252 | #$(info int_add_encoded(0,0): [$(call int_add_encoded,0,0)]) | |
253 | ||
254 | #$(info int_add(1,2): [$(call int_add,1,2)]) | |
255 | #$(info int_add(9,9): [$(call int_add,9,9)]) | |
256 | #$(info int_add(0,9): [$(call int_add,0,9)]) | |
257 | #$(info int_add(9,0): [$(call int_add,9,0)]) | |
258 | #$(info int_add(0,0): [$(call int_add,0,0)]) | |
259 | #$(info int_add(123,456): [$(call int_add,123,456)]) | |
260 | #$(info int_add(678,789): [$(call int_add,678,789)]) | |
261 | #$(info int_add(1,12): [$(call int_add,1,12)]) | |
262 | #$(info int_add(123,5): [$(call int_add,123,5)]) | |
263 | #$(info int_add(123456,9): [$(call int_add,123456,9)]) | |
264 | #$(info int_add(999999991,9): [$(call int_add,999999991,9)]) | |
4c0073a3 JM |
265 | # negative numbers |
266 | #$(info int_add(-2,2): [$(call int_add,-2,2)]) | |
267 | #$(info int_add(-1,2): [$(call int_add,-1,2)]) | |
268 | #$(info int_add(1,-2): [$(call int_add,1,-2)]) | |
269 | #$(info int_add(-1,-2): [$(call int_add,-1,-2)]) | |
f4c8a091 JM |
270 | |
271 | ### | |
272 | ### subtraction | |
273 | ### | |
274 | ||
275 | _get_zeros = $(if $(call _EQ,0,$(word 1,$(1))),$(call _get_zeros,$(wordlist 2,$(words $(1)),$(1)),$(2) 0),$(2)) | |
276 | ||
277 | # return a 9's complement of a single digit | |
278 | _complement9 = $(strip \ | |
279 | $(if $(call _EQ,0,$(1)),9,\ | |
280 | $(if $(call _EQ,1,$(1)),8,\ | |
281 | $(if $(call _EQ,2,$(1)),7,\ | |
282 | $(if $(call _EQ,3,$(1)),6,\ | |
283 | $(if $(call _EQ,4,$(1)),5,\ | |
284 | $(if $(call _EQ,5,$(1)),4,\ | |
285 | $(if $(call _EQ,6,$(1)),3,\ | |
286 | $(if $(call _EQ,7,$(1)),2,\ | |
287 | $(if $(call _EQ,8,$(1)),1,\ | |
288 | $(if $(call _EQ,9,$(1)),0))))))))))) | |
289 | ||
290 | # return a 10's complement of a single digit | |
291 | _complement10 = $(call _inc_digit,$(call _complement9,$(1))) | |
292 | ||
293 | # | |
294 | _complement_rest = $(if $(strip $(1)),\ | |
295 | $(strip \ | |
296 | $(call _complement10,$(word 1,$(1))) \ | |
297 | $(foreach digit,$(wordlist 2,$(words $(1)),$(1)),\ | |
298 | $(call _complement9,$(digit)))),) | |
299 | ||
300 | # return the complement of a number | |
301 | _complement = $(strip $(call _get_zeros,$(1)) \ | |
302 | $(call _complement_rest,$(wordlist $(call _inc_digit,$(words $(call _get_zeros,$(1)))),$(words $(1)),$(1)))) | |
303 | ||
304 | # subtracted encoded number 2 from encoded number 1 and return and | |
4c0073a3 JM |
305 | # encoded number result. both numbers must be positive but may have |
306 | # a negative result | |
307 | __int_sub_encoded = $(strip \ | |
f4c8a091 JM |
308 | $(call trim_zeros,\ |
309 | $(call drop_last,\ | |
310 | $(call int_add_encoded,\ | |
311 | $(1),\ | |
4c0073a3 JM |
312 | $(wordlist 1,$(words $(1)),$(call _complement,$(2)) $(LIST100_9)))))) |
313 | ||
314 | _int_sub_encoded = $(strip \ | |
315 | $(if $(call _EQ,0,$(strip $(2))),\ | |
316 | $(1),\ | |
317 | $(if $(call _int_lte_encoded,$(2),$(1)),\ | |
318 | $(call __int_sub_encoded,$(1),$(2)),\ | |
319 | $(call _negate,$(call __int_sub_encoded,$(2),$(1)))))) | |
320 | ||
321 | int_sub_encoded = $(strip \ | |
322 | $(if $(filter -,$(1)),\ | |
323 | $(if $(filter -,$(2)),\ | |
324 | $(call _int_sub_encoded,$(filter-out -,$(2)),$(filter-out -,$(1))),\ | |
325 | $(call _negate,$(call _int_add_encoded,$(filter-out -,$(1)),$(2)))),\ | |
326 | $(if $(filter -,$(2)),\ | |
327 | $(call _int_add_encoded,$(1),$(filter-out -,$(2))),\ | |
328 | $(call _int_sub_encoded,$(1),$(2))))) | |
f4c8a091 JM |
329 | |
330 | # subtract unencoded number 2 from unencoded number 1 and return | |
331 | # unencoded result | |
332 | int_sub = $(call int_decode,$(call int_sub_encoded,$(call int_encode,$(1)),$(call int_encode,$(2)))) | |
333 | ||
334 | ### subtraction tests | |
335 | ||
336 | #$(info _get_zeros(5 7): [$(call _get_zeros,5 7)]) | |
337 | #$(info _get_zeros(0 0 0 2): [$(call _get_zeros,0 0 0 2)]) | |
338 | #$(info _get_zeros(0 0 0 2 5): [$(call _get_zeros,0 0 0 2 5)]) | |
339 | ||
340 | #$(info _complement(0): [$(call _complement,0)]) | |
341 | #$(info _complement(1): [$(call _complement,1)]) | |
342 | #$(info _complement(9): [$(call _complement,9)]) | |
343 | #$(info _complement(5 7): [$(call _complement,5 7)]) | |
344 | #$(info _complement(0 0 0 2): [$(call _complement,0 0 0 2)]) | |
345 | #$(info _complement(0 0 0 5 4 3 2 1): [$(call _complement,0 0 0 5 4 3 2 1)]) | |
346 | ||
347 | #$(info int_sub_encoded(0 0 1, 3 1): [$(call int_sub_encoded,0 0 1,3 1)]) | |
348 | #$(info int_sub_encoded(2, 2): [$(call int_sub_encoded,2,2)]) | |
349 | ||
350 | #$(info int_sub(2,1): [$(call int_sub,2,1)]) | |
351 | #$(info int_sub(2,0): [$(call int_sub,2,0)]) | |
352 | #$(info int_sub(2,2): [$(call int_sub,2,2)]) | |
353 | #$(info int_sub(100,13): [$(call int_sub,100,13)]) | |
354 | #$(info int_sub(100,99): [$(call int_sub,100,99)]) | |
355 | #$(info int_sub(91,19): [$(call int_sub,91,19)]) | |
4c0073a3 JM |
356 | # negative numbers |
357 | #$(info int_sub(1,2): [$(call int_sub,1,2)]) | |
358 | #$(info int_sub(-1,2): [$(call int_sub,-1,2)]) | |
359 | #$(info int_sub(1,-2): [$(call int_sub,1,-2)]) | |
360 | #$(info int_sub(-1,-2): [$(call int_sub,-1,-2)]) | |
361 | #$(info int_sub(-2,-1): [$(call int_sub,-2,-1)]) | |
362 | #$(info int_sub(19,91): [$(call int_sub,19,91)]) | |
363 | #$(info int_sub(91,-19): [$(call int_sub,91,-19)]) | |
364 | #$(info int_sub(-91,19): [$(call int_sub,-91,19)]) | |
365 | #$(info int_sub(-91,-19): [$(call int_sub,-91,-19)]) | |
f4c8a091 JM |
366 | |
367 | ||
368 | ### | |
369 | ### multiplication | |
370 | ### | |
371 | ||
372 | # multiply two digits | |
373 | #_mult_digit = $(words $(foreach x,$(1),$(2))) | |
374 | _mult_digit = $(strip \ | |
375 | $(words $(foreach x,$(wordlist 1,$(1),$(LIST20_X)),\ | |
376 | $(wordlist 1,$(2),$(LIST20_X))))) | |
377 | ||
378 | # multipy every digit of number 1 with number 2 | |
379 | # params: digits, digit, indent_zeros, results | |
380 | _mult_row = $(if $(strip $(1)),$(call _mult_row,$(wordlist 2,$(words $(1)),$(1)),$(2),$(3)0,$(4) $(call _mult_digit,$(word 1,$(1)),$(2))$(3)),$(4)) | |
381 | ||
382 | # multiply every digit of number 2 with every digit of number 1 adding | |
383 | # correct zero padding to the end of each result | |
384 | # params: digits, digits, indent_zeros, results | |
385 | _mult_each = $(if $(strip $(2)),$(call _mult_each,$(1),$(wordlist 2,$(words $(2)),$(2)),$(3)0,$(4) $(call _mult_row,$(1),$(word 1,$(2)),$(3))),$(4)) | |
386 | ||
387 | # add up a bunch of unencoded numbers. Basically reduce into the first number | |
388 | _add_many = $(if $(word 2,$(1)),$(call _add_many,$(call int_add,$(word 1,$(1)),$(word 2,$(1))) $(wordlist 3,$(words $(1)),$(1))),$(1)) | |
389 | ||
390 | # multiply two encoded numbers, returns encoded number | |
4c0073a3 JM |
391 | _int_mult_encoded = $(call trim_zeros,$(call int_encode,$(call _add_many,$(call _mult_each,$(1),$(2))))) |
392 | ||
393 | int_mult_encoded = $(strip \ | |
394 | $(if $(filter -,$(1)),\ | |
395 | $(if $(filter -,$(2)),\ | |
396 | $(call _int_mult_encoded,$(filter-out -,$(1)),$(filter-out -,$(2))),\ | |
397 | $(call _negate,$(call _int_mult_encoded,$(filter-out -,$(1)),$(2)))),\ | |
398 | $(if $(filter -,$(2)),\ | |
399 | $(call _negate,$(call _int_mult_encoded,$(1),$(filter-out -,$(2)))),\ | |
400 | $(call _int_mult_encoded,$(1),$(2))))) | |
f4c8a091 JM |
401 | |
402 | # multiply two unencoded numbers, returns unencoded number | |
403 | int_mult = $(call int_decode,$(call int_mult_encoded,$(call int_encode,$(1)),$(call int_encode,$(2)))) | |
404 | ||
405 | #$(info _mult_digit(8,6): [$(call _mult_digit,8,6)]) | |
406 | #$(info _mult_digit(7,6): [$(call _mult_digit,7,6)]) | |
407 | #$(info _mult_row(8,6): [$(call _mult_row,8,6)]) | |
408 | #$(info _mult_row(8 7,6): [$(call _mult_row,8 7,6)]) | |
409 | #$(info _mult_row(8 7 3,6): [$(call _mult_row,8 7 3,6)]) | |
410 | #$(info _mult_each(8 7 6, 4 3 2): [$(call _mult_each,8 7 6,4 3 2)]) | |
411 | #$(info _add_many(123 234 345 456): [$(call _add_many,123 234 345 456)]) | |
412 | ||
413 | #$(info int_mult_encoded(8 7 3,6): [$(call int_mult_encoded,8 7 3,6)]) | |
414 | #$(info int_mult_encoded(8 7 3,0): [$(call int_mult_encoded,8 7 3,0)]) | |
415 | ||
416 | #$(info int_mult(378,6): [$(call int_mult,378,6)]) | |
417 | #$(info int_mult(678,234): [$(call int_mult,678,234)]) | |
418 | #$(info int_mult(1,23456): [$(call int_mult,1,23456)]) | |
419 | #$(info int_mult(0,23456): [$(call int_mult,0,23456)]) | |
420 | #$(info int_mult(0,0): [$(call int_mult,0,0)]) | |
4c0073a3 JM |
421 | # negative numbers |
422 | #$(info int_mult(-378,6): [$(call int_mult,-378,6)]) | |
423 | #$(info int_mult(678,-234): [$(call int_mult,678,-234)]) | |
424 | #$(info int_mult(-1,-23456): [$(call int_mult,-1,-23456)]) | |
425 | #$(info int_mult(0,-23456): [$(call int_mult,0,-23456)]) | |
f4c8a091 JM |
426 | |
427 | ### | |
428 | ### division | |
429 | ### | |
430 | ||
431 | # return list of zeros needed to pad number 2 to the same length as number 1 | |
432 | _zero_pad = $(strip $(wordlist 1,$(call int_sub,$(words $(1)),$(words $(2))),$(LIST100_0))) | |
433 | ||
434 | # num1, num2, zero pad, result_accumulator | |
435 | # algorithm: | |
436 | # - B = pad with zeros to make same digit length as A | |
437 | # - loop | |
438 | # - if (B <= A) | |
439 | # - A = subtract B from A | |
440 | # - C = C + 10^(B pad.length) | |
441 | # - else | |
442 | # - if B.length < origin B.length: break | |
443 | # - chop least significant digit of B | |
444 | _div = $(strip \ | |
445 | $(if $(call int_lte_encoded,$(3) $(2),$(1)),\ | |
446 | $(call _div,$(call int_sub_encoded,$(1),$(3) $(2)),$(2),$(3),$(call int_add_encoded,$(4),$(3) 1)),\ | |
447 | $(if $(3),\ | |
448 | $(call _div,$(1),$(2),$(wordlist 2,$(words $(3)),$(3)),$(4)),\ | |
449 | $(4)))) | |
450 | ||
451 | # divide two encoded numbers, returns encoded number | |
4c0073a3 | 452 | _int_div_encoded = $(strip \ |
f4c8a091 JM |
453 | $(if $(call _EQ,0,$(1)),\ |
454 | 0,\ | |
455 | $(if $(call _EQ,$(1),$(2)),\ | |
456 | 1,\ | |
457 | $(if $(call int_gt_encoded,$(2),$(1)),\ | |
458 | 0,\ | |
459 | $(call _div,$(1),$(2),$(call _zero_pad,$(1),$(2)),0))))) | |
460 | ||
4c0073a3 JM |
461 | int_div_encoded = $(strip \ |
462 | $(if $(filter -,$(1)),\ | |
463 | $(if $(filter -,$(2)),\ | |
464 | $(call _int_div_encoded,$(filter-out -,$(1)),$(filter-out -,$(2))),\ | |
465 | $(call _negate,$(call _int_div_encoded,$(filter-out -,$(1)),$(2)))),\ | |
466 | $(if $(filter -,$(2)),\ | |
467 | $(call _negate,$(call _int_div_encoded,$(1),$(filter-out -,$(2)))),\ | |
468 | $(call _int_div_encoded,$(1),$(2))))) | |
469 | ||
f4c8a091 JM |
470 | # divide two unencoded numbers, returns unencoded number |
471 | int_div = $(call int_decode,$(call int_div_encoded,$(call int_encode,$(1)),$(call int_encode,$(2)))) | |
472 | ||
473 | ### division tests | |
474 | ||
475 | #$(info _zero_pad(1 2 3 4,1 3): [$(call _zero_pad,1 2 3 4,1 3)]) | |
476 | #$(info _zero_pad(1 2,1 3): [$(call _zero_pad,1 2,1 3)]) | |
477 | #$(info _zero_pad(2,1 3): [$(call _zero_pad,1 2,1 3)]) | |
478 | # | |
479 | #$(info int_div_encoded(2,1): [$(call int_div_encoded,2,1)]) | |
480 | #$(info int_div_encoded(3,1): [$(call int_div_encoded,3,1)]) | |
481 | #$(info int_div_encoded(3,2): [$(call int_div_encoded,3,2)]) | |
482 | #$(info int_div_encoded(0,7): [$(call int_div_encoded,0,7)]) | |
483 | #$(info int_div_encoded(0 3,0 2): [$(call int_div_encoded,0 3,0 2)]) | |
484 | #$(info int_div_encoded(0 3,5): [$(call int_div_encoded,0 3,5)]) | |
485 | # | |
486 | #$(info int_div(5,1): [$(call int_div,5,1)]) | |
487 | #$(info int_div(5,2): [$(call int_div,5,2)]) | |
488 | #$(info int_div(123,7): [$(call int_div,123,7)]) | |
489 | #$(info int_div(100,7): [$(call int_div,100,7)]) | |
4c0073a3 JM |
490 | # negative numbers |
491 | #$(info int_div(-5,1): [$(call int_div,-5,1)]) | |
492 | #$(info int_div(5,-2): [$(call int_div,5,-2)]) | |
493 | #$(info int_div(-123,-7): [$(call int_div,-123,-7)]) | |
f4c8a091 JM |
494 | |
495 | ||
496 | ### combination tests | |
497 | ||
4c0073a3 | 498 | # (/ (- (+ 515 (* 222 311)) 300) 41) = 1689 |
f4c8a091 JM |
499 | #$(info int_mult,222,311: [$(call int_mult,222,311)]) |
500 | #$(info int_add(515,69042): [$(call int_add,515,69042)]) | |
501 | #$(info int_sub(69557,300): [$(call int_sub,69557,300)]) | |
502 | #$(info int_div(69257,41): [$(call int_div,69257,41)]) | |
4c0073a3 JM |
503 | # (/ (- (+ 515 (* -222 311)) 300) 41) = -1678 |
504 | #$(info int_mult,-222,311: [$(call int_mult,-222,311)]) | |
505 | #$(info int_add(515,-69042): [$(call int_add,515,-69042)]) | |
506 | #$(info int_sub(-68527,300): [$(call int_sub,-68527,300)]) | |
507 | #$(info int_div(-68827,41): [$(call int_div,-68827,41)]) | |
f4c8a091 JM |
508 | |
509 | ############################################################### | |
510 | ||
511 | all: | |
512 | @true | |
513 | ||
514 | endif | |
515 | ||
516 | # vim: ts=2 et |