move around - flatter.
[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  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
41  */
42
43 #include <math.h>
44 #include "embryo_private.h"
45
46 #define PI  3.1415926535897932384626433832795
47
48 /* internally useful calls */
49
50 static float
51 _embryo_fp_degrees_to_radians(float angle, int radix)
52 {
53    switch (radix)
54      {
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 */
60         break;
61      }
62    return angle;
63 }
64
65 /* exported float api */
66
67 static Embryo_Cell
68 _embryo_fp(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
69 {
70    /* params[1] = long value to convert to a float */
71    float f;
72
73    if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
74    f = (float)params[1];
75    return EMBRYO_FLOAT_TO_CELL(f);
76 }
77
78 static Embryo_Cell
79 _embryo_fp_str(Embryo_Program *ep, Embryo_Cell *params)
80 {
81    /* params[1] = virtual string address to convert to a float */
82    char buf[64];
83    Embryo_Cell *str;
84    float f;
85    int len;
86
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);
92    f = (float)atof(buf);
93    return EMBRYO_FLOAT_TO_CELL(f);
94 }
95
96 static Embryo_Cell
97 _embryo_fp_mul(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
98 {
99    /* params[1] = float operand 1 */
100    /* params[2] = float operand 2 */
101    float f;
102
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);
106 }
107
108 static Embryo_Cell
109 _embryo_fp_div(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
110 {
111    /* params[1] = float dividend (top) */
112    /* params[2] = float divisor (bottom) */
113    float f;
114
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);
118 }
119
120 static Embryo_Cell
121 _embryo_fp_add(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
122 {
123    /* params[1] = float operand 1 */
124    /* params[2] = float operand 2 */
125    float f;
126
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);
130 }
131
132 static Embryo_Cell
133 _embryo_fp_sub(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
134 {
135    /* params[1] = float operand 1 */
136    /* params[2] = float operand 2 */
137    float f;
138
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);
142 }
143
144 /* Return fractional part of float */
145 static Embryo_Cell
146 _embryo_fp_fract(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
147 {
148    /* params[1] = float operand */
149    float f;
150
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);
155 }
156
157 /* Return integer part of float, rounded */
158 static Embryo_Cell
159 _embryo_fp_round(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
160 {
161    /* params[1] = float operand */
162    /* params[2] = Type of rounding (cell) */
163    float f;
164
165    if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
166    f = EMBRYO_CELL_TO_FLOAT(params[1]);
167    switch (params[2])
168      {
169       case 1: /* round downwards (truncate) */
170         f = (float)(floor((double)f));
171         break;
172       case 2: /* round upwards */
173         f = (float)(ceil((double)f));
174         break;
175       case 3: /* round towards zero */
176         if (f >= 0.0) f = (float)(floor((double)f));
177         else          f = (float)(ceil((double)f));
178         break;
179       default: /* standard, round to nearest */
180         f = (float)(floor((double)f + 0.5));
181         break;
182      }
183     return (Embryo_Cell)f;
184 }
185
186 static Embryo_Cell
187 _embryo_fp_cmp(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
188 {
189    /* params[1] = float operand 1 */
190    /* params[2] = float operand 2 */
191    float f, ff;
192
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;
198    return -1;
199 }
200
201 static Embryo_Cell
202 _embryo_fp_sqroot(Embryo_Program *ep, Embryo_Cell *params)
203 {
204    /* params[1] = float operand */
205    float f;
206
207    if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
208    f = EMBRYO_CELL_TO_FLOAT(params[1]);
209    f = (float)sqrt(f);
210    if (f < 0)
211      {
212         embryo_program_error_set(ep, EMBRYO_ERROR_DOMAIN);
213         return 0;
214      }
215    return EMBRYO_FLOAT_TO_CELL(f);
216 }
217
218 static Embryo_Cell
219 _embryo_fp_power(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
220 {
221    /* params[1] = float operand 1 */
222    /* params[2] = float operand 2 */
223    float f, ff;
224
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);
230 }
231
232 static Embryo_Cell
233 _embryo_fp_log(Embryo_Program *ep, Embryo_Cell *params)
234 {
235    /* params[1] = float operand 1 (value) */
236    /* params[2] = float operand 2 (base) */
237    float f, ff;
238
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))
243      {
244         embryo_program_error_set(ep, EMBRYO_ERROR_DOMAIN);
245         return 0;
246      }
247     if (ff == 10.0) f = (float)log10(f);
248     else f = (float)(log(f) / log(ff));
249     return EMBRYO_FLOAT_TO_CELL(f);
250 }
251
252 static Embryo_Cell
253 _embryo_fp_sin(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
254 {
255    /* params[1] = float operand 1 (angle) */
256    /* params[2] = float operand 2 (radix) */
257    float f;
258
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]);
262    f = sin(f);
263    return EMBRYO_FLOAT_TO_CELL(f);
264 }
265
266 static Embryo_Cell
267 _embryo_fp_cos(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
268 {
269    /* params[1] = float operand 1 (angle) */
270    /* params[2] = float operand 2 (radix) */
271    float f;
272
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]);
276    f = cos(f);
277    return EMBRYO_FLOAT_TO_CELL(f);
278 }
279
280 static Embryo_Cell
281 _embryo_fp_tan(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
282 {
283    /* params[1] = float operand 1 (angle) */
284    /* params[2] = float operand 2 (radix) */
285    float f;
286
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]);
290    f = tan(f);
291    return EMBRYO_FLOAT_TO_CELL(f);
292 }
293
294 static Embryo_Cell
295 _embryo_fp_abs(Embryo_Program *ep __UNUSED__, Embryo_Cell *params)
296 {
297    /* params[1] = float operand */
298    float f;
299
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);
304 }
305
306 /* functions used by the rest of embryo */
307
308 void
309 _embryo_fp_init(Embryo_Program *ep)
310 {
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);
327 }