1 /* Float arithmetic for the Small AMX engine
3 * Copyright (c) Artran, Inc. 1999
4 * Written by Greg Garner (gmg@artran.com)
5 * Portions Copyright (c) Carsten Haitzler, 2004 <raster@rasterman.com>
7 * This software is provided "as-is", without any express or implied warranty.
8 * In no event will the authors be held liable for any damages arising from
9 * the use of this software.
11 * Permission is granted to anyone to use this software for any purpose,
12 * including commercial applications, and to alter it and redistribute it
13 * freely, subject to the following restrictions:
15 * 1. The origin of this software must not be misrepresented; you must not
16 * claim that you wrote the original software. If you use this software in
17 * a product, an acknowledgment in the product documentation would be
18 * appreciated but is not required.
19 * 2. Altered source versions must be plainly marked as such, and must not be
20 * misrepresented as being the original software.
21 * 3. This notice may not be removed or altered from any source distribution.
25 * 2002-08-27: Basic conversion of source from C++ to C by Adam D. Moss
26 * <adam@gimp.org> <aspirin@icculus.org>
27 * 2003-08-29: Removal of the dynamic memory allocation and replacing two
28 * type conversion functions by macros, by Thiadmer Riemersma
29 * 2003-09-22: Moved the type conversion macros to AMX.H, and simplifications
30 * of some routines, by Thiadmer Riemersma
31 * 2003-11-24: A few more native functions (geometry), plus minor modifications,
32 * mostly to be compatible with dynamically loadable extension
33 * modules, by Thiadmer Riemersma
34 * 2004-03-20: Cleaned up and reduced size for Embryo, Modified to conform to
35 * E coding style. Added extra parameter checks.
36 * Carsten Haitzler, <raster@rasterman.com>
48 #include "embryo_private.h"
50 #define PI 3.1415926535897932384626433832795f
52 #define MAXFLOAT 3.40282347e+38f
55 /* internally useful calls */
58 _embryo_fp_degrees_to_radians(float angle, int radix)
62 case 1: /* degrees, sexagesimal system (technically: degrees/minutes/seconds) */
63 return (angle * PI / 180.0f);
64 case 2: /* grades, centesimal system */
65 return (angle * PI / 200.0f);
66 default: /* assume already radian */
72 /* exported float api */
75 _embryo_fp(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
77 /* params[1] = long value to convert to a float */
80 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
82 return EMBRYO_FLOAT_TO_CELL(f);
86 _embryo_fp_str(Embryo_Program *ep, Embryo_Cell *params)
88 /* params[1] = virtual string address to convert to a float */
94 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
95 str = embryo_data_address_get(ep, params[1]);
96 len = embryo_data_string_length_get(ep, str);
97 if ((len == 0) || (len >= (int)sizeof(buf))) return 0;
98 embryo_data_string_get(ep, str, buf);
100 return EMBRYO_FLOAT_TO_CELL(f);
104 _embryo_fp_mul(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
106 /* params[1] = float operand 1 */
107 /* params[2] = float operand 2 */
110 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
111 f = EMBRYO_CELL_TO_FLOAT(params[1]) * EMBRYO_CELL_TO_FLOAT(params[2]);
112 return EMBRYO_FLOAT_TO_CELL(f);
116 _embryo_fp_div(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
118 /* params[1] = float dividend (top) */
119 /* params[2] = float divisor (bottom) */
122 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
123 f = EMBRYO_CELL_TO_FLOAT(params[1]);
124 ff = EMBRYO_CELL_TO_FLOAT(params[2]);
128 return EMBRYO_FLOAT_TO_CELL(0.0f);
130 return EMBRYO_FLOAT_TO_CELL(-MAXFLOAT);
132 return EMBRYO_FLOAT_TO_CELL(MAXFLOAT);
135 return EMBRYO_FLOAT_TO_CELL(f);
139 _embryo_fp_add(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
141 /* params[1] = float operand 1 */
142 /* params[2] = float operand 2 */
145 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
146 f = EMBRYO_CELL_TO_FLOAT(params[1]) + EMBRYO_CELL_TO_FLOAT(params[2]);
147 return EMBRYO_FLOAT_TO_CELL(f);
151 _embryo_fp_sub(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
153 /* params[1] = float operand 1 */
154 /* params[2] = float operand 2 */
157 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
158 f = EMBRYO_CELL_TO_FLOAT(params[1]) - EMBRYO_CELL_TO_FLOAT(params[2]);
159 return EMBRYO_FLOAT_TO_CELL(f);
162 /* Return fractional part of float */
164 _embryo_fp_fract(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
166 /* params[1] = float operand */
169 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
170 f = EMBRYO_CELL_TO_FLOAT(params[1]);
172 return EMBRYO_FLOAT_TO_CELL(f);
175 /* Return integer part of float, rounded */
177 _embryo_fp_round(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
179 /* params[1] = float operand */
180 /* params[2] = Type of rounding (cell) */
183 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
184 f = EMBRYO_CELL_TO_FLOAT(params[1]);
187 case 1: /* round downwards (truncate) */
190 case 2: /* round upwards */
193 case 3: /* round towards zero */
194 if (f >= 0.0) f = (floorf(f));
197 default: /* standard, round to nearest */
198 f = (floorf(f + 0.5));
201 return (Embryo_Cell)f;
205 _embryo_fp_cmp(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
207 /* params[1] = float operand 1 */
208 /* params[2] = float operand 2 */
211 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
212 f = EMBRYO_CELL_TO_FLOAT(params[1]);
213 ff = EMBRYO_CELL_TO_FLOAT(params[2]);
214 if (f == ff) return 0;
215 else if (f > ff) return 1;
220 _embryo_fp_sqroot(Embryo_Program *ep, Embryo_Cell *params)
222 /* params[1] = float operand */
225 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
226 f = EMBRYO_CELL_TO_FLOAT(params[1]);
230 embryo_program_error_set(ep, EMBRYO_ERROR_DOMAIN);
233 return EMBRYO_FLOAT_TO_CELL(f);
237 _embryo_fp_power(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
239 /* params[1] = float operand 1 */
240 /* params[2] = float operand 2 */
243 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
244 f = EMBRYO_CELL_TO_FLOAT(params[1]);
245 ff = EMBRYO_CELL_TO_FLOAT(params[2]);
247 return EMBRYO_FLOAT_TO_CELL(f);
251 _embryo_fp_log(Embryo_Program *ep, Embryo_Cell *params)
253 /* params[1] = float operand 1 (value) */
254 /* params[2] = float operand 2 (base) */
257 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
258 f = EMBRYO_CELL_TO_FLOAT(params[1]);
259 ff = EMBRYO_CELL_TO_FLOAT(params[2]);
260 if ((f <= 0.0) || (ff <= 0.0))
262 embryo_program_error_set(ep, EMBRYO_ERROR_DOMAIN);
265 if (ff == 10.0) f = log10f(f);
266 else if (ff == 2.0) f = log2f(f);
270 if (tf == 0.0) f = 0.0;
271 else f = (logf(f) / tf);
273 return EMBRYO_FLOAT_TO_CELL(f);
277 _embryo_fp_sin(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
279 /* params[1] = float operand 1 (angle) */
280 /* params[2] = float operand 2 (radix) */
283 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
284 f = EMBRYO_CELL_TO_FLOAT(params[1]);
285 f = _embryo_fp_degrees_to_radians(f, params[2]);
287 return EMBRYO_FLOAT_TO_CELL(f);
291 _embryo_fp_cos(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
293 /* params[1] = float operand 1 (angle) */
294 /* params[2] = float operand 2 (radix) */
297 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
298 f = EMBRYO_CELL_TO_FLOAT(params[1]);
299 f = _embryo_fp_degrees_to_radians(f, params[2]);
301 return EMBRYO_FLOAT_TO_CELL(f);
305 _embryo_fp_tan(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
307 /* params[1] = float operand 1 (angle) */
308 /* params[2] = float operand 2 (radix) */
311 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
312 f = EMBRYO_CELL_TO_FLOAT(params[1]);
313 f = _embryo_fp_degrees_to_radians(f, params[2]);
315 return EMBRYO_FLOAT_TO_CELL(f);
319 _embryo_fp_abs(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
321 /* params[1] = float operand */
324 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
325 f = EMBRYO_CELL_TO_FLOAT(params[1]);
326 f = (f >= 0) ? f : -f;
327 return EMBRYO_FLOAT_TO_CELL(f);
331 _embryo_fp_asin(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
333 /* params[1] = float operand 1 (angle) */
334 /* params[2] = float operand 2 (radix) */
337 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
338 f = EMBRYO_CELL_TO_FLOAT(params[1]);
340 f = _embryo_fp_degrees_to_radians(f, params[2]);
341 return EMBRYO_FLOAT_TO_CELL(f);
345 _embryo_fp_acos(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
347 /* params[1] = float operand 1 (angle) */
348 /* params[2] = float operand 2 (radix) */
351 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
352 f = EMBRYO_CELL_TO_FLOAT(params[1]);
354 f = _embryo_fp_degrees_to_radians(f, params[2]);
355 return EMBRYO_FLOAT_TO_CELL(f);
359 _embryo_fp_atan(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
361 /* params[1] = float operand 1 (angle) */
362 /* params[2] = float operand 2 (radix) */
365 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
366 f = EMBRYO_CELL_TO_FLOAT(params[1]);
368 f = _embryo_fp_degrees_to_radians(f, params[2]);
369 return EMBRYO_FLOAT_TO_CELL(f);
373 _embryo_fp_atan2(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
375 /* params[1] = float operand 1 (y) */
376 /* params[2] = float operand 2 (x) */
377 /* params[3] = float operand 3 (radix) */
380 if (params[0] != (3 * sizeof(Embryo_Cell))) return 0;
381 f = EMBRYO_CELL_TO_FLOAT(params[1]);
382 ff = EMBRYO_CELL_TO_FLOAT(params[2]);
384 f = _embryo_fp_degrees_to_radians(f, params[3]);
385 return EMBRYO_FLOAT_TO_CELL(f);
389 _embryo_fp_log1p(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
391 /* params[1] = float operand */
394 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
395 f = EMBRYO_CELL_TO_FLOAT(params[1]);
397 return EMBRYO_FLOAT_TO_CELL(f);
401 _embryo_fp_cbrt(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
403 /* params[1] = float operand */
406 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
407 f = EMBRYO_CELL_TO_FLOAT(params[1]);
409 return EMBRYO_FLOAT_TO_CELL(f);
413 _embryo_fp_exp(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
415 /* params[1] = float operand */
418 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
419 f = EMBRYO_CELL_TO_FLOAT(params[1]);
421 return EMBRYO_FLOAT_TO_CELL(f);
425 _embryo_fp_exp2(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
427 /* params[1] = float operand */
430 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
431 f = EMBRYO_CELL_TO_FLOAT(params[1]);
433 return EMBRYO_FLOAT_TO_CELL(f);
437 _embryo_fp_hypot(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
439 /* params[1] = float operand */
442 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
443 f = EMBRYO_CELL_TO_FLOAT(params[1]);
444 ff = EMBRYO_CELL_TO_FLOAT(params[2]);
446 return EMBRYO_FLOAT_TO_CELL(f);
449 /* functions used by the rest of embryo */
452 _embryo_fp_init(Embryo_Program *ep)
454 embryo_program_native_call_add(ep, "float", _embryo_fp);
455 embryo_program_native_call_add(ep, "atof", _embryo_fp_str);
456 embryo_program_native_call_add(ep, "float_mul", _embryo_fp_mul);
457 embryo_program_native_call_add(ep, "float_div", _embryo_fp_div);
458 embryo_program_native_call_add(ep, "float_add", _embryo_fp_add);
459 embryo_program_native_call_add(ep, "float_sub", _embryo_fp_sub);
460 embryo_program_native_call_add(ep, "fract", _embryo_fp_fract);
461 embryo_program_native_call_add(ep, "round", _embryo_fp_round);
462 embryo_program_native_call_add(ep, "float_cmp", _embryo_fp_cmp);
463 embryo_program_native_call_add(ep, "sqrt", _embryo_fp_sqroot);
464 embryo_program_native_call_add(ep, "pow", _embryo_fp_power);
465 embryo_program_native_call_add(ep, "log", _embryo_fp_log);
466 embryo_program_native_call_add(ep, "sin", _embryo_fp_sin);
467 embryo_program_native_call_add(ep, "cos", _embryo_fp_cos);
468 embryo_program_native_call_add(ep, "tan", _embryo_fp_tan);
469 embryo_program_native_call_add(ep, "abs", _embryo_fp_abs);
470 /* Added in embryo 1.2 */
471 embryo_program_native_call_add(ep, "asin", _embryo_fp_asin);
472 embryo_program_native_call_add(ep, "acos", _embryo_fp_acos);
473 embryo_program_native_call_add(ep, "atan", _embryo_fp_atan);
474 embryo_program_native_call_add(ep, "atan2", _embryo_fp_atan2);
475 embryo_program_native_call_add(ep, "log1p", _embryo_fp_log1p);
476 embryo_program_native_call_add(ep, "cbrt", _embryo_fp_cbrt);
477 embryo_program_native_call_add(ep, "exp", _embryo_fp_exp);
478 embryo_program_native_call_add(ep, "exp2", _embryo_fp_exp2);
479 embryo_program_native_call_add(ep, "hypot", _embryo_fp_hypot);