DISABLE FDs (REMOVE ME).
[jackhill/mal.git] / make / numbers.mk
CommitLineData
f4c8a091
JM
1#
2# mal (Make a Lisp) number types
3#
4
5ifndef __mal_numbers_included
6__mal_numbers_included := true
7
8_TOP_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
9include $(_TOP_DIR)util.mk
10
11LIST20_X := x x x x x x x x x x x x x x x x x x x x
12LIST100_X := $(foreach x,$(LIST20_X),X X X X X)
13LIST100_0 := $(foreach x,$(LIST20_X),0 0 0 0 0)
14LIST100_9 := $(foreach x,$(LIST20_X),9 9 9 9 9)
15
16###
17### general numeric utility functions
18###
19
20int_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
25int_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
29trim_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
36drop_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 84int_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
93int_lte = $(call int_lte_encoded,$(call int_encode,$(1)),$(call int_encode,$(2)))
94
95### lt/less than
96
97int_lt_encoded = $(strip \
98 $(if $(call _EQ,$(strip $(1)),$(strip $(2))),\
99 ,\
100 $(call int_lte_encoded,$(1),$(2))))
101
102int_lt = $(call int_lt_encoded,$(call int_encode,$(1)),$(call int_encode,$(2)))
103
104### gte/greater than or equal to
105
106int_gte_encoded = $(strip \
107 $(if $(call _EQ,$(strip $(1)),$(strip $(2))),\
108 true,\
109 $(if $(call int_lte_encoded,$(1),$(2)),,true)))
110
111int_gte = $(call int_gte_encoded,$(call int_encode,$(1)),$(call int_encode,$(2)))
112
113### gt/greater than
114
115int_gt_encoded = $(strip \
116 $(if $(call _EQ,$(strip $(1)),$(strip $(2))),\
117 ,\
118 $(call int_gte_encoded,$(1),$(2))))
119
120int_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
230int_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
240int_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
321int_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
332int_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
393int_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
403int_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
461int_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
471int_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
511all:
512 @true
513
514endif
515
516# vim: ts=2 et