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>
40 * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
44 #include "embryo_private.h"
46 #define PI 3.1415926535897932384626433832795
48 /* internally useful calls */
51 _embryo_fp_degrees_to_radians(float angle, int radix)
55 case 1: /* degrees, sexagesimal system (technically: degrees/minutes/seconds) */
56 return (float)(angle * PI / 180.0);
57 case 2: /* grades, centesimal system */
58 return (float)(angle * PI / 200.0);
59 default: /* assume already radian */
65 /* exported float api */
68 _embryo_fp(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
70 /* params[1] = long value to convert to a float */
73 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
75 return EMBRYO_FLOAT_TO_CELL(f);
79 _embryo_fp_str(Embryo_Program *ep, Embryo_Cell *params)
81 /* params[1] = virtual string address to convert to a float */
87 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
88 str = embryo_data_address_get(ep, params[1]);
89 len = embryo_data_string_length_get(ep, str);
90 if ((len == 0) || (len >= sizeof(buf))) return 0;
91 embryo_data_string_get(ep, str, buf);
93 return EMBRYO_FLOAT_TO_CELL(f);
97 _embryo_fp_mul(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
99 /* params[1] = float operand 1 */
100 /* params[2] = float operand 2 */
103 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
104 f = EMBRYO_CELL_TO_FLOAT(params[1]) * EMBRYO_CELL_TO_FLOAT(params[2]);
105 return EMBRYO_FLOAT_TO_CELL(f);
109 _embryo_fp_div(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
111 /* params[1] = float dividend (top) */
112 /* params[2] = float divisor (bottom) */
115 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
116 f = EMBRYO_CELL_TO_FLOAT(params[1]) / EMBRYO_CELL_TO_FLOAT(params[2]);
117 return EMBRYO_FLOAT_TO_CELL(f);
121 _embryo_fp_add(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
123 /* params[1] = float operand 1 */
124 /* params[2] = float operand 2 */
127 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
128 f = EMBRYO_CELL_TO_FLOAT(params[1]) + EMBRYO_CELL_TO_FLOAT(params[2]);
129 return EMBRYO_FLOAT_TO_CELL(f);
133 _embryo_fp_sub(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
135 /* params[1] = float operand 1 */
136 /* params[2] = float operand 2 */
139 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
140 f = EMBRYO_CELL_TO_FLOAT(params[1]) - EMBRYO_CELL_TO_FLOAT(params[2]);
141 return EMBRYO_FLOAT_TO_CELL(f);
144 /* Return fractional part of float */
146 _embryo_fp_fract(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
148 /* params[1] = float operand */
151 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
152 f = EMBRYO_CELL_TO_FLOAT(params[1]);
153 f -= (float)(floor((double)f));
154 return EMBRYO_FLOAT_TO_CELL(f);
157 /* Return integer part of float, rounded */
159 _embryo_fp_round(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
161 /* params[1] = float operand */
162 /* params[2] = Type of rounding (cell) */
165 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
166 f = EMBRYO_CELL_TO_FLOAT(params[1]);
169 case 1: /* round downwards (truncate) */
170 f = (float)(floor((double)f));
172 case 2: /* round upwards */
173 f = (float)(ceil((double)f));
175 case 3: /* round towards zero */
176 if (f >= 0.0) f = (float)(floor((double)f));
177 else f = (float)(ceil((double)f));
179 default: /* standard, round to nearest */
180 f = (float)(floor((double)f + 0.5));
183 return (Embryo_Cell)f;
187 _embryo_fp_cmp(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
189 /* params[1] = float operand 1 */
190 /* params[2] = float operand 2 */
193 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
194 f = EMBRYO_CELL_TO_FLOAT(params[1]);
195 ff = EMBRYO_CELL_TO_FLOAT(params[2]);
196 if (f == ff) return 0;
197 else if (f > ff) return 1;
202 _embryo_fp_sqroot(Embryo_Program *ep, Embryo_Cell *params)
204 /* params[1] = float operand */
207 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
208 f = EMBRYO_CELL_TO_FLOAT(params[1]);
212 embryo_program_error_set(ep, EMBRYO_ERROR_DOMAIN);
215 return EMBRYO_FLOAT_TO_CELL(f);
219 _embryo_fp_power(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
221 /* params[1] = float operand 1 */
222 /* params[2] = float operand 2 */
225 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
226 f = EMBRYO_CELL_TO_FLOAT(params[1]);
227 ff = EMBRYO_CELL_TO_FLOAT(params[2]);
228 f = (float)pow(f, ff);
229 return EMBRYO_FLOAT_TO_CELL(f);
233 _embryo_fp_log(Embryo_Program *ep, Embryo_Cell *params)
235 /* params[1] = float operand 1 (value) */
236 /* params[2] = float operand 2 (base) */
239 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
240 f = EMBRYO_CELL_TO_FLOAT(params[1]);
241 ff = EMBRYO_CELL_TO_FLOAT(params[2]);
242 if ((f <= 0.0) || (ff <= 0.0))
244 embryo_program_error_set(ep, EMBRYO_ERROR_DOMAIN);
247 if (ff == 10.0) f = (float)log10(f);
248 else f = (float)(log(f) / log(ff));
249 return EMBRYO_FLOAT_TO_CELL(f);
253 _embryo_fp_sin(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
255 /* params[1] = float operand 1 (angle) */
256 /* params[2] = float operand 2 (radix) */
259 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
260 f = EMBRYO_CELL_TO_FLOAT(params[1]);
261 f = _embryo_fp_degrees_to_radians(f, params[2]);
263 return EMBRYO_FLOAT_TO_CELL(f);
267 _embryo_fp_cos(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
269 /* params[1] = float operand 1 (angle) */
270 /* params[2] = float operand 2 (radix) */
273 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
274 f = EMBRYO_CELL_TO_FLOAT(params[1]);
275 f = _embryo_fp_degrees_to_radians(f, params[2]);
277 return EMBRYO_FLOAT_TO_CELL(f);
281 _embryo_fp_tan(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
283 /* params[1] = float operand 1 (angle) */
284 /* params[2] = float operand 2 (radix) */
287 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
288 f = EMBRYO_CELL_TO_FLOAT(params[1]);
289 f = _embryo_fp_degrees_to_radians(f, params[2]);
291 return EMBRYO_FLOAT_TO_CELL(f);
295 _embryo_fp_abs(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
297 /* params[1] = float operand */
300 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
301 f = EMBRYO_CELL_TO_FLOAT(params[1]);
302 f = (f >= 0) ? f : -f;
303 return EMBRYO_FLOAT_TO_CELL(f);
306 /* functions used by the rest of embryo */
309 _embryo_fp_init(Embryo_Program *ep)
311 embryo_program_native_call_add(ep, "float", _embryo_fp);
312 embryo_program_native_call_add(ep, "atof", _embryo_fp_str);
313 embryo_program_native_call_add(ep, "float_mul", _embryo_fp_mul);
314 embryo_program_native_call_add(ep, "float_div", _embryo_fp_div);
315 embryo_program_native_call_add(ep, "float_add", _embryo_fp_add);
316 embryo_program_native_call_add(ep, "float_sub", _embryo_fp_sub);
317 embryo_program_native_call_add(ep, "fract", _embryo_fp_fract);
318 embryo_program_native_call_add(ep, "round", _embryo_fp_round);
319 embryo_program_native_call_add(ep, "float_cmp", _embryo_fp_cmp);
320 embryo_program_native_call_add(ep, "sqrt", _embryo_fp_sqroot);
321 embryo_program_native_call_add(ep, "pow", _embryo_fp_power);
322 embryo_program_native_call_add(ep, "log", _embryo_fp_log);
323 embryo_program_native_call_add(ep, "sin", _embryo_fp_sin);
324 embryo_program_native_call_add(ep, "cos", _embryo_fp_cos);
325 embryo_program_native_call_add(ep, "tan", _embryo_fp_tan);
326 embryo_program_native_call_add(ep, "abs", _embryo_fp_abs);