/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 | 6.03k | { |
44 | 6.03k | txSlot* slot; |
45 | 6.03k | mxPush(mxObjectPrototype); |
46 | 6.03k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
47 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_abs), 1, mxID(_abs), XS_DONT_ENUM_FLAG); |
48 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_acos), 1, mxID(_acos), XS_DONT_ENUM_FLAG); |
49 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_acosh), 1, mxID(_acosh), XS_DONT_ENUM_FLAG); |
50 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_asin), 1, mxID(_asin), XS_DONT_ENUM_FLAG); |
51 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_asinh), 1, mxID(_asinh), XS_DONT_ENUM_FLAG); |
52 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_atan), 1, mxID(_atan), XS_DONT_ENUM_FLAG); |
53 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_atanh), 1, mxID(_atanh), XS_DONT_ENUM_FLAG); |
54 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_atan2), 2, mxID(_atan2), XS_DONT_ENUM_FLAG); |
55 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_cbrt), 1, mxID(_cbrt), XS_DONT_ENUM_FLAG); |
56 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_ceil), 1, mxID(_ceil), XS_DONT_ENUM_FLAG); |
57 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_clz32), 1, mxID(_clz32), XS_DONT_ENUM_FLAG); |
58 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_cos), 1, mxID(_cos), XS_DONT_ENUM_FLAG); |
59 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_cosh), 1, mxID(_cosh), XS_DONT_ENUM_FLAG); |
60 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_exp), 1, mxID(_exp), XS_DONT_ENUM_FLAG); |
61 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_expm1), 1, mxID(_expm1), XS_DONT_ENUM_FLAG); |
62 | 6.03k | #if mxFloat16 |
63 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_f16round), 1, mxID(_f16round), XS_DONT_ENUM_FLAG); |
64 | 6.03k | #endif |
65 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_floor), 1, mxID(_floor), XS_DONT_ENUM_FLAG); |
66 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_fround), 1, mxID(_fround), XS_DONT_ENUM_FLAG); |
67 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_hypot), 2, mxID(_hypot_), XS_DONT_ENUM_FLAG); |
68 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_idiv), 2, mxID(_idiv), XS_DONT_ENUM_FLAG); |
69 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_idivmod), 2, mxID(_idivmod), XS_DONT_ENUM_FLAG); |
70 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_imod), 2, mxID(_imod), XS_DONT_ENUM_FLAG); |
71 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_imul), 2, mxID(_imul), XS_DONT_ENUM_FLAG); |
72 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_imuldiv), 2, mxID(_imuldiv), XS_DONT_ENUM_FLAG); |
73 | 6.03k | #if mxECMAScript2023 |
74 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_irandom), 0, mxID(_irandom), XS_DONT_ENUM_FLAG); |
75 | 6.03k | #endif |
76 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_irem), 2, mxID(_irem), XS_DONT_ENUM_FLAG); |
77 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_log), 1, mxID(_log), XS_DONT_ENUM_FLAG); |
78 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_log1p), 1, mxID(_log1p), XS_DONT_ENUM_FLAG); |
79 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_log10), 1, mxID(_log10), XS_DONT_ENUM_FLAG); |
80 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_log2), 1, mxID(_log2), XS_DONT_ENUM_FLAG); |
81 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_max), 2, mxID(_max), XS_DONT_ENUM_FLAG); |
82 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_min), 2, mxID(_min), XS_DONT_ENUM_FLAG); |
83 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_mod), 2, mxID(_mod), XS_DONT_ENUM_FLAG); |
84 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_pow), 2, mxID(_pow), XS_DONT_ENUM_FLAG); |
85 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_random), 0, mxID(_random), XS_DONT_ENUM_FLAG); |
86 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_round), 1, mxID(_round), XS_DONT_ENUM_FLAG); |
87 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_sign), 1, mxID(_sign), XS_DONT_ENUM_FLAG); |
88 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_sin), 1, mxID(_sin), XS_DONT_ENUM_FLAG); |
89 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_sinh), 1, mxID(_sinh), XS_DONT_ENUM_FLAG); |
90 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_sqrt), 1, mxID(_sqrt), XS_DONT_ENUM_FLAG); |
91 | 6.03k | #if mxECMAScript2026 |
92 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_sumPrecise), 1, mxID(_sumPrecise), XS_DONT_ENUM_FLAG); |
93 | 6.03k | #endif |
94 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_tan), 1, mxID(_tan), XS_DONT_ENUM_FLAG); |
95 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_tanh), 1, mxID(_tanh), XS_DONT_ENUM_FLAG); |
96 | 6.03k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Math_trunc), 1, mxID(_trunc), XS_DONT_ENUM_FLAG); |
97 | 6.03k | slot = fxNextNumberProperty(the, slot, C_M_E, mxID(_E), XS_GET_ONLY); |
98 | 6.03k | slot = fxNextNumberProperty(the, slot, C_M_LN10, mxID(_LN10), XS_GET_ONLY); |
99 | 6.03k | slot = fxNextNumberProperty(the, slot, C_M_LN2, mxID(_LN2), XS_GET_ONLY); |
100 | 6.03k | slot = fxNextNumberProperty(the, slot, C_M_LOG10E, mxID(_LOG10E), XS_GET_ONLY); |
101 | 6.03k | slot = fxNextNumberProperty(the, slot, C_M_LOG2E, mxID(_LOG2E), XS_GET_ONLY); |
102 | 6.03k | slot = fxNextNumberProperty(the, slot, C_M_PI, mxID(_PI), XS_GET_ONLY); |
103 | 6.03k | slot = fxNextNumberProperty(the, slot, C_M_SQRT1_2, mxID(_SQRT1_2), XS_GET_ONLY); |
104 | 6.03k | slot = fxNextNumberProperty(the, slot, C_M_SQRT2, mxID(_SQRT2), XS_GET_ONLY); |
105 | 6.03k | slot = fxNextStringXProperty(the, slot, "Math", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG); |
106 | 6.03k | mxPull(mxMathObject); |
107 | | //@@ c_srand((unsigned)c_time(0)); |
108 | 6.03k | } |
109 | | |
110 | | #define mxNanResultIfNoArg \ |
111 | 0 | if (mxArgc < 1) { \ |
112 | 0 | mxResult->kind = XS_NUMBER_KIND; \ |
113 | 0 | mxResult->value.number = C_NAN; \ |
114 | 0 | return; \ |
115 | 0 | } |
116 | | |
117 | | #define mxNanResultIfNoArg2 \ |
118 | 0 | if (mxArgc < 2) { \ |
119 | 0 | mxResult->kind = XS_NUMBER_KIND; \ |
120 | 0 | mxResult->value.number = C_NAN; \ |
121 | 0 | return; \ |
122 | 0 | } |
123 | | |
124 | | void fx_Math_abs(txMachine* the) |
125 | 0 | { |
126 | 0 | mxNanResultIfNoArg; |
127 | 0 | fxToNumber(the, mxArgv(0)); |
128 | 0 | mxResult->kind = XS_NUMBER_KIND; |
129 | 0 | mxResult->value.number = c_fabs(mxArgv(0)->value.number); |
130 | 0 | } |
131 | | |
132 | | void fx_Math_acos(txMachine* the) |
133 | 0 | { |
134 | 0 | mxNanResultIfNoArg; |
135 | 0 | fxToNumber(the, mxArgv(0)); |
136 | 0 | mxResult->kind = XS_NUMBER_KIND; |
137 | 0 | mxResult->value.number = c_acos(mxArgv(0)->value.number); |
138 | 0 | } |
139 | | |
140 | | void fx_Math_acosh(txMachine* the) |
141 | 0 | { |
142 | 0 | mxNanResultIfNoArg; |
143 | 0 | fxToNumber(the, mxArgv(0)); |
144 | 0 | mxResult->kind = XS_NUMBER_KIND; |
145 | 0 | mxResult->value.number = c_acosh(mxArgv(0)->value.number); |
146 | 0 | } |
147 | | |
148 | | void fx_Math_asin(txMachine* the) |
149 | 0 | { |
150 | 0 | mxNanResultIfNoArg; |
151 | 0 | fxToNumber(the, mxArgv(0)); |
152 | 0 | mxResult->kind = XS_NUMBER_KIND; |
153 | 0 | mxResult->value.number = c_asin(mxArgv(0)->value.number); |
154 | 0 | } |
155 | | |
156 | | void fx_Math_asinh(txMachine* the) |
157 | 0 | { |
158 | 0 | mxNanResultIfNoArg; |
159 | 0 | fxToNumber(the, mxArgv(0)); |
160 | 0 | mxResult->kind = XS_NUMBER_KIND; |
161 | 0 | mxResult->value.number = c_asinh(mxArgv(0)->value.number); |
162 | 0 | } |
163 | | |
164 | | void fx_Math_atan(txMachine* the) |
165 | 0 | { |
166 | 0 | mxNanResultIfNoArg; |
167 | 0 | fxToNumber(the, mxArgv(0)); |
168 | 0 | mxResult->kind = XS_NUMBER_KIND; |
169 | 0 | mxResult->value.number = c_atan(mxArgv(0)->value.number); |
170 | 0 | } |
171 | | |
172 | | void fx_Math_atanh(txMachine* the) |
173 | 0 | { |
174 | 0 | mxNanResultIfNoArg; |
175 | 0 | fxToNumber(the, mxArgv(0)); |
176 | 0 | mxResult->kind = XS_NUMBER_KIND; |
177 | 0 | mxResult->value.number = c_atanh(mxArgv(0)->value.number); |
178 | 0 | } |
179 | | |
180 | | void fx_Math_atan2(txMachine* the) |
181 | 0 | { |
182 | 0 | mxNanResultIfNoArg2; |
183 | 0 | fxToNumber(the, mxArgv(0)); |
184 | 0 | fxToNumber(the, mxArgv(1)); |
185 | 0 | mxResult->kind = XS_NUMBER_KIND; |
186 | 0 | mxResult->value.number = c_atan2(mxArgv(0)->value.number, mxArgv(1)->value.number); |
187 | 0 | } |
188 | | |
189 | | void fx_Math_cbrt(txMachine* the) |
190 | 0 | { |
191 | 0 | mxNanResultIfNoArg; |
192 | 0 | fxToNumber(the, mxArgv(0)); |
193 | 0 | mxResult->kind = XS_NUMBER_KIND; |
194 | 0 | mxResult->value.number = c_cbrt(mxArgv(0)->value.number); |
195 | 0 | } |
196 | | |
197 | | void fx_Math_ceil(txMachine* the) |
198 | 0 | { |
199 | 0 | mxNanResultIfNoArg; |
200 | 0 | if (XS_INTEGER_KIND == mxArgv(0)->kind) { |
201 | 0 | mxResult->kind = XS_INTEGER_KIND; |
202 | 0 | mxResult->value.integer = mxArgv(0)->value.integer; |
203 | 0 | return; |
204 | 0 | } |
205 | 0 | fxToNumber(the, mxArgv(0)); |
206 | 0 | mxResult->kind = XS_NUMBER_KIND; |
207 | 0 | mxResult->value.number = c_ceil(mxArgv(0)->value.number); |
208 | 0 | fx_Math_toInteger(the); |
209 | 0 | } |
210 | | |
211 | | void fx_Math_clz32(txMachine* the) |
212 | 0 | { |
213 | 0 | txUnsigned x = (mxArgc > 0) ? fxToUnsigned(the, mxArgv(0)) : 0; |
214 | 0 | txInteger r; |
215 | 0 | if (x) |
216 | | #if mxWindows |
217 | | { |
218 | | _BitScanReverse(&r, x); |
219 | | r = 31 - r; |
220 | | } |
221 | | #else |
222 | 0 | r = __builtin_clz(x); |
223 | 0 | #endif |
224 | 0 | else |
225 | 0 | r = 32; |
226 | 0 | mxResult->kind = XS_INTEGER_KIND; |
227 | 0 | mxResult->value.integer = r; |
228 | 0 | } |
229 | | |
230 | | void fx_Math_cos(txMachine* the) |
231 | 0 | { |
232 | 0 | mxNanResultIfNoArg; |
233 | 0 | fxToNumber(the, mxArgv(0)); |
234 | 0 | mxResult->kind = XS_NUMBER_KIND; |
235 | 0 | mxResult->value.number = c_cos(mxArgv(0)->value.number); |
236 | 0 | } |
237 | | |
238 | | void fx_Math_cosh(txMachine* the) |
239 | 0 | { |
240 | 0 | mxNanResultIfNoArg; |
241 | 0 | fxToNumber(the, mxArgv(0)); |
242 | 0 | mxResult->kind = XS_NUMBER_KIND; |
243 | 0 | mxResult->value.number = c_cosh(mxArgv(0)->value.number); |
244 | 0 | } |
245 | | |
246 | | void fx_Math_exp(txMachine* the) |
247 | 0 | { |
248 | 0 | mxNanResultIfNoArg; |
249 | 0 | fxToNumber(the, mxArgv(0)); |
250 | 0 | mxResult->kind = XS_NUMBER_KIND; |
251 | 0 | mxResult->value.number = c_exp(mxArgv(0)->value.number); |
252 | 0 | } |
253 | | |
254 | | void fx_Math_expm1(txMachine* the) |
255 | 0 | { |
256 | 0 | mxNanResultIfNoArg; |
257 | 0 | fxToNumber(the, mxArgv(0)); |
258 | 0 | mxResult->kind = XS_NUMBER_KIND; |
259 | 0 | mxResult->value.number = c_expm1(mxArgv(0)->value.number); |
260 | 0 | } |
261 | | |
262 | | void fx_Math_floor(txMachine* the) |
263 | 0 | { |
264 | 0 | mxNanResultIfNoArg; |
265 | 0 | if (XS_INTEGER_KIND == mxArgv(0)->kind) { |
266 | 0 | mxResult->kind = XS_INTEGER_KIND; |
267 | 0 | mxResult->value.integer = mxArgv(0)->value.integer; |
268 | 0 | return; |
269 | 0 | } |
270 | 0 | fxToNumber(the, mxArgv(0)); |
271 | 0 | mxResult->kind = XS_NUMBER_KIND; |
272 | 0 | mxResult->value.number = c_floor(mxArgv(0)->value.number); |
273 | 0 | fx_Math_toInteger(the); |
274 | 0 | } |
275 | | |
276 | | void fx_Math_fround(txMachine* the) |
277 | 0 | { |
278 | 0 | float arg; |
279 | 0 | mxNanResultIfNoArg; |
280 | 0 | if (XS_INTEGER_KIND == mxArgv(0)->kind) { |
281 | 0 | mxResult->kind = XS_INTEGER_KIND; |
282 | 0 | mxResult->value.integer = mxArgv(0)->value.integer; |
283 | 0 | return; |
284 | 0 | } |
285 | 0 | arg = (float)fxToNumber(the, mxArgv(0)); |
286 | 0 | mxResult->kind = XS_NUMBER_KIND; |
287 | 0 | mxResult->value.number = arg; |
288 | 0 | } |
289 | | |
290 | | void fx_Math_hypot(txMachine* the) |
291 | 0 | { |
292 | 0 | if (mxArgc == 2) { |
293 | 0 | fxToNumber(the, mxArgv(0)); |
294 | 0 | fxToNumber(the, mxArgv(1)); |
295 | 0 | mxResult->kind = XS_NUMBER_KIND; |
296 | 0 | mxResult->value.number = c_hypot(mxArgv(0)->value.number, mxArgv(1)->value.number); |
297 | 0 | } |
298 | 0 | else { |
299 | 0 | txInteger c = mxArgc, i; |
300 | 0 | txNumber result = 0; |
301 | 0 | for (i = 0; i < c; i++) { |
302 | 0 | txNumber argument = fxToNumber(the, mxArgv(i)); |
303 | 0 | result += argument * argument; |
304 | 0 | } |
305 | 0 | mxResult->kind = XS_NUMBER_KIND; |
306 | 0 | mxResult->value.number = c_sqrt(result); |
307 | 0 | } |
308 | 0 | } |
309 | | |
310 | | void fx_Math_idiv(txMachine* the) |
311 | 0 | { |
312 | 0 | txInteger x = (mxArgc > 0) ? fxToInteger(the, mxArgv(0)) : 0; |
313 | 0 | txInteger y = (mxArgc > 1) ? fxToInteger(the, mxArgv(1)) : 0; |
314 | 0 | if (y == 0) { |
315 | 0 | mxResult->kind = XS_NUMBER_KIND; |
316 | 0 | mxResult->value.number = C_NAN; |
317 | 0 | } |
318 | 0 | else { |
319 | 0 | mxResult->kind = XS_INTEGER_KIND; |
320 | 0 | #if mxIntegerDivideOverflowException |
321 | 0 | if ((x == (txInteger)0x80000000) && (y == -1)) |
322 | 0 | mxResult->value.integer = x; |
323 | 0 | else |
324 | 0 | #endif |
325 | 0 | mxResult->value.integer = x / y; |
326 | 0 | } |
327 | 0 | } |
328 | | |
329 | | void fx_Math_idivmod(txMachine* the) |
330 | 0 | { |
331 | 0 | mxTypeError("not available"); |
332 | 0 | } |
333 | | |
334 | | void fx_Math_imod(txMachine* the) |
335 | 0 | { |
336 | 0 | txInteger x = (mxArgc > 0) ? fxToInteger(the, mxArgv(0)) : 0; |
337 | 0 | txInteger y = (mxArgc > 1) ? fxToInteger(the, mxArgv(1)) : 0; |
338 | 0 | if (y == 0) { |
339 | 0 | mxResult->kind = XS_NUMBER_KIND; |
340 | 0 | mxResult->value.number = C_NAN; |
341 | 0 | } |
342 | 0 | else { |
343 | 0 | mxResult->kind = XS_INTEGER_KIND; |
344 | 0 | #if mxIntegerDivideOverflowException |
345 | 0 | if ((x == (txInteger)0x80000000) && (y == -1)) |
346 | 0 | mxResult->value.integer = 0; |
347 | 0 | else |
348 | 0 | #endif |
349 | 0 | mxResult->value.integer = (x % y + y) % y; |
350 | 0 | } |
351 | 0 | } |
352 | | |
353 | | void fx_Math_imul(txMachine* the) |
354 | 0 | { |
355 | 0 | txInteger x = (mxArgc > 0) ? fxToInteger(the, mxArgv(0)) : 0; |
356 | 0 | txInteger y = (mxArgc > 1) ? fxToInteger(the, mxArgv(1)) : 0; |
357 | 0 | mxResult->kind = XS_INTEGER_KIND; |
358 | 0 | mxResult->value.integer = x * y; |
359 | 0 | } |
360 | | |
361 | | void fx_Math_imuldiv(txMachine* the) |
362 | 0 | { |
363 | 0 | txS8 x = (mxArgc > 0) ? fxToInteger(the, mxArgv(0)) : 0; |
364 | 0 | txS8 y = (mxArgc > 1) ? fxToInteger(the, mxArgv(1)) : 0; |
365 | 0 | txS8 z = (mxArgc > 2) ? fxToInteger(the, mxArgv(2)) : 0; |
366 | 0 | if (z == 0) { |
367 | 0 | mxResult->kind = XS_NUMBER_KIND; |
368 | 0 | mxResult->value.number = C_NAN; |
369 | 0 | } |
370 | 0 | else { |
371 | 0 | txS8 r = (x * y) / z; |
372 | 0 | mxResult->kind = XS_INTEGER_KIND; |
373 | 0 | mxResult->value.integer = (txInteger)(r & 0x00000000FFFFFFFF); |
374 | 0 | } |
375 | 0 | } |
376 | | |
377 | | void fx_Math_irandom(txMachine* the) |
378 | 0 | { |
379 | 0 | double min = 0; |
380 | 0 | double max = 2147483647; |
381 | 0 | uint32_t result; |
382 | 0 | if (mxArgc > 1) { |
383 | 0 | min = (double)fxToInteger(the, mxArgv(0)); |
384 | 0 | max = (double)fxToInteger(the, mxArgv(1)); |
385 | 0 | } |
386 | 0 | else if (mxArgc > 0) { |
387 | 0 | max = (double)fxToInteger(the, mxArgv(0)); |
388 | 0 | } |
389 | 0 | result = c_rand(); |
390 | 0 | while (result == C_RAND_MAX) |
391 | 0 | result = c_rand(); |
392 | 0 | if (max < min) |
393 | 0 | mxResult->value.integer = (txInteger)c_ceil(min + (((double)result / (double)C_RAND_MAX) * (max - min))); |
394 | 0 | else |
395 | 0 | mxResult->value.integer = (txInteger)c_floor(min + (((double)result / (double)C_RAND_MAX) * (max - min))); |
396 | 0 | mxResult->kind = XS_INTEGER_KIND; |
397 | 0 | } |
398 | | |
399 | | void fx_Math_irandom_secure(txMachine* the) |
400 | 0 | { |
401 | 0 | mxTypeError("secure mode"); |
402 | 0 | } |
403 | | |
404 | | void fx_Math_irem(txMachine* the) |
405 | 0 | { |
406 | 0 | txInteger x = (mxArgc > 0) ? fxToInteger(the, mxArgv(0)) : 0; |
407 | 0 | txInteger y = (mxArgc > 1) ? fxToInteger(the, mxArgv(1)) : 0; |
408 | 0 | if (y == 0) { |
409 | 0 | mxResult->kind = XS_NUMBER_KIND; |
410 | 0 | mxResult->value.number = C_NAN; |
411 | 0 | } |
412 | 0 | else { |
413 | 0 | mxResult->kind = XS_INTEGER_KIND; |
414 | 0 | #if mxIntegerDivideOverflowException |
415 | 0 | if ((x == (txInteger)0x80000000) && (y == -1)) |
416 | 0 | mxResult->value.integer = 0; |
417 | 0 | else |
418 | 0 | #endif |
419 | 0 | mxResult->value.integer = x % y; |
420 | 0 | } |
421 | 0 | } |
422 | | |
423 | | void fx_Math_log(txMachine* the) |
424 | 0 | { |
425 | 0 | mxNanResultIfNoArg; |
426 | 0 | fxToNumber(the, mxArgv(0)); |
427 | 0 | mxResult->kind = XS_NUMBER_KIND; |
428 | 0 | mxResult->value.number = c_log(mxArgv(0)->value.number); |
429 | 0 | } |
430 | | |
431 | | void fx_Math_log1p(txMachine* the) |
432 | 0 | { |
433 | 0 | mxNanResultIfNoArg; |
434 | 0 | fxToNumber(the, mxArgv(0)); |
435 | 0 | mxResult->kind = XS_NUMBER_KIND; |
436 | 0 | mxResult->value.number = c_log1p(mxArgv(0)->value.number); |
437 | 0 | } |
438 | | |
439 | | void fx_Math_log10(txMachine* the) |
440 | 0 | { |
441 | 0 | mxNanResultIfNoArg; |
442 | 0 | fxToNumber(the, mxArgv(0)); |
443 | 0 | mxResult->kind = XS_NUMBER_KIND; |
444 | 0 | mxResult->value.number = c_log10(mxArgv(0)->value.number); |
445 | 0 | } |
446 | | |
447 | | void fx_Math_log2(txMachine* the) |
448 | 0 | { |
449 | 0 | mxNanResultIfNoArg; |
450 | 0 | fxToNumber(the, mxArgv(0)); |
451 | 0 | mxResult->kind = XS_NUMBER_KIND; |
452 | | #if mxAndroid |
453 | | mxResult->value.number = c_log(mxArgv(0)->value.number) / c_log(2); |
454 | | #else |
455 | 0 | mxResult->value.number = c_log2(mxArgv(0)->value.number); |
456 | 0 | #endif |
457 | 0 | } |
458 | | |
459 | | void fx_Math_max(txMachine* the) |
460 | 0 | { |
461 | 0 | txInteger c = mxArgc, i = 0; |
462 | 0 | mxResult->kind = XS_NUMBER_KIND; |
463 | 0 | mxResult->value.number = -((txNumber)C_INFINITY); |
464 | 0 | if (0 == c) |
465 | 0 | return; |
466 | | |
467 | 0 | if (XS_INTEGER_KIND == mxArgv(0)->kind) { |
468 | 0 | mxResult->kind = XS_INTEGER_KIND; |
469 | 0 | mxResult->value.integer = mxArgv(0)->value.integer; |
470 | 0 | i = 1; |
471 | 0 | } |
472 | |
|
473 | 0 | for (; i < c; i++) { |
474 | 0 | txSlot *slot = mxArgv(i); |
475 | 0 | if (XS_INTEGER_KIND == mxResult->kind) { |
476 | 0 | if (XS_INTEGER_KIND == slot->kind) { |
477 | 0 | if (mxResult->value.integer < slot->value.integer) { |
478 | 0 | mxResult->value.integer = slot->value.integer; |
479 | 0 | } |
480 | 0 | continue; |
481 | 0 | } |
482 | 0 | mxResult->kind = XS_NUMBER_KIND; |
483 | 0 | mxResult->value.number = mxResult->value.integer; |
484 | 0 | } |
485 | | |
486 | 0 | txNumber n = fxToNumber(the, slot); |
487 | 0 | if (c_isnan(n)) { |
488 | 0 | for (; i < c; i++) |
489 | 0 | fxToNumber(the, mxArgv(i)); |
490 | 0 | mxResult->value.number = C_NAN; |
491 | 0 | return; |
492 | 0 | } |
493 | 0 | if (mxResult->value.number < n) |
494 | 0 | mxResult->value.number = n; |
495 | 0 | else if ((mxResult->value.number == 0) && (n == 0)) { |
496 | 0 | if (c_signbit(mxResult->value.number) != c_signbit(n)) |
497 | 0 | mxResult->value.number = 0; |
498 | 0 | } |
499 | 0 | } |
500 | 0 | } |
501 | | |
502 | | void fx_Math_min(txMachine* the) |
503 | 0 | { |
504 | 0 | txInteger c = mxArgc, i = 0; |
505 | 0 | mxResult->kind = XS_NUMBER_KIND; |
506 | 0 | mxResult->value.number = (txNumber)C_INFINITY; |
507 | 0 | if (0 == c) |
508 | 0 | return; |
509 | | |
510 | 0 | if (XS_INTEGER_KIND == mxArgv(0)->kind) { |
511 | 0 | mxResult->kind = XS_INTEGER_KIND; |
512 | 0 | mxResult->value.integer = mxArgv(0)->value.integer; |
513 | 0 | i = 1; |
514 | 0 | } |
515 | |
|
516 | 0 | for (; i < c; i++) { |
517 | 0 | txSlot *slot = mxArgv(i); |
518 | 0 | if (XS_INTEGER_KIND == mxResult->kind) { |
519 | 0 | if (XS_INTEGER_KIND == slot->kind) { |
520 | 0 | if (mxResult->value.integer > slot->value.integer) |
521 | 0 | mxResult->value.integer = slot->value.integer; |
522 | 0 | continue; |
523 | 0 | } |
524 | 0 | mxResult->kind = XS_NUMBER_KIND; |
525 | 0 | mxResult->value.number = mxResult->value.integer; |
526 | 0 | } |
527 | | |
528 | 0 | txNumber n = fxToNumber(the, slot); |
529 | 0 | if (c_isnan(n)) { |
530 | 0 | for (; i < c; i++) |
531 | 0 | fxToNumber(the, mxArgv(i)); |
532 | 0 | mxResult->value.number = C_NAN; |
533 | 0 | return; |
534 | 0 | } |
535 | 0 | if (mxResult->value.number > n) |
536 | 0 | mxResult->value.number = n; |
537 | 0 | else if ((mxResult->value.number == 0) && (n == 0)) { |
538 | 0 | if (c_signbit(mxResult->value.number) != c_signbit(n)) |
539 | 0 | mxResult->value.number = -0.0; |
540 | 0 | } |
541 | 0 | } |
542 | 0 | } |
543 | | |
544 | | void fx_Math_mod(txMachine* the) |
545 | 0 | { |
546 | 0 | txNumber x = (mxArgc > 0) ? fxToNumber(the, mxArgv(0)) : 0; |
547 | 0 | txNumber y = (mxArgc > 1) ? fxToNumber(the, mxArgv(1)) : 0; |
548 | 0 | mxResult->kind = XS_NUMBER_KIND; |
549 | 0 | mxResult->value.number = c_fmod((c_fmod(x, y) + y), y); |
550 | 0 | } |
551 | | |
552 | | txNumber fx_pow(txNumber x, txNumber y) |
553 | 0 | { |
554 | 0 | if (!c_isfinite(y) && (c_fabs(x) == 1.0)) |
555 | 0 | return C_NAN; |
556 | 0 | return c_pow(x, y); |
557 | 0 | } |
558 | | |
559 | | void fx_Math_pow(txMachine* the) |
560 | 0 | { |
561 | 0 | txNumber x, y; |
562 | 0 | mxNanResultIfNoArg2; |
563 | 0 | x = fxToNumber(the, mxArgv(0)); |
564 | 0 | y = fxToNumber(the, mxArgv(1)); |
565 | 0 | mxResult->kind = XS_NUMBER_KIND; |
566 | 0 | mxResult->value.number = fx_pow(x, y); |
567 | 0 | } |
568 | | |
569 | | void fx_Math_random(txMachine* the) |
570 | 0 | { |
571 | 0 | uint32_t result; |
572 | 0 | do { |
573 | 0 | result = c_rand(); |
574 | 0 | } while (result == C_RAND_MAX); |
575 | 0 | mxResult->kind = XS_NUMBER_KIND; |
576 | 0 | mxResult->value.number = (double)result / (double)C_RAND_MAX; |
577 | 0 | } |
578 | | |
579 | | void fx_Math_random_secure(txMachine* the) |
580 | 0 | { |
581 | 0 | mxTypeError("secure mode"); |
582 | 0 | } |
583 | | |
584 | | void fx_Math_round(txMachine* the) |
585 | 0 | { |
586 | 0 | txNumber arg; |
587 | 0 | mxNanResultIfNoArg; |
588 | 0 | if (XS_INTEGER_KIND == mxArgv(0)->kind) { |
589 | 0 | mxResult->kind = XS_INTEGER_KIND; |
590 | 0 | mxResult->value.integer = mxArgv(0)->value.integer; |
591 | 0 | return; |
592 | 0 | } |
593 | 0 | arg = fxToNumber(the, mxArgv(0)); |
594 | 0 | if (c_isnormal(arg) && (-4503599627370495 < arg) && (arg < 4503599627370495)) { // 2 ** 52 - 1 |
595 | 0 | if ((arg < -0.5) || (0.5 <= arg)) |
596 | 0 | arg = c_floor(arg + 0.5); |
597 | 0 | else if (arg < 0) |
598 | 0 | arg = -0.0; |
599 | 0 | else if (arg > 0) |
600 | 0 | arg = 0.0; |
601 | 0 | } |
602 | 0 | mxResult->kind = XS_NUMBER_KIND; |
603 | 0 | mxResult->value.number = arg; |
604 | 0 | fx_Math_toInteger(the); |
605 | 0 | } |
606 | | |
607 | | void fx_Math_sqrt(txMachine* the) |
608 | 0 | { |
609 | 0 | mxNanResultIfNoArg; |
610 | 0 | fxToNumber(the, mxArgv(0)); |
611 | 0 | mxResult->kind = XS_NUMBER_KIND; |
612 | 0 | mxResult->value.number = c_sqrt(mxArgv(0)->value.number); |
613 | 0 | } |
614 | | |
615 | | void fx_Math_sumPrecise(txMachine* the) |
616 | 0 | { |
617 | 0 | txSlot *iterable, *iterator, *next, *value; |
618 | 0 | xsum_small_accumulator accumulator; |
619 | 0 | txInteger count = 0; |
620 | 0 | txBoolean flag = 1; |
621 | 0 | if (mxArgc < 1) |
622 | 0 | mxTypeError("no items"); |
623 | 0 | iterable = mxArgv(0); |
624 | 0 | fxToInstance(the, iterable); |
625 | 0 | mxTemporary(iterator); |
626 | 0 | mxTemporary(next); |
627 | 0 | fxGetIterator(the, iterable, iterator, next, 0); |
628 | 0 | xsum_small_init(&accumulator); |
629 | 0 | mxTemporary(value); |
630 | 0 | while (fxIteratorNext(the, iterator, next, value)) { |
631 | 0 | mxTry(the) { |
632 | 0 | if (value->kind == XS_INTEGER_KIND) { |
633 | 0 | flag = 0; |
634 | 0 | xsum_small_add1(&accumulator, value->value.integer); |
635 | 0 | } |
636 | 0 | else if (value->kind == XS_NUMBER_KIND) { |
637 | 0 | if (value->value.number != -0.0) { |
638 | 0 | flag = 0; |
639 | 0 | xsum_small_add1(&accumulator, value->value.number); |
640 | 0 | } |
641 | 0 | } |
642 | 0 | else |
643 | 0 | mxTypeError("items[%d]: not a number", count); |
644 | 0 | count++; |
645 | 0 | } |
646 | 0 | mxCatch(the) { |
647 | 0 | fxIteratorReturn(the, iterator, 1); |
648 | 0 | fxJump(the); |
649 | 0 | } |
650 | 0 | } |
651 | 0 | if (flag) |
652 | 0 | mxResult->value.number = -0.0; |
653 | 0 | else |
654 | 0 | mxResult->value.number = xsum_small_round(&accumulator); |
655 | 0 | mxResult->kind = XS_NUMBER_KIND; |
656 | 0 | } |
657 | | |
658 | | void fx_Math_sign(txMachine* the) |
659 | 0 | { |
660 | 0 | txNumber arg; |
661 | 0 | mxNanResultIfNoArg; |
662 | 0 | arg = fxToNumber(the, mxArgv(0)); |
663 | 0 | mxResult->kind = XS_NUMBER_KIND; |
664 | 0 | if (c_isnan(arg)) |
665 | 0 | mxResult->value.number = C_NAN; |
666 | 0 | else if (arg < 0) |
667 | 0 | mxResult->value.number = -1; |
668 | 0 | else if (arg > 0) |
669 | 0 | mxResult->value.number = 1; |
670 | 0 | else |
671 | 0 | mxResult->value.number = arg; |
672 | 0 | fx_Math_toInteger(the); |
673 | 0 | } |
674 | | |
675 | | void fx_Math_sin(txMachine* the) |
676 | 0 | { |
677 | 0 | mxNanResultIfNoArg; |
678 | 0 | fxToNumber(the, mxArgv(0)); |
679 | 0 | mxResult->kind = XS_NUMBER_KIND; |
680 | 0 | mxResult->value.number = c_sin(mxArgv(0)->value.number); |
681 | 0 | } |
682 | | |
683 | | void fx_Math_sinh(txMachine* the) |
684 | 0 | { |
685 | 0 | mxNanResultIfNoArg; |
686 | 0 | fxToNumber(the, mxArgv(0)); |
687 | 0 | mxResult->kind = XS_NUMBER_KIND; |
688 | 0 | mxResult->value.number = c_sinh(mxArgv(0)->value.number); |
689 | 0 | } |
690 | | |
691 | | void fx_Math_tan(txMachine* the) |
692 | 0 | { |
693 | 0 | mxNanResultIfNoArg; |
694 | 0 | fxToNumber(the, mxArgv(0)); |
695 | 0 | mxResult->kind = XS_NUMBER_KIND; |
696 | 0 | mxResult->value.number = c_tan(mxArgv(0)->value.number); |
697 | 0 | } |
698 | | |
699 | | void fx_Math_tanh(txMachine* the) |
700 | 0 | { |
701 | 0 | mxNanResultIfNoArg; |
702 | 0 | fxToNumber(the, mxArgv(0)); |
703 | 0 | mxResult->kind = XS_NUMBER_KIND; |
704 | 0 | mxResult->value.number = c_tanh(mxArgv(0)->value.number); |
705 | 0 | } |
706 | | |
707 | | void fx_Math_trunc(txMachine* the) |
708 | 0 | { |
709 | 0 | mxNanResultIfNoArg; |
710 | 0 | fxToNumber(the, mxArgv(0)); |
711 | 0 | mxResult->kind = XS_NUMBER_KIND; |
712 | 0 | mxResult->value.number = c_trunc(mxArgv(0)->value.number); |
713 | 0 | fx_Math_toInteger(the); |
714 | 0 | } |
715 | | |
716 | | void fx_Math_toInteger(txMachine* the) |
717 | 0 | { |
718 | 0 | txNumber number = mxResult->value.number; |
719 | 0 | txInteger integer = (txInteger)number; |
720 | 0 | txNumber check = integer; |
721 | 0 | if ((number == check) && (number || !c_signbit(number))) { |
722 | 0 | mxResult->value.integer = integer; |
723 | 0 | mxResult->kind = XS_INTEGER_KIND; |
724 | 0 | } |
725 | 0 | } |