aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/embryo/src/lib/embryo_float.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/embryo/src/lib/embryo_float.c')
-rw-r--r--libraries/embryo/src/lib/embryo_float.c331
1 files changed, 331 insertions, 0 deletions
diff --git a/libraries/embryo/src/lib/embryo_float.c b/libraries/embryo/src/lib/embryo_float.c
new file mode 100644
index 0000000..608be9d
--- /dev/null
+++ b/libraries/embryo/src/lib/embryo_float.c
@@ -0,0 +1,331 @@
1/* Float arithmetic for the Small AMX engine
2 *
3 * Copyright (c) Artran, Inc. 1999
4 * Written by Greg Garner (gmg@artran.com)
5 * Portions Copyright (c) Carsten Haitzler, 2004 <raster@rasterman.com>
6 *
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.
10 *
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:
14 *
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.
22 */
23
24/* CHANGES -
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>
37 */
38
39
40#ifdef HAVE_CONFIG_H
41# include "config.h"
42#endif
43
44#include <stdlib.h>
45#include <math.h>
46
47#include "Embryo.h"
48#include "embryo_private.h"
49
50#define PI 3.1415926535897932384626433832795f
51
52/* internally useful calls */
53
54static float
55_embryo_fp_degrees_to_radians(float angle, int radix)
56{
57 switch (radix)
58 {
59 case 1: /* degrees, sexagesimal system (technically: degrees/minutes/seconds) */
60 return (angle * PI / 180.0f);
61 case 2: /* grades, centesimal system */
62 return (angle * PI / 200.0f);
63 default: /* assume already radian */
64 break;
65 }
66 return angle;
67}
68
69/* exported float api */
70
71static Embryo_Cell
72_embryo_fp(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
73{
74 /* params[1] = long value to convert to a float */
75 float f;
76
77 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
78 f = (float)params[1];
79 return EMBRYO_FLOAT_TO_CELL(f);
80}
81
82static Embryo_Cell
83_embryo_fp_str(Embryo_Program *ep, Embryo_Cell *params)
84{
85 /* params[1] = virtual string address to convert to a float */
86 char buf[64];
87 Embryo_Cell *str;
88 float f;
89 int len;
90
91 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
92 str = embryo_data_address_get(ep, params[1]);
93 len = embryo_data_string_length_get(ep, str);
94 if ((len == 0) || (len >= (int)sizeof(buf))) return 0;
95 embryo_data_string_get(ep, str, buf);
96 f = (float)atof(buf);
97 return EMBRYO_FLOAT_TO_CELL(f);
98}
99
100static Embryo_Cell
101_embryo_fp_mul(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
102{
103 /* params[1] = float operand 1 */
104 /* params[2] = float operand 2 */
105 float f;
106
107 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
108 f = EMBRYO_CELL_TO_FLOAT(params[1]) * EMBRYO_CELL_TO_FLOAT(params[2]);
109 return EMBRYO_FLOAT_TO_CELL(f);
110}
111
112static Embryo_Cell
113_embryo_fp_div(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
114{
115 /* params[1] = float dividend (top) */
116 /* params[2] = float divisor (bottom) */
117 float f;
118
119 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
120 f = EMBRYO_CELL_TO_FLOAT(params[1]) / EMBRYO_CELL_TO_FLOAT(params[2]);
121 return EMBRYO_FLOAT_TO_CELL(f);
122}
123
124static Embryo_Cell
125_embryo_fp_add(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
126{
127 /* params[1] = float operand 1 */
128 /* params[2] = float operand 2 */
129 float f;
130
131 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
132 f = EMBRYO_CELL_TO_FLOAT(params[1]) + EMBRYO_CELL_TO_FLOAT(params[2]);
133 return EMBRYO_FLOAT_TO_CELL(f);
134}
135
136static Embryo_Cell
137_embryo_fp_sub(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
138{
139 /* params[1] = float operand 1 */
140 /* params[2] = float operand 2 */
141 float f;
142
143 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
144 f = EMBRYO_CELL_TO_FLOAT(params[1]) - EMBRYO_CELL_TO_FLOAT(params[2]);
145 return EMBRYO_FLOAT_TO_CELL(f);
146}
147
148/* Return fractional part of float */
149static Embryo_Cell
150_embryo_fp_fract(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
151{
152 /* params[1] = float operand */
153 float f;
154
155 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
156 f = EMBRYO_CELL_TO_FLOAT(params[1]);
157 f -= (floorf(f));
158 return EMBRYO_FLOAT_TO_CELL(f);
159}
160
161/* Return integer part of float, rounded */
162static Embryo_Cell
163_embryo_fp_round(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
164{
165 /* params[1] = float operand */
166 /* params[2] = Type of rounding (cell) */
167 float f;
168
169 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
170 f = EMBRYO_CELL_TO_FLOAT(params[1]);
171 switch (params[2])
172 {
173 case 1: /* round downwards (truncate) */
174 f = (floorf(f));
175 break;
176 case 2: /* round upwards */
177 f = (ceilf(f));
178 break;
179 case 3: /* round towards zero */
180 if (f >= 0.0) f = (floorf(f));
181 else f = (ceilf(f));
182 break;
183 default: /* standard, round to nearest */
184 f = (floorf(f + 0.5));
185 break;
186 }
187 return (Embryo_Cell)f;
188}
189
190static Embryo_Cell
191_embryo_fp_cmp(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
192{
193 /* params[1] = float operand 1 */
194 /* params[2] = float operand 2 */
195 float f, ff;
196
197 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
198 f = EMBRYO_CELL_TO_FLOAT(params[1]);
199 ff = EMBRYO_CELL_TO_FLOAT(params[2]);
200 if (f == ff) return 0;
201 else if (f > ff) return 1;
202 return -1;
203}
204
205static Embryo_Cell
206_embryo_fp_sqroot(Embryo_Program *ep, Embryo_Cell *params)
207{
208 /* params[1] = float operand */
209 float f;
210
211 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
212 f = EMBRYO_CELL_TO_FLOAT(params[1]);
213 f = sqrtf(f);
214 if (f < 0)
215 {
216 embryo_program_error_set(ep, EMBRYO_ERROR_DOMAIN);
217 return 0;
218 }
219 return EMBRYO_FLOAT_TO_CELL(f);
220}
221
222static Embryo_Cell
223_embryo_fp_power(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
224{
225 /* params[1] = float operand 1 */
226 /* params[2] = float operand 2 */
227 float f, ff;
228
229 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
230 f = EMBRYO_CELL_TO_FLOAT(params[1]);
231 ff = EMBRYO_CELL_TO_FLOAT(params[2]);
232 f = powf(f, ff);
233 return EMBRYO_FLOAT_TO_CELL(f);
234}
235
236static Embryo_Cell
237_embryo_fp_log(Embryo_Program *ep, Embryo_Cell *params)
238{
239 /* params[1] = float operand 1 (value) */
240 /* params[2] = float operand 2 (base) */
241 float f, ff;
242
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]);
246 if ((f <= 0.0) || (ff <= 0.0))
247 {
248 embryo_program_error_set(ep, EMBRYO_ERROR_DOMAIN);
249 return 0;
250 }
251 if (ff == 10.0) f = log10f(f);
252 else f = (logf(f) / logf(ff));
253 return EMBRYO_FLOAT_TO_CELL(f);
254}
255
256static Embryo_Cell
257_embryo_fp_sin(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
258{
259 /* params[1] = float operand 1 (angle) */
260 /* params[2] = float operand 2 (radix) */
261 float f;
262
263 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
264 f = EMBRYO_CELL_TO_FLOAT(params[1]);
265 f = _embryo_fp_degrees_to_radians(f, params[2]);
266 f = sinf(f);
267 return EMBRYO_FLOAT_TO_CELL(f);
268}
269
270static Embryo_Cell
271_embryo_fp_cos(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
272{
273 /* params[1] = float operand 1 (angle) */
274 /* params[2] = float operand 2 (radix) */
275 float f;
276
277 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
278 f = EMBRYO_CELL_TO_FLOAT(params[1]);
279 f = _embryo_fp_degrees_to_radians(f, params[2]);
280 f = cosf(f);
281 return EMBRYO_FLOAT_TO_CELL(f);
282}
283
284static Embryo_Cell
285_embryo_fp_tan(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
286{
287 /* params[1] = float operand 1 (angle) */
288 /* params[2] = float operand 2 (radix) */
289 float f;
290
291 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
292 f = EMBRYO_CELL_TO_FLOAT(params[1]);
293 f = _embryo_fp_degrees_to_radians(f, params[2]);
294 f = tanf(f);
295 return EMBRYO_FLOAT_TO_CELL(f);
296}
297
298static Embryo_Cell
299_embryo_fp_abs(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
300{
301 /* params[1] = float operand */
302 float f;
303
304 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
305 f = EMBRYO_CELL_TO_FLOAT(params[1]);
306 f = (f >= 0) ? f : -f;
307 return EMBRYO_FLOAT_TO_CELL(f);
308}
309
310/* functions used by the rest of embryo */
311
312void
313_embryo_fp_init(Embryo_Program *ep)
314{
315 embryo_program_native_call_add(ep, "float", _embryo_fp);
316 embryo_program_native_call_add(ep, "atof", _embryo_fp_str);
317 embryo_program_native_call_add(ep, "float_mul", _embryo_fp_mul);
318 embryo_program_native_call_add(ep, "float_div", _embryo_fp_div);
319 embryo_program_native_call_add(ep, "float_add", _embryo_fp_add);
320 embryo_program_native_call_add(ep, "float_sub", _embryo_fp_sub);
321 embryo_program_native_call_add(ep, "fract", _embryo_fp_fract);
322 embryo_program_native_call_add(ep, "round", _embryo_fp_round);
323 embryo_program_native_call_add(ep, "float_cmp", _embryo_fp_cmp);
324 embryo_program_native_call_add(ep, "sqrt", _embryo_fp_sqroot);
325 embryo_program_native_call_add(ep, "pow", _embryo_fp_power);
326 embryo_program_native_call_add(ep, "log", _embryo_fp_log);
327 embryo_program_native_call_add(ep, "sin", _embryo_fp_sin);
328 embryo_program_native_call_add(ep, "cos", _embryo_fp_cos);
329 embryo_program_native_call_add(ep, "tan", _embryo_fp_tan);
330 embryo_program_native_call_add(ep, "abs", _embryo_fp_abs);
331}