/src/moddable/xs/sources/xsMath.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2016-2025 Moddable Tech, Inc. |
3 | | * |
4 | | * This file is part of the Moddable SDK Runtime. |
5 | | * |
6 | | * The Moddable SDK Runtime is free software: you can redistribute it and/or modify |
7 | | * it under the terms of the GNU Lesser General Public License as published by |
8 | | * the Free Software Foundation, either version 3 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * The Moddable SDK Runtime is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public License |
17 | | * along with the Moddable SDK Runtime. If not, see <http://www.gnu.org/licenses/>. |
18 | | * |
19 | | * This file incorporates work covered by the following copyright and |
20 | | * permission notice: |
21 | | * |
22 | | * Copyright (C) 2010-2016 Marvell International Ltd. |
23 | | * Copyright (C) 2002-2010 Kinoma, Inc. |
24 | | * |
25 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
26 | | * you may not use this file except in compliance with the License. |
27 | | * You may obtain a copy of the License at |
28 | | * |
29 | | * http://www.apache.org/licenses/LICENSE-2.0 |
30 | | * |
31 | | * Unless required by applicable law or agreed to in writing, software |
32 | | * distributed under the License is distributed on an "AS IS" BASIS, |
33 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
34 | | * See the License for the specific language governing permissions and |
35 | | * limitations under the License. |
36 | | */ |
37 | | |
38 | | #include "xsAll.h" |
39 | | |
40 | | #include "xsum.c" |
41 | | |
42 | | void fxBuildMath(txMachine* the) |
43 | 30.4k | { |
44 | 30.4k | txSlot* slot; |
45 | 30.4k | mxPush(mxObjectPrototype); |
46 | 30.4k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
47 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_abs), 1, mxID(_abs), XS_DONT_ENUM_FLAG); |
48 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_acos), 1, mxID(_acos), XS_DONT_ENUM_FLAG); |
49 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_acosh), 1, mxID(_acosh), XS_DONT_ENUM_FLAG); |
50 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_asin), 1, mxID(_asin), XS_DONT_ENUM_FLAG); |
51 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_asinh), 1, mxID(_asinh), XS_DONT_ENUM_FLAG); |
52 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_atan), 1, mxID(_atan), XS_DONT_ENUM_FLAG); |
53 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_atanh), 1, mxID(_atanh), XS_DONT_ENUM_FLAG); |
54 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_atan2), 2, mxID(_atan2), XS_DONT_ENUM_FLAG); |
55 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_cbrt), 1, mxID(_cbrt), XS_DONT_ENUM_FLAG); |
56 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_ceil), 1, mxID(_ceil), XS_DONT_ENUM_FLAG); |
57 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_clz32), 1, mxID(_clz32), XS_DONT_ENUM_FLAG); |
58 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_cos), 1, mxID(_cos), XS_DONT_ENUM_FLAG); |
59 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_cosh), 1, mxID(_cosh), XS_DONT_ENUM_FLAG); |
60 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_exp), 1, mxID(_exp), XS_DONT_ENUM_FLAG); |
61 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_expm1), 1, mxID(_expm1), XS_DONT_ENUM_FLAG); |
62 | 30.4k | #if mxFloat16 |
63 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_f16round), 1, mxID(_f16round), XS_DONT_ENUM_FLAG); |
64 | 30.4k | #endif |
65 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_floor), 1, mxID(_floor), XS_DONT_ENUM_FLAG); |
66 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_fround), 1, mxID(_fround), XS_DONT_ENUM_FLAG); |
67 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_hypot), 2, mxID(_hypot_), XS_DONT_ENUM_FLAG); |
68 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_idiv), 2, mxID(_idiv), XS_DONT_ENUM_FLAG); |
69 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_idivmod), 2, mxID(_idivmod), XS_DONT_ENUM_FLAG); |
70 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_imod), 2, mxID(_imod), XS_DONT_ENUM_FLAG); |
71 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_imul), 2, mxID(_imul), XS_DONT_ENUM_FLAG); |
72 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_imuldiv), 2, mxID(_imuldiv), XS_DONT_ENUM_FLAG); |
73 | 30.4k | #if mxECMAScript2023 |
74 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_irandom), 0, mxID(_irandom), XS_DONT_ENUM_FLAG); |
75 | 30.4k | #endif |
76 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_irem), 2, mxID(_irem), XS_DONT_ENUM_FLAG); |
77 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_log), 1, mxID(_log), XS_DONT_ENUM_FLAG); |
78 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_log1p), 1, mxID(_log1p), XS_DONT_ENUM_FLAG); |
79 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_log10), 1, mxID(_log10), XS_DONT_ENUM_FLAG); |
80 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_log2), 1, mxID(_log2), XS_DONT_ENUM_FLAG); |
81 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_max), 2, mxID(_max), XS_DONT_ENUM_FLAG); |
82 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_min), 2, mxID(_min), XS_DONT_ENUM_FLAG); |
83 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_mod), 2, mxID(_mod), XS_DONT_ENUM_FLAG); |
84 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_pow), 2, mxID(_pow), XS_DONT_ENUM_FLAG); |
85 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_random), 0, mxID(_random), XS_DONT_ENUM_FLAG); |
86 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_round), 1, mxID(_round), XS_DONT_ENUM_FLAG); |
87 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_sign), 1, mxID(_sign), XS_DONT_ENUM_FLAG); |
88 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_sin), 1, mxID(_sin), XS_DONT_ENUM_FLAG); |
89 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_sinh), 1, mxID(_sinh), XS_DONT_ENUM_FLAG); |
90 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_sqrt), 1, mxID(_sqrt), XS_DONT_ENUM_FLAG); |
91 | 30.4k | #if mxECMAScript2026 |
92 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_sumPrecise), 1, mxID(_sumPrecise), XS_DONT_ENUM_FLAG); |
93 | 30.4k | #endif |
94 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_tan), 1, mxID(_tan), XS_DONT_ENUM_FLAG); |
95 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_tanh), 1, mxID(_tanh), XS_DONT_ENUM_FLAG); |
96 | 30.4k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_trunc), 1, mxID(_trunc), XS_DONT_ENUM_FLAG); |
97 | 30.4k | slot = fxNextNumberProperty(the, slot, C_M_E, mxID(_E), XS_GET_ONLY); |
98 | 30.4k | slot = fxNextNumberProperty(the, slot, C_M_LN10, mxID(_LN10), XS_GET_ONLY); |
99 | 30.4k | slot = fxNextNumberProperty(the, slot, C_M_LN2, mxID(_LN2), XS_GET_ONLY); |
100 | 30.4k | slot = fxNextNumberProperty(the, slot, C_M_LOG10E, mxID(_LOG10E), XS_GET_ONLY); |
101 | 30.4k | slot = fxNextNumberProperty(the, slot, C_M_LOG2E, mxID(_LOG2E), XS_GET_ONLY); |
102 | 30.4k | slot = fxNextNumberProperty(the, slot, C_M_PI, mxID(_PI), XS_GET_ONLY); |
103 | 30.4k | slot = fxNextNumberProperty(the, slot, C_M_SQRT1_2, mxID(_SQRT1_2), XS_GET_ONLY); |
104 | 30.4k | slot = fxNextNumberProperty(the, slot, C_M_SQRT2, mxID(_SQRT2), XS_GET_ONLY); |
105 | 30.4k | slot = fxNextStringXProperty(the, slot, "Math", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG); |
106 | 30.4k | mxPull(mxMathObject); |
107 | | //@@ c_srand((unsigned)c_time(0)); |
108 | 30.4k | } |
109 | | |
110 | | #define mxNanResultIfNoArg \ |
111 | 2.50M | if (mxArgc < 1) { \ |
112 | 11.3k | mxResult->kind = XS_NUMBER_KIND; \ |
113 | 11.3k | mxResult->value.number = C_NAN; \ |
114 | 11.3k | return; \ |
115 | 11.3k | } |
116 | | |
117 | | #define mxNanResultIfNoArg2 \ |
118 | 1.21M | if (mxArgc < 2) { \ |
119 | 56.7k | mxResult->kind = XS_NUMBER_KIND; \ |
120 | 56.7k | mxResult->value.number = C_NAN; \ |
121 | 56.7k | return; \ |
122 | 56.7k | } |
123 | | |
124 | | void fx_Math_abs(txMachine* the) |
125 | 14 | { |
126 | 14 | mxNanResultIfNoArg; |
127 | 14 | fxToNumber(the, mxArgv(0)); |
128 | 14 | mxResult->kind = XS_NUMBER_KIND; |
129 | 14 | mxResult->value.number = c_fabs(mxArgv(0)->value.number); |
130 | 14 | } |
131 | | |
132 | | void fx_Math_acos(txMachine* the) |
133 | 5.58k | { |
134 | 5.58k | mxNanResultIfNoArg; |
135 | 5.14k | fxToNumber(the, mxArgv(0)); |
136 | 5.14k | mxResult->kind = XS_NUMBER_KIND; |
137 | 5.14k | mxResult->value.number = c_acos(mxArgv(0)->value.number); |
138 | 5.14k | } |
139 | | |
140 | | void fx_Math_acosh(txMachine* the) |
141 | 6.39k | { |
142 | 6.39k | mxNanResultIfNoArg; |
143 | 5.58k | fxToNumber(the, mxArgv(0)); |
144 | 5.58k | mxResult->kind = XS_NUMBER_KIND; |
145 | 5.58k | mxResult->value.number = c_acosh(mxArgv(0)->value.number); |
146 | 5.58k | } |
147 | | |
148 | | void fx_Math_asin(txMachine* the) |
149 | 6.82k | { |
150 | 6.82k | mxNanResultIfNoArg; |
151 | 6.33k | fxToNumber(the, mxArgv(0)); |
152 | 6.33k | mxResult->kind = XS_NUMBER_KIND; |
153 | 6.33k | mxResult->value.number = c_asin(mxArgv(0)->value.number); |
154 | 6.33k | } |
155 | | |
156 | | void fx_Math_asinh(txMachine* the) |
157 | 58.8k | { |
158 | 58.8k | mxNanResultIfNoArg; |
159 | 57.5k | fxToNumber(the, mxArgv(0)); |
160 | 57.5k | mxResult->kind = XS_NUMBER_KIND; |
161 | 57.5k | mxResult->value.number = c_asinh(mxArgv(0)->value.number); |
162 | 57.5k | } |
163 | | |
164 | | void fx_Math_atan(txMachine* the) |
165 | 1.00k | { |
166 | 1.00k | mxNanResultIfNoArg; |
167 | 992 | fxToNumber(the, mxArgv(0)); |
168 | 992 | mxResult->kind = XS_NUMBER_KIND; |
169 | 992 | mxResult->value.number = c_atan(mxArgv(0)->value.number); |
170 | 992 | } |
171 | | |
172 | | void fx_Math_atanh(txMachine* the) |
173 | 110k | { |
174 | 110k | mxNanResultIfNoArg; |
175 | 109k | fxToNumber(the, mxArgv(0)); |
176 | 109k | mxResult->kind = XS_NUMBER_KIND; |
177 | 109k | mxResult->value.number = c_atanh(mxArgv(0)->value.number); |
178 | 109k | } |
179 | | |
180 | | void fx_Math_atan2(txMachine* the) |
181 | 948k | { |
182 | 948k | mxNanResultIfNoArg; |
183 | 948k | fxToNumber(the, mxArgv(0)); |
184 | 948k | mxNanResultIfNoArg2; |
185 | 948k | fxToNumber(the, mxArgv(1)); |
186 | 948k | mxResult->kind = XS_NUMBER_KIND; |
187 | 948k | mxResult->value.number = c_atan2(mxArgv(0)->value.number, mxArgv(1)->value.number); |
188 | 948k | } |
189 | | |
190 | | void fx_Math_cbrt(txMachine* the) |
191 | 24 | { |
192 | 24 | mxNanResultIfNoArg; |
193 | 24 | fxToNumber(the, mxArgv(0)); |
194 | 24 | mxResult->kind = XS_NUMBER_KIND; |
195 | 24 | mxResult->value.number = c_cbrt(mxArgv(0)->value.number); |
196 | 24 | } |
197 | | |
198 | | void fx_Math_ceil(txMachine* the) |
199 | 174k | { |
200 | 174k | mxNanResultIfNoArg; |
201 | 174k | if (XS_INTEGER_KIND == mxArgv(0)->kind) { |
202 | 9 | mxResult->kind = XS_INTEGER_KIND; |
203 | 9 | mxResult->value.integer = mxArgv(0)->value.integer; |
204 | 9 | return; |
205 | 9 | } |
206 | 174k | fxToNumber(the, mxArgv(0)); |
207 | 174k | mxResult->kind = XS_NUMBER_KIND; |
208 | 174k | mxResult->value.number = c_ceil(mxArgv(0)->value.number); |
209 | 174k | fx_Math_toInteger(the); |
210 | 174k | } |
211 | | |
212 | | void fx_Math_clz32(txMachine* the) |
213 | 48 | { |
214 | 48 | txUnsigned x = (mxArgc > 0) ? fxToUnsigned(the, mxArgv(0)) : 0; |
215 | 48 | txInteger r; |
216 | 48 | if (x) |
217 | | #if mxWindows |
218 | | { |
219 | | _BitScanReverse(&r, x); |
220 | | r = 31 - r; |
221 | | } |
222 | | #else |
223 | 37 | r = __builtin_clz(x); |
224 | 11 | #endif |
225 | 11 | else |
226 | 11 | r = 32; |
227 | 48 | mxResult->kind = XS_INTEGER_KIND; |
228 | 48 | mxResult->value.integer = r; |
229 | 48 | } |
230 | | |
231 | | void fx_Math_cos(txMachine* the) |
232 | 30.4k | { |
233 | 30.4k | mxNanResultIfNoArg; |
234 | 30.2k | fxToNumber(the, mxArgv(0)); |
235 | 30.2k | mxResult->kind = XS_NUMBER_KIND; |
236 | 30.2k | mxResult->value.number = c_cos(mxArgv(0)->value.number); |
237 | 30.2k | } |
238 | | |
239 | | void fx_Math_cosh(txMachine* the) |
240 | 13.6k | { |
241 | 13.6k | mxNanResultIfNoArg; |
242 | 13.2k | fxToNumber(the, mxArgv(0)); |
243 | 13.2k | mxResult->kind = XS_NUMBER_KIND; |
244 | 13.2k | mxResult->value.number = c_cosh(mxArgv(0)->value.number); |
245 | 13.2k | } |
246 | | |
247 | | void fx_Math_exp(txMachine* the) |
248 | 278k | { |
249 | 278k | mxNanResultIfNoArg; |
250 | 277k | fxToNumber(the, mxArgv(0)); |
251 | 277k | mxResult->kind = XS_NUMBER_KIND; |
252 | 277k | mxResult->value.number = c_exp(mxArgv(0)->value.number); |
253 | 277k | } |
254 | | |
255 | | void fx_Math_expm1(txMachine* the) |
256 | 23 | { |
257 | 23 | mxNanResultIfNoArg; |
258 | 23 | fxToNumber(the, mxArgv(0)); |
259 | 23 | mxResult->kind = XS_NUMBER_KIND; |
260 | 23 | mxResult->value.number = c_expm1(mxArgv(0)->value.number); |
261 | 23 | } |
262 | | |
263 | | void fx_Math_floor(txMachine* the) |
264 | 193k | { |
265 | 193k | mxNanResultIfNoArg; |
266 | 193k | if (XS_INTEGER_KIND == mxArgv(0)->kind) { |
267 | 8 | mxResult->kind = XS_INTEGER_KIND; |
268 | 8 | mxResult->value.integer = mxArgv(0)->value.integer; |
269 | 8 | return; |
270 | 8 | } |
271 | 193k | fxToNumber(the, mxArgv(0)); |
272 | 193k | mxResult->kind = XS_NUMBER_KIND; |
273 | 193k | mxResult->value.number = c_floor(mxArgv(0)->value.number); |
274 | 193k | fx_Math_toInteger(the); |
275 | 193k | } |
276 | | |
277 | | void fx_Math_fround(txMachine* the) |
278 | 114 | { |
279 | 114 | float arg; |
280 | 114 | mxNanResultIfNoArg; |
281 | 111 | if (XS_INTEGER_KIND == mxArgv(0)->kind) { |
282 | 16 | mxResult->kind = XS_INTEGER_KIND; |
283 | 16 | mxResult->value.integer = mxArgv(0)->value.integer; |
284 | 16 | return; |
285 | 16 | } |
286 | 95 | arg = (float)fxToNumber(the, mxArgv(0)); |
287 | 95 | mxResult->kind = XS_NUMBER_KIND; |
288 | 95 | mxResult->value.number = arg; |
289 | 95 | } |
290 | | |
291 | | void fx_Math_hypot(txMachine* the) |
292 | 26 | { |
293 | 26 | if (mxArgc == 2) { |
294 | 16 | fxToNumber(the, mxArgv(0)); |
295 | 16 | fxToNumber(the, mxArgv(1)); |
296 | 16 | mxResult->kind = XS_NUMBER_KIND; |
297 | 16 | mxResult->value.number = c_hypot(mxArgv(0)->value.number, mxArgv(1)->value.number); |
298 | 16 | } |
299 | 10 | else { |
300 | 10 | txInteger c = mxArgc, i; |
301 | 10 | txNumber result = 0; |
302 | 23 | for (i = 0; i < c; i++) { |
303 | 13 | txNumber argument = fxToNumber(the, mxArgv(i)); |
304 | 13 | result += argument * argument; |
305 | 13 | } |
306 | 10 | mxResult->kind = XS_NUMBER_KIND; |
307 | 10 | mxResult->value.number = c_sqrt(result); |
308 | 10 | } |
309 | 26 | } |
310 | | |
311 | | void fx_Math_idiv(txMachine* the) |
312 | 102k | { |
313 | 102k | txInteger x = (mxArgc > 0) ? fxToInteger(the, mxArgv(0)) : 0; |
314 | 102k | txInteger y = (mxArgc > 1) ? fxToInteger(the, mxArgv(1)) : 0; |
315 | 102k | if (y == 0) { |
316 | 102k | mxResult->kind = XS_NUMBER_KIND; |
317 | 102k | mxResult->value.number = C_NAN; |
318 | 102k | } |
319 | 225 | else { |
320 | 225 | mxResult->kind = XS_INTEGER_KIND; |
321 | 225 | #if mxIntegerDivideOverflowException |
322 | 225 | if ((x == (txInteger)0x80000000) && (y == -1)) |
323 | 4 | mxResult->value.integer = x; |
324 | 221 | else |
325 | 221 | #endif |
326 | 221 | mxResult->value.integer = x / y; |
327 | 225 | } |
328 | 102k | } |
329 | | |
330 | | void fx_Math_idivmod(txMachine* the) |
331 | 0 | { |
332 | 0 | mxTypeError("not available"); |
333 | 0 | } |
334 | | |
335 | | void fx_Math_imod(txMachine* the) |
336 | 0 | { |
337 | 0 | txInteger x = (mxArgc > 0) ? fxToInteger(the, mxArgv(0)) : 0; |
338 | 0 | txInteger y = (mxArgc > 1) ? fxToInteger(the, mxArgv(1)) : 0; |
339 | 0 | if (y == 0) { |
340 | 0 | mxResult->kind = XS_NUMBER_KIND; |
341 | 0 | mxResult->value.number = C_NAN; |
342 | 0 | } |
343 | 0 | else { |
344 | 0 | mxResult->kind = XS_INTEGER_KIND; |
345 | 0 | #if mxIntegerDivideOverflowException |
346 | 0 | if ((x == (txInteger)0x80000000) && (y == -1)) |
347 | 0 | mxResult->value.integer = 0; |
348 | 0 | else |
349 | 0 | #endif |
350 | 0 | { |
351 | 0 | txInteger r = x % y; |
352 | 0 | if (r && ((r ^ y) < 0)) |
353 | 0 | r += y; |
354 | 0 | mxResult->value.integer = r; |
355 | 0 | } |
356 | 0 | } |
357 | 0 | } |
358 | | |
359 | | void fx_Math_imul(txMachine* the) |
360 | 102k | { |
361 | 102k | txInteger x = (mxArgc > 0) ? fxToInteger(the, mxArgv(0)) : 0; |
362 | 102k | txInteger y = (mxArgc > 1) ? fxToInteger(the, mxArgv(1)) : 0; |
363 | 102k | mxResult->kind = XS_INTEGER_KIND; |
364 | 102k | mxResult->value.integer = (txInteger)((uint32_t)x * (uint32_t)y); |
365 | 102k | } |
366 | | |
367 | | void fx_Math_imuldiv(txMachine* the) |
368 | 205k | { |
369 | 205k | txS8 x = (mxArgc > 0) ? fxToInteger(the, mxArgv(0)) : 0; |
370 | 205k | txS8 y = (mxArgc > 1) ? fxToInteger(the, mxArgv(1)) : 0; |
371 | 205k | txS8 z = (mxArgc > 2) ? fxToInteger(the, mxArgv(2)) : 0; |
372 | 205k | if (z == 0) { |
373 | 102k | mxResult->kind = XS_NUMBER_KIND; |
374 | 102k | mxResult->value.number = C_NAN; |
375 | 102k | } |
376 | 102k | else { |
377 | 102k | txS8 r = (x * y) / z; |
378 | 102k | mxResult->kind = XS_INTEGER_KIND; |
379 | 102k | mxResult->value.integer = (txInteger)(r & 0x00000000FFFFFFFF); |
380 | 102k | } |
381 | 205k | } |
382 | | |
383 | | void fx_Math_irandom(txMachine* the) |
384 | 133k | { |
385 | 133k | txInteger min = 0; |
386 | 133k | txInteger max = 2147483647; |
387 | 133k | uint32_t result, range, delta; |
388 | 133k | if (mxArgc > 1) { |
389 | 24.0k | min = fxToInteger(the, mxArgv(0)); |
390 | 24.0k | max = fxToInteger(the, mxArgv(1)); |
391 | 24.0k | } |
392 | 109k | else if (mxArgc > 0) |
393 | 89.0k | max = fxToInteger(the, mxArgv(0)); |
394 | 133k | do { |
395 | 133k | result = c_rand(); |
396 | 133k | } while (result == C_RAND_MAX); |
397 | 133k | if (max >= min) { |
398 | 122k | range = (uint32_t)max - (uint32_t)min; |
399 | 122k | delta = (uint32_t)(((uint64_t)result * (uint64_t)range) / (uint64_t)C_RAND_MAX); |
400 | 122k | mxResult->value.integer = (txInteger)((uint32_t)min + delta); |
401 | 122k | } |
402 | 11.0k | else { |
403 | 11.0k | range = (uint32_t)min - (uint32_t)max; |
404 | 11.0k | delta = (uint32_t)(((uint64_t)result * (uint64_t)range) / (uint64_t)C_RAND_MAX); |
405 | 11.0k | mxResult->value.integer = (txInteger)((uint32_t)min - delta); |
406 | 11.0k | } |
407 | 133k | mxResult->kind = XS_INTEGER_KIND; |
408 | 133k | } |
409 | | |
410 | | void fx_Math_irandom_secure(txMachine* the) |
411 | 0 | { |
412 | 0 | mxTypeError("secure mode"); |
413 | 0 | } |
414 | | |
415 | | void fx_Math_irem(txMachine* the) |
416 | 0 | { |
417 | 0 | txInteger x = (mxArgc > 0) ? fxToInteger(the, mxArgv(0)) : 0; |
418 | 0 | txInteger y = (mxArgc > 1) ? fxToInteger(the, mxArgv(1)) : 0; |
419 | 0 | if (y == 0) { |
420 | 0 | mxResult->kind = XS_NUMBER_KIND; |
421 | 0 | mxResult->value.number = C_NAN; |
422 | 0 | } |
423 | 0 | else { |
424 | 0 | mxResult->kind = XS_INTEGER_KIND; |
425 | 0 | #if mxIntegerDivideOverflowException |
426 | 0 | if ((x == (txInteger)0x80000000) && (y == -1)) |
427 | 0 | mxResult->value.integer = 0; |
428 | 0 | else |
429 | 0 | #endif |
430 | 0 | mxResult->value.integer = x % y; |
431 | 0 | } |
432 | 0 | } |
433 | | |
434 | | void fx_Math_log(txMachine* the) |
435 | 24 | { |
436 | 24 | mxNanResultIfNoArg; |
437 | 23 | fxToNumber(the, mxArgv(0)); |
438 | 23 | mxResult->kind = XS_NUMBER_KIND; |
439 | 23 | mxResult->value.number = c_log(mxArgv(0)->value.number); |
440 | 23 | } |
441 | | |
442 | | void fx_Math_log1p(txMachine* the) |
443 | 1.33k | { |
444 | 1.33k | mxNanResultIfNoArg; |
445 | 1.33k | fxToNumber(the, mxArgv(0)); |
446 | 1.33k | mxResult->kind = XS_NUMBER_KIND; |
447 | 1.33k | mxResult->value.number = c_log1p(mxArgv(0)->value.number); |
448 | 1.33k | } |
449 | | |
450 | | void fx_Math_log10(txMachine* the) |
451 | 224 | { |
452 | 224 | mxNanResultIfNoArg; |
453 | 160 | fxToNumber(the, mxArgv(0)); |
454 | 160 | mxResult->kind = XS_NUMBER_KIND; |
455 | 160 | mxResult->value.number = c_log10(mxArgv(0)->value.number); |
456 | 160 | } |
457 | | |
458 | | void fx_Math_log2(txMachine* the) |
459 | 13 | { |
460 | 13 | mxNanResultIfNoArg; |
461 | 13 | fxToNumber(the, mxArgv(0)); |
462 | 13 | mxResult->kind = XS_NUMBER_KIND; |
463 | | #if mxAndroid |
464 | | mxResult->value.number = c_log(mxArgv(0)->value.number) / c_log(2); |
465 | | #else |
466 | 13 | mxResult->value.number = c_log2(mxArgv(0)->value.number); |
467 | 13 | #endif |
468 | 13 | } |
469 | | |
470 | | void fx_Math_max(txMachine* the) |
471 | 1.80k | { |
472 | 1.80k | txInteger c = mxArgc, i = 0; |
473 | 1.80k | mxResult->kind = XS_NUMBER_KIND; |
474 | 1.80k | mxResult->value.number = -((txNumber)C_INFINITY); |
475 | 1.80k | if (0 == c) |
476 | 200 | return; |
477 | | |
478 | 1.60k | if (XS_INTEGER_KIND == mxArgv(0)->kind) { |
479 | 1.10k | mxResult->kind = XS_INTEGER_KIND; |
480 | 1.10k | mxResult->value.integer = mxArgv(0)->value.integer; |
481 | 1.10k | i = 1; |
482 | 1.10k | } |
483 | | |
484 | 3.42k | for (; i < c; i++) { |
485 | 2.28k | txSlot *slot = mxArgv(i); |
486 | 2.28k | if (XS_INTEGER_KIND == mxResult->kind) { |
487 | 1.26k | if (XS_INTEGER_KIND == slot->kind) { |
488 | 885 | if (mxResult->value.integer < slot->value.integer) { |
489 | 562 | mxResult->value.integer = slot->value.integer; |
490 | 562 | } |
491 | 885 | continue; |
492 | 885 | } |
493 | 383 | mxResult->kind = XS_NUMBER_KIND; |
494 | 383 | mxResult->value.number = mxResult->value.integer; |
495 | 383 | } |
496 | | |
497 | 1.39k | txNumber n = fxToNumber(the, slot); |
498 | 1.39k | if (c_isnan(n)) { |
499 | 8.06k | for (; i < c; i++) |
500 | 7.60k | fxToNumber(the, mxArgv(i)); |
501 | 456 | mxResult->value.number = C_NAN; |
502 | 456 | return; |
503 | 456 | } |
504 | 940 | if (mxResult->value.number < n) |
505 | 381 | mxResult->value.number = n; |
506 | 559 | else if ((mxResult->value.number == 0) && (n == 0)) { |
507 | 291 | if (c_signbit(mxResult->value.number) != c_signbit(n)) |
508 | 63 | mxResult->value.number = 0; |
509 | 291 | } |
510 | 940 | } |
511 | 1.60k | } |
512 | | |
513 | | void fx_Math_min(txMachine* the) |
514 | 2.37k | { |
515 | 2.37k | txInteger c = mxArgc, i = 0; |
516 | 2.37k | mxResult->kind = XS_NUMBER_KIND; |
517 | 2.37k | mxResult->value.number = (txNumber)C_INFINITY; |
518 | 2.37k | if (0 == c) |
519 | 595 | return; |
520 | | |
521 | 1.77k | if (XS_INTEGER_KIND == mxArgv(0)->kind) { |
522 | 548 | mxResult->kind = XS_INTEGER_KIND; |
523 | 548 | mxResult->value.integer = mxArgv(0)->value.integer; |
524 | 548 | i = 1; |
525 | 548 | } |
526 | | |
527 | 5.63k | for (; i < c; i++) { |
528 | 5.32k | txSlot *slot = mxArgv(i); |
529 | 5.32k | if (XS_INTEGER_KIND == mxResult->kind) { |
530 | 892 | if (XS_INTEGER_KIND == slot->kind) { |
531 | 445 | if (mxResult->value.integer > slot->value.integer) |
532 | 222 | mxResult->value.integer = slot->value.integer; |
533 | 445 | continue; |
534 | 445 | } |
535 | 447 | mxResult->kind = XS_NUMBER_KIND; |
536 | 447 | mxResult->value.number = mxResult->value.integer; |
537 | 447 | } |
538 | | |
539 | 4.88k | txNumber n = fxToNumber(the, slot); |
540 | 4.88k | if (c_isnan(n)) { |
541 | 3.25k | for (; i < c; i++) |
542 | 1.78k | fxToNumber(the, mxArgv(i)); |
543 | 1.47k | mxResult->value.number = C_NAN; |
544 | 1.47k | return; |
545 | 1.47k | } |
546 | 3.41k | if (mxResult->value.number > n) |
547 | 1.49k | mxResult->value.number = n; |
548 | 1.91k | else if ((mxResult->value.number == 0) && (n == 0)) { |
549 | 961 | if (c_signbit(mxResult->value.number) != c_signbit(n)) |
550 | 225 | mxResult->value.number = -0.0; |
551 | 961 | } |
552 | 3.41k | } |
553 | 1.77k | } |
554 | | |
555 | | void fx_Math_mod(txMachine* the) |
556 | 0 | { |
557 | 0 | txNumber x = (mxArgc > 0) ? fxToNumber(the, mxArgv(0)) : 0; |
558 | 0 | txNumber y = (mxArgc > 1) ? fxToNumber(the, mxArgv(1)) : 0; |
559 | 0 | mxResult->kind = XS_NUMBER_KIND; |
560 | 0 | mxResult->value.number = c_fmod((c_fmod(x, y) + y), y); |
561 | 0 | } |
562 | | |
563 | | txNumber fx_pow(txNumber x, txNumber y) |
564 | 2.40M | { |
565 | 2.40M | if (!c_isfinite(y) && (c_fabs(x) == 1.0)) |
566 | 99.0k | return C_NAN; |
567 | 2.30M | return c_pow(x, y); |
568 | 2.40M | } |
569 | | |
570 | | void fx_Math_pow(txMachine* the) |
571 | 267k | { |
572 | 267k | txNumber x, y; |
573 | 267k | mxNanResultIfNoArg; |
574 | 267k | x = fxToNumber(the, mxArgv(0)); |
575 | 267k | mxNanResultIfNoArg2; |
576 | 210k | y = fxToNumber(the, mxArgv(1)); |
577 | 210k | mxResult->kind = XS_NUMBER_KIND; |
578 | 210k | mxResult->value.number = fx_pow(x, y); |
579 | 210k | } |
580 | | |
581 | | void fx_Math_random(txMachine* the) |
582 | 106 | { |
583 | 106 | uint32_t result; |
584 | 106 | do { |
585 | 106 | result = c_rand(); |
586 | 106 | } while (result == C_RAND_MAX); |
587 | 106 | mxResult->kind = XS_NUMBER_KIND; |
588 | 106 | mxResult->value.number = (double)result / (double)C_RAND_MAX; |
589 | 106 | } |
590 | | |
591 | | void fx_Math_random_secure(txMachine* the) |
592 | 0 | { |
593 | 0 | mxTypeError("secure mode"); |
594 | 0 | } |
595 | | |
596 | | void fx_Math_round(txMachine* the) |
597 | 218k | { |
598 | 218k | txNumber arg; |
599 | 218k | mxNanResultIfNoArg; |
600 | 218k | if (XS_INTEGER_KIND == mxArgv(0)->kind) { |
601 | 107k | mxResult->kind = XS_INTEGER_KIND; |
602 | 107k | mxResult->value.integer = mxArgv(0)->value.integer; |
603 | 107k | return; |
604 | 107k | } |
605 | 110k | arg = fxToNumber(the, mxArgv(0)); |
606 | 110k | if (c_isfinite(arg) && (-4503599627370495 < arg) && (arg < 4503599627370495)) { // 2 ** 52 - 1 |
607 | 109k | if ((arg < -0.5) || (0.5 <= arg)) |
608 | 109k | arg = c_floor(arg + 0.5); |
609 | 137 | else if (arg < 0) |
610 | 4 | arg = -0.0; |
611 | 133 | else if (arg > 0) |
612 | 11 | arg = 0.0; |
613 | 109k | } |
614 | 110k | mxResult->kind = XS_NUMBER_KIND; |
615 | 110k | mxResult->value.number = arg; |
616 | 110k | fx_Math_toInteger(the); |
617 | 110k | } |
618 | | |
619 | | void fx_Math_sqrt(txMachine* the) |
620 | 1.41k | { |
621 | 1.41k | mxNanResultIfNoArg; |
622 | 1.41k | fxToNumber(the, mxArgv(0)); |
623 | 1.41k | mxResult->kind = XS_NUMBER_KIND; |
624 | 1.41k | mxResult->value.number = c_sqrt(mxArgv(0)->value.number); |
625 | 1.41k | } |
626 | | |
627 | | void fx_Math_sumPrecise(txMachine* the) |
628 | 24.8k | { |
629 | 24.8k | txSlot *iterable, *iterator, *next, *value; |
630 | 24.8k | xsum_small_accumulator accumulator; |
631 | 24.8k | txInteger count = 0; |
632 | 24.8k | txBoolean flag = 1; |
633 | 24.8k | if (mxArgc < 1) |
634 | 1 | mxTypeError("no items"); |
635 | 24.8k | iterable = mxArgv(0); |
636 | 24.8k | fxToInstance(the, iterable); |
637 | 24.8k | mxTemporary(iterator); |
638 | 24.8k | mxTemporary(next); |
639 | 24.8k | fxGetIterator(the, iterable, iterator, next, 0); |
640 | 24.8k | xsum_small_init(&accumulator); |
641 | 24.8k | mxTemporary(value); |
642 | 80.9k | while (fxIteratorNext(the, iterator, next, value)) { |
643 | 56.1k | mxTry(the) { |
644 | 56.1k | if (value->kind == XS_INTEGER_KIND) { |
645 | 14.0k | flag = 0; |
646 | 14.0k | xsum_small_add1(&accumulator, value->value.integer); |
647 | 14.0k | } |
648 | 42.0k | else if (value->kind == XS_NUMBER_KIND) { |
649 | 42.0k | if (value->value.number != -0.0) { |
650 | 41.3k | flag = 0; |
651 | 41.3k | xsum_small_add1(&accumulator, value->value.number); |
652 | 41.3k | } |
653 | 42.0k | } |
654 | 12 | else |
655 | 12 | mxTypeError("items[%d]: not a number", count); |
656 | 56.1k | count++; |
657 | 56.1k | } |
658 | 56.1k | mxCatch(the) { |
659 | 12 | fxIteratorReturn(the, iterator, 1); |
660 | 12 | fxJump(the); |
661 | 12 | } |
662 | 56.1k | } |
663 | 24.7k | if (flag) |
664 | 222 | mxResult->value.number = -0.0; |
665 | 24.5k | else |
666 | 24.5k | mxResult->value.number = xsum_small_round(&accumulator); |
667 | 24.7k | mxResult->kind = XS_NUMBER_KIND; |
668 | 24.7k | } |
669 | | |
670 | | void fx_Math_sign(txMachine* the) |
671 | 9.30k | { |
672 | 9.30k | txNumber arg; |
673 | 9.30k | mxNanResultIfNoArg; |
674 | 8.44k | arg = fxToNumber(the, mxArgv(0)); |
675 | 8.44k | mxResult->kind = XS_NUMBER_KIND; |
676 | 8.44k | if (c_isnan(arg)) |
677 | 5.77k | mxResult->value.number = C_NAN; |
678 | 2.67k | else if (arg < 0) |
679 | 463 | mxResult->value.number = -1; |
680 | 2.20k | else if (arg > 0) |
681 | 760 | mxResult->value.number = 1; |
682 | 1.44k | else |
683 | 1.44k | mxResult->value.number = arg; |
684 | 8.44k | fx_Math_toInteger(the); |
685 | 8.44k | } |
686 | | |
687 | | void fx_Math_sin(txMachine* the) |
688 | 11.5k | { |
689 | 11.5k | mxNanResultIfNoArg; |
690 | 10.4k | fxToNumber(the, mxArgv(0)); |
691 | 10.4k | mxResult->kind = XS_NUMBER_KIND; |
692 | 10.4k | mxResult->value.number = c_sin(mxArgv(0)->value.number); |
693 | 10.4k | } |
694 | | |
695 | | void fx_Math_sinh(txMachine* the) |
696 | 84.1k | { |
697 | 84.1k | mxNanResultIfNoArg; |
698 | 82.8k | fxToNumber(the, mxArgv(0)); |
699 | 82.8k | mxResult->kind = XS_NUMBER_KIND; |
700 | 82.8k | mxResult->value.number = c_sinh(mxArgv(0)->value.number); |
701 | 82.8k | } |
702 | | |
703 | | void fx_Math_tan(txMachine* the) |
704 | 77.9k | { |
705 | 77.9k | mxNanResultIfNoArg; |
706 | 76.2k | fxToNumber(the, mxArgv(0)); |
707 | 76.2k | mxResult->kind = XS_NUMBER_KIND; |
708 | 76.2k | mxResult->value.number = c_tan(mxArgv(0)->value.number); |
709 | 76.2k | } |
710 | | |
711 | | void fx_Math_tanh(txMachine* the) |
712 | 5.81k | { |
713 | 5.81k | mxNanResultIfNoArg; |
714 | 5.61k | fxToNumber(the, mxArgv(0)); |
715 | 5.61k | mxResult->kind = XS_NUMBER_KIND; |
716 | 5.61k | mxResult->value.number = c_tanh(mxArgv(0)->value.number); |
717 | 5.61k | } |
718 | | |
719 | | void fx_Math_trunc(txMachine* the) |
720 | 114 | { |
721 | 114 | mxNanResultIfNoArg; |
722 | 113 | fxToNumber(the, mxArgv(0)); |
723 | 113 | mxResult->kind = XS_NUMBER_KIND; |
724 | 113 | mxResult->value.number = c_trunc(mxArgv(0)->value.number); |
725 | 113 | fx_Math_toInteger(the); |
726 | 113 | } |
727 | | |
728 | | void fx_Math_toInteger(txMachine* the) |
729 | 699k | { |
730 | 699k | txNumber number = mxResult->value.number; |
731 | 699k | txInteger integer = (txInteger)number; |
732 | 699k | txNumber check = integer; |
733 | 699k | if ((number == check) && (number || !c_signbit(number))) { |
734 | 420k | mxResult->value.integer = integer; |
735 | 420k | mxResult->kind = XS_INTEGER_KIND; |
736 | 420k | } |
737 | 699k | } |