blob: 3486c7ab01a8512b83d97bd8e2fb591242f34ae3 [file] [log] [blame]
Steven Morelanda64f3362017-05-31 12:48:55 -07001#
2# Copyright (C) 2017 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17###########################################################
18# Basic math functions for positive integers <= 100
19#
20# (SDK versions for example)
21###########################################################
22__MATH_NUMBERS := 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
23 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
24 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
25 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
26 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
27
Colin Cross5bc27ea2018-05-09 13:28:06 -070028math-error = $(call pretty-error,$(1))
29math-expect :=
30math-expect-true :=
31math-expect :=
32math-expect-error :=
33
34# Run the math tests with:
35# make -f ${ANDROID_BUILD_TOP}/build/make/core/math.mk RUN_MATH_TESTS=true
36# $(get_build_var CKATI) -f ${ANDROID_BUILD_TOP}//build/make/core/math.mk RUN_MATH_TESTS=true
37ifdef RUN_MATH_TESTS
38 MATH_TEST_FAILURE :=
39 MATH_TEST_ERROR :=
40 math-error = $(if $(MATH_TEST_ERROR),,$(eval MATH_TEST_ERROR:=$(1)))
41 define math-expect
42 $(eval got:=$$$1) \
43 $(if $(subst $(got),,$(2))$(subst $(2),,$(got))$(MATH_TEST_ERROR), \
44 $(if $(MATH_TEST_ERROR),$(warning $(MATH_TEST_ERROR)),$(warning $$$1 '$(got)' != '$(2)')) \
45 $(eval MATH_TEST_FAILURE := true)) \
46 $(eval MATH_TEST_ERROR :=) \
47 $(eval got:=)
48 endef
49 math-expect-true = $(call math-expect,$(1),true)
50 math-expect-false = $(call math-expect,$(1),)
51
52 define math-expect-error
53 $(eval got:=$$$1) \
54 $(if $(subst $(MATH_TEST_ERROR),,$(2))$(subst $(2),,$(MATH_TEST_ERROR)), \
55 $(warning '$(MATH_TEST_ERROR)' != '$(2)') \
56 $(eval MATH_TEST_FAILURE := true)) \
57 $(eval MATH_TEST_ERROR :=) \
58 $(eval got:=)
59 endef
60endif
61
62
Steven Morelanda64f3362017-05-31 12:48:55 -070063# Returns true if $(1) is a positive integer <= 100, otherwise returns nothing.
64define math_is_number
65$(strip \
Colin Cross5bc27ea2018-05-09 13:28:06 -070066 $(if $(1),,$(call math-error,Argument missing)) \
67 $(if $(word 2,$(1)),$(call math-error,Multiple words in a single argument: $(1))) \
Steven Morelanda64f3362017-05-31 12:48:55 -070068 $(if $(filter $(1),$(__MATH_NUMBERS)),true))
69endef
70
Colin Cross5bc27ea2018-05-09 13:28:06 -070071
72$(call math-expect-true,(call math_is_number,2))
73$(call math-expect-false,(call math_is_number,foo))
74$(call math-expect-false,(call math_is_number,-1))
75$(call math-expect-error,(call math_is_number,1 2),Multiple words in a single argument: 1 2)
76$(call math-expect-error,(call math_is_number,no 2),Multiple words in a single argument: no 2)
Steven Morelanda64f3362017-05-31 12:48:55 -070077
78define _math_check_valid
Colin Cross5bc27ea2018-05-09 13:28:06 -070079$(if $(call math_is_number,$(1)),,$(call math-error,Only positive integers <= 100 are supported (not $(1))))
Steven Morelanda64f3362017-05-31 12:48:55 -070080endef
81
Colin Cross5bc27ea2018-05-09 13:28:06 -070082$(call math-expect,(call _math_check_valid,1))
83$(call math-expect,(call _math_check_valid,100))
84$(call math-expect-error,(call _math_check_valid,-1),Only positive integers <= 100 are supported (not -1))
85$(call math-expect-error,(call _math_check_valid,101),Only positive integers <= 100 are supported (not 101))
86$(call math-expect-error,(call _math_check_valid,),Argument missing)
87$(call math-expect-error,(call _math_check_valid,1 2),Multiple words in a single argument: 1 2)
88
Nan Zhangad818dc2017-10-04 09:26:06 -070089# return a list containing integers ranging from [$(1),$(2)]
90define int_range_list
Colin Cross5bc27ea2018-05-09 13:28:06 -070091$(strip $(call _math_check_valid,$(1))$(call _math_check_valid,$(2))$(wordlist $(1),$(2),$(__MATH_NUMBERS)))
Nan Zhangad818dc2017-10-04 09:26:06 -070092endef
93
Colin Cross5bc27ea2018-05-09 13:28:06 -070094$(call math-expect,(call int_range_list,1,1),1)
95$(call math-expect,(call int_range_list,1,2),1 2)
96$(call math-expect,(call int_range_list,2,1),)
97$(call math-expect-error,(call int_range_list,1,101),Only positive integers <= 100 are supported (not 101))
98
Steven Morelanda64f3362017-05-31 12:48:55 -070099
100# Returns the greater of $1 or $2.
101# If $1 or $2 is not a positive integer <= 100, then an error is generated.
102define math_max
103$(strip $(call _math_check_valid,$(1)) $(call _math_check_valid,$(2)) \
104 $(lastword $(filter $(1) $(2),$(__MATH_NUMBERS))))
105endef
106
Colin Cross5bc27ea2018-05-09 13:28:06 -0700107$(call math-expect-error,(call math_max),Argument missing)
108$(call math-expect-error,(call math_max,1),Argument missing)
109$(call math-expect-error,(call math_max,1 2,3),Multiple words in a single argument: 1 2)
110$(call math-expect,(call math_max,1,1),1)
111$(call math-expect,(call math_max,5,42),42)
112$(call math-expect,(call math_max,42,5),42)
Steven Morelanda64f3362017-05-31 12:48:55 -0700113
114define math_gt_or_eq
115$(if $(filter $(1),$(call math_max,$(1),$(2))),true)
116endef
117
Colin Crossf9602572017-10-12 13:34:40 -0700118define math_lt
119$(if $(call math_gt_or_eq,$(1),$(2)),,true)
120endef
121
Colin Cross5bc27ea2018-05-09 13:28:06 -0700122$(call math-expect-true,(call math_gt_or_eq, 2, 1))
123$(call math-expect-true,(call math_gt_or_eq, 1, 1))
124$(call math-expect-false,(call math_gt_or_eq, 1, 2))
Steven Morelanda64f3362017-05-31 12:48:55 -0700125
126# $1 is the variable name to increment
127define inc_and_print
128$(strip $(eval $(1) := $($(1)) .)$(words $($(1))))
129endef
Nan Zhangad818dc2017-10-04 09:26:06 -0700130
Colin Cross5bc27ea2018-05-09 13:28:06 -0700131ifdef RUN_MATH_TESTS
132a :=
133$(call math-expect,(call inc_and_print,a),1)
134$(call math-expect,(call inc_and_print,a),2)
135$(call math-expect,(call inc_and_print,a),3)
136$(call math-expect,(call inc_and_print,a),4)
137endif
138
Colin Crossf9602572017-10-12 13:34:40 -0700139# Returns the words in $2 that are numbers and are less than $1
140define numbers_less_than
141$(strip \
142 $(foreach n,$2, \
143 $(if $(call math_is_number,$(n)), \
144 $(if $(call math_lt,$(n),$(1)), \
145 $(n)))))
146endef
147
Colin Cross5bc27ea2018-05-09 13:28:06 -0700148$(call math-expect,(call numbers_less_than,1,2 1 3),)
149$(call math-expect,(call numbers_less_than,2,2 1 3),1)
150$(call math-expect,(call numbers_less_than,3,2 1 3),2 1)
151$(call math-expect,(call numbers_less_than,4,2 1 3),2 1 3)
152$(call math-expect,(call numbers_less_than,3,2 1 3 2),2 1 2)
153
Nan Zhangad818dc2017-10-04 09:26:06 -0700154_INT_LIMIT_WORDS := $(foreach a,x x,$(foreach b,x x x x x x x x x x x x x x x x,\
155 $(foreach c,x x x x x x x x x x x x x x x x,x x x x x x x x x x x x x x x x)))
156
157define _int_encode
158$(if $(filter $(words x $(_INT_LIMIT_WORDS)),$(words $(wordlist 1,$(1),x $(_INT_LIMIT_WORDS)))),\
Colin Cross5bc27ea2018-05-09 13:28:06 -0700159 $(call math-error,integer greater than $(words $(_INT_LIMIT_WORDS)) is not supported!),\
Nan Zhangad818dc2017-10-04 09:26:06 -0700160 $(wordlist 1,$(1),$(_INT_LIMIT_WORDS)))
161endef
162
163# _int_max returns the maximum of the two arguments
164# input: two (x) lists; output: one (x) list
165# integer cannot be passed in directly. It has to be converted using _int_encode.
166define _int_max
167$(subst xx,x,$(join $(1),$(2)))
168endef
169
170# first argument is greater than second argument
171# output: non-empty if true
172# integer cannot be passed in directly. It has to be converted using _int_encode.
173define _int_greater-than
174$(filter-out $(words $(2)),$(words $(call _int_max,$(1),$(2))))
175endef
176
177# first argument equals to second argument
178# output: non-empty if true
179# integer cannot be passed in directly. It has to be converted using _int_encode.
180define _int_equal
181$(filter $(words $(1)),$(words $(2)))
182endef
183
184# first argument is greater than or equal to second argument
185# output: non-empty if true
186# integer cannot be passed in directly. It has to be converted using _int_encode.
187define _int_greater-or-equal
188$(call _int_greater-than,$(1),$(2))$(call _int_equal,$(1),$(2))
189endef
190
191define int_plus
192$(words $(call _int_encode,$(1)) $(call _int_encode,$(2)))
193endef
194
Colin Cross5bc27ea2018-05-09 13:28:06 -0700195$(call math-expect,(call int_plus,0,0),0)
196$(call math-expect,(call int_plus,0,1),1)
197$(call math-expect,(call int_plus,1,0),1)
198$(call math-expect,(call int_plus,1,100),101)
199$(call math-expect,(call int_plus,100,100),200)
200
Nan Zhangad818dc2017-10-04 09:26:06 -0700201define int_subtract
Colin Cross5bc27ea2018-05-09 13:28:06 -0700202$(strip \
203 $(if $(call _int_greater-or-equal,$(call _int_encode,$(1)),$(call _int_encode,$(2))),\
Nan Zhangad818dc2017-10-04 09:26:06 -0700204 $(words $(filter-out xx,$(join $(call _int_encode,$(1)),$(call _int_encode,$(2))))),\
Colin Cross5bc27ea2018-05-09 13:28:06 -0700205 $(call math-error,subtract underflow $(1) - $(2))))
Nan Zhangad818dc2017-10-04 09:26:06 -0700206endef
207
Colin Cross5bc27ea2018-05-09 13:28:06 -0700208$(call math-expect,(call int_subtract,0,0),0)
209$(call math-expect,(call int_subtract,1,0),1)
210$(call math-expect,(call int_subtract,1,1),0)
211$(call math-expect,(call int_subtract,100,1),99)
212$(call math-expect,(call int_subtract,200,100),100)
213$(call math-expect-error,(call int_subtract,0,1),subtract underflow 0 - 1)
214
Nan Zhangad818dc2017-10-04 09:26:06 -0700215define int_multiply
216$(words $(foreach a,$(call _int_encode,$(1)),$(call _int_encode,$(2))))
217endef
218
Colin Cross5bc27ea2018-05-09 13:28:06 -0700219$(call math-expect,(call int_multiply,0,0),0)
220$(call math-expect,(call int_multiply,1,0),0)
221$(call math-expect,(call int_multiply,1,1),1)
222$(call math-expect,(call int_multiply,100,1),100)
223$(call math-expect,(call int_multiply,1,100),100)
224$(call math-expect,(call int_multiply,4,100),400)
225$(call math-expect,(call int_multiply,100,4),400)
226
Nan Zhangad818dc2017-10-04 09:26:06 -0700227define int_divide
Colin Cross5bc27ea2018-05-09 13:28:06 -0700228$(if $(filter 0,$(2)),$(call math-error,division by zero is not allowed!),$(strip \
Nan Zhangad818dc2017-10-04 09:26:06 -0700229 $(if $(call _int_greater-or-equal,$(call _int_encode,$(1)),$(call _int_encode,$(2))), \
230 $(call int_plus,$(call int_divide,$(call int_subtract,$(1),$(2)),$(2)),1),0)))
231endef
Colin Cross5bc27ea2018-05-09 13:28:06 -0700232
233$(call math-expect,(call int_divide,1,1),1)
234$(call math-expect,(call int_divide,200,1),200)
235$(call math-expect,(call int_divide,200,3),66)
236$(call math-expect,(call int_divide,1,2),0)
237$(call math-expect-error,(call int_divide,0,0),division by zero is not allowed!)
238$(call math-expect-error,(call int_divide,1,0),division by zero is not allowed!)
239
240ifdef RUN_MATH_TESTS
241 ifdef MATH_TEST_FAILURE
242 math-tests:
243 @echo FAIL
244 @false
245 else
246 math-tests:
247 @echo PASS
248 endif
249 .PHONY: math-tests
250endif