6efa2ae82da1a4b5d189091acc10409677702689
[framework/uifw/embryo.git] / src / lib / embryo_float.c
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
54 static 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
71 static 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
82 static 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
100 static 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
112 static 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
124 static 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
136 static 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 */
149 static 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 */
162 static 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
190 static 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
205 static 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
222 static 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
236 static 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 if (ff == 2.0) f = log2f(f);
253     else f = (logf(f) / logf(ff));
254     return EMBRYO_FLOAT_TO_CELL(f);
255 }
256
257 static Embryo_Cell
258 _embryo_fp_sin(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
259 {
260    /* params[1] = float operand 1 (angle) */
261    /* params[2] = float operand 2 (radix) */
262    float f;
263
264    if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
265    f = EMBRYO_CELL_TO_FLOAT(params[1]);
266    f = _embryo_fp_degrees_to_radians(f, params[2]);
267    f = sinf(f);
268    return EMBRYO_FLOAT_TO_CELL(f);
269 }
270
271 static Embryo_Cell
272 _embryo_fp_cos(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
273 {
274    /* params[1] = float operand 1 (angle) */
275    /* params[2] = float operand 2 (radix) */
276    float f;
277
278    if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
279    f = EMBRYO_CELL_TO_FLOAT(params[1]);
280    f = _embryo_fp_degrees_to_radians(f, params[2]);
281    f = cosf(f);
282    return EMBRYO_FLOAT_TO_CELL(f);
283 }
284
285 static Embryo_Cell
286 _embryo_fp_tan(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
287 {
288    /* params[1] = float operand 1 (angle) */
289    /* params[2] = float operand 2 (radix) */
290    float f;
291
292    if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
293    f = EMBRYO_CELL_TO_FLOAT(params[1]);
294    f = _embryo_fp_degrees_to_radians(f, params[2]);
295    f = tanf(f);
296    return EMBRYO_FLOAT_TO_CELL(f);
297 }
298
299 static Embryo_Cell
300 _embryo_fp_abs(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
301 {
302    /* params[1] = float operand */
303    float f;
304
305    if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
306    f = EMBRYO_CELL_TO_FLOAT(params[1]);
307    f = (f >= 0) ? f : -f;
308    return EMBRYO_FLOAT_TO_CELL(f);
309 }
310
311 static Embryo_Cell
312 _embryo_fp_asin(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
313 {
314    /* params[1] = float operand 1 (angle) */
315    /* params[2] = float operand 2 (radix) */
316    float f;
317
318    if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
319    f = EMBRYO_CELL_TO_FLOAT(params[1]);
320    f = sinf(f);
321    f = _embryo_fp_degrees_to_radians(f, params[2]);
322    return EMBRYO_FLOAT_TO_CELL(f);
323 }
324
325 static Embryo_Cell
326 _embryo_fp_acos(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
327 {
328    /* params[1] = float operand 1 (angle) */
329    /* params[2] = float operand 2 (radix) */
330    float f;
331
332    if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
333    f = EMBRYO_CELL_TO_FLOAT(params[1]);
334    f = cosf(f);
335    f = _embryo_fp_degrees_to_radians(f, params[2]);
336    return EMBRYO_FLOAT_TO_CELL(f);
337 }
338
339 static Embryo_Cell
340 _embryo_fp_atan(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
341 {
342    /* params[1] = float operand 1 (angle) */
343    /* params[2] = float operand 2 (radix) */
344    float f;
345
346    if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
347    f = EMBRYO_CELL_TO_FLOAT(params[1]);
348    f = tanf(f);
349    f = _embryo_fp_degrees_to_radians(f, params[2]);
350    return EMBRYO_FLOAT_TO_CELL(f);
351 }
352
353 static Embryo_Cell
354 _embryo_fp_atan2(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
355 {
356    /* params[1] = float operand 1 (y) */
357    /* params[2] = float operand 2 (x) */
358    /* params[3] = float operand 3 (radix) */
359    float f, ff;
360
361    if (params[0] != (3 * sizeof(Embryo_Cell))) return 0;
362    f = EMBRYO_CELL_TO_FLOAT(params[1]);
363    ff = EMBRYO_CELL_TO_FLOAT(params[2]);
364    f = atan2f(f, ff);
365    f = _embryo_fp_degrees_to_radians(f, params[3]);
366    return EMBRYO_FLOAT_TO_CELL(f);
367 }
368
369 static Embryo_Cell
370 _embryo_fp_log1p(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
371 {
372    /* params[1] = float operand */
373    float f;
374
375    if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
376    f = EMBRYO_CELL_TO_FLOAT(params[1]);
377    f = log1pf(f);
378    return EMBRYO_FLOAT_TO_CELL(f);
379 }
380
381 static Embryo_Cell
382 _embryo_fp_cbrt(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
383 {
384    /* params[1] = float operand */
385    float f;
386
387    if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
388    f = EMBRYO_CELL_TO_FLOAT(params[1]);
389    f = cbrtf(f);
390    return EMBRYO_FLOAT_TO_CELL(f);
391 }
392
393 static Embryo_Cell
394 _embryo_fp_exp(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
395 {
396    /* params[1] = float operand */
397    float f;
398
399    if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
400    f = EMBRYO_CELL_TO_FLOAT(params[1]);
401    f = expf(f);
402    return EMBRYO_FLOAT_TO_CELL(f);
403 }
404
405 static Embryo_Cell
406 _embryo_fp_exp2(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
407 {
408    /* params[1] = float operand */
409    float f;
410
411    if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
412    f = EMBRYO_CELL_TO_FLOAT(params[1]);
413    f = exp2f(f);
414    return EMBRYO_FLOAT_TO_CELL(f);
415 }
416
417 static Embryo_Cell
418 _embryo_fp_hypot(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
419 {
420    /* params[1] = float operand */
421    float f, ff;
422
423    if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
424    f = EMBRYO_CELL_TO_FLOAT(params[1]);
425    ff = EMBRYO_CELL_TO_FLOAT(params[2]);
426    f = hypotf(f, ff);
427    return EMBRYO_FLOAT_TO_CELL(f);
428 }
429
430 /* functions used by the rest of embryo */
431
432 void
433 _embryo_fp_init(Embryo_Program *ep)
434 {
435    embryo_program_native_call_add(ep, "float",     _embryo_fp);
436    embryo_program_native_call_add(ep, "atof",      _embryo_fp_str);
437    embryo_program_native_call_add(ep, "float_mul", _embryo_fp_mul);
438    embryo_program_native_call_add(ep, "float_div", _embryo_fp_div);
439    embryo_program_native_call_add(ep, "float_add", _embryo_fp_add);
440    embryo_program_native_call_add(ep, "float_sub", _embryo_fp_sub);
441    embryo_program_native_call_add(ep, "fract",     _embryo_fp_fract);
442    embryo_program_native_call_add(ep, "round",     _embryo_fp_round);
443    embryo_program_native_call_add(ep, "float_cmp", _embryo_fp_cmp);
444    embryo_program_native_call_add(ep, "sqrt",      _embryo_fp_sqroot);
445    embryo_program_native_call_add(ep, "pow",       _embryo_fp_power);
446    embryo_program_native_call_add(ep, "log",       _embryo_fp_log);
447    embryo_program_native_call_add(ep, "sin",       _embryo_fp_sin);
448    embryo_program_native_call_add(ep, "cos",       _embryo_fp_cos);
449    embryo_program_native_call_add(ep, "tan",       _embryo_fp_tan);
450    embryo_program_native_call_add(ep, "abs",       _embryo_fp_abs);
451    /* Added in embryo 1.2 */
452    embryo_program_native_call_add(ep, "asin",      _embryo_fp_asin);
453    embryo_program_native_call_add(ep, "acos",      _embryo_fp_acos);
454    embryo_program_native_call_add(ep, "atan",      _embryo_fp_atan);
455    embryo_program_native_call_add(ep, "atan2",     _embryo_fp_atan2);
456    embryo_program_native_call_add(ep, "log1p",     _embryo_fp_log1p);
457    embryo_program_native_call_add(ep, "cbrt",      _embryo_fp_cbrt);
458    embryo_program_native_call_add(ep, "exp",       _embryo_fp_exp);
459    embryo_program_native_call_add(ep, "exp2",      _embryo_fp_exp2);
460    embryo_program_native_call_add(ep, "hypot",     _embryo_fp_hypot);
461 }