]> git.mxchange.org Git - simgear.git/blob - simgear/nasal/mathlib.c
canvas::Layout: support for contents margins.
[simgear.git] / simgear / nasal / mathlib.c
1 #include <math.h>
2 #include <string.h>
3
4 #include "nasal.h"
5
6 // Toss a runtime error for any NaN or Inf values produced.  Note that
7 // this assumes an IEEE 754 format.
8 #define VALIDATE(r) (valid(r.num) ? (r) : die(c, __FUNCTION__+2))
9
10 static int valid(double d)
11 {
12     union { double d; unsigned long long ull; } u;
13     u.d = d;
14     return ((u.ull >> 52) & 0x7ff) != 0x7ff;
15 }
16
17 static naRef die(naContext c, const char* fn)
18 {
19     naRuntimeError(c, "floating point error in math.%s()", fn);
20     return naNil();
21 }
22
23 static naRef f_sin(naContext c, naRef me, int argc, naRef* args)
24 {
25     naRef a = naNumValue(argc > 0 ? args[0] : naNil());
26     if(naIsNil(a))
27         naRuntimeError(c, "non numeric argument to sin()");
28     a.num = sin(a.num);
29     return VALIDATE(a);
30 }
31
32 static naRef f_cos(naContext c, naRef me, int argc, naRef* args)
33 {
34     naRef a = naNumValue(argc > 0 ? args[0] : naNil());
35     if(naIsNil(a))
36         naRuntimeError(c, "non numeric argument to cos()");
37     a.num = cos(a.num);
38     return VALIDATE(a);
39 }
40
41 static naRef f_exp(naContext c, naRef me, int argc, naRef* args)
42 {
43     naRef a = naNumValue(argc > 0 ? args[0] : naNil());
44     if(naIsNil(a))
45         naRuntimeError(c, "non numeric argument to exp()");
46     a.num = exp(a.num);
47     return VALIDATE(a);
48 }
49
50 static naRef f_ln(naContext c, naRef me, int argc, naRef* args)
51 {
52     naRef a = naNumValue(argc > 0 ? args[0] : naNil());
53     if(naIsNil(a))
54         naRuntimeError(c, "non numeric argument to ln()");
55     a.num = log(a.num);
56     return VALIDATE(a);
57 }
58
59 static naRef f_sqrt(naContext c, naRef me, int argc, naRef* args)
60 {
61     naRef a = naNumValue(argc > 0 ? args[0] : naNil());
62     if(naIsNil(a))
63         naRuntimeError(c, "non numeric argument to sqrt()");
64     a.num = sqrt(a.num);
65     return VALIDATE(a);
66 }
67
68 static naRef f_pow(naContext c, naRef me, int argc, naRef* args)
69 {
70     naRef a = naNumValue(argc > 0 ? args[0] : naNil());
71     naRef b = naNumValue(argc > 1 ? args[1] : naNil());
72     if(naIsNil(a) || naIsNil(b))
73         naRuntimeError(c, "non numeric argument to pow()");
74     a.num = pow(a.num, b.num);
75     return VALIDATE(a);
76 }
77
78 static naRef f_atan2(naContext c, naRef me, int argc, naRef* args)
79 {
80     naRef a = naNumValue(argc > 0 ? args[0] : naNil());
81     naRef b = naNumValue(argc > 1 ? args[1] : naNil());
82     if(naIsNil(a) || naIsNil(b))
83         naRuntimeError(c, "non numeric argument to atan2()");
84     a.num = atan2(a.num, b.num);
85     return VALIDATE(a);
86 }
87
88 static naRef f_floor(naContext c, naRef me, int argc, naRef* args)
89 {
90     naRef a = naNumValue(argc > 0 ? args[0] : naNil());
91     if(naIsNil(a))
92         naRuntimeError(c, "non numeric argument to floor()");
93     a.num = floor(a.num);
94     return VALIDATE(a);
95 }
96
97 static naRef f_ceil(naContext c, naRef me, int argc, naRef* args)
98 {
99     naRef a = naNumValue(argc > 0 ? args[0] : naNil());
100     if(naIsNil(a))
101         naRuntimeError(c, "non numeric argument to ceil()");
102     a.num = ceil(a.num);
103     return VALIDATE(a);
104 }
105
106 static naRef f_fmod(naContext c, naRef me, int argc, naRef* args)
107 {
108     naRef a = naNumValue(argc > 0 ? args[0] : naNil());
109     naRef b = naNumValue(argc > 1 ? args[1] : naNil());
110     if(naIsNil(a) || naIsNil(b))
111         naRuntimeError(c, "non numeric arguments to fmod()");
112     
113     a.num = fmod(a.num, b.num);
114     return VALIDATE(a);
115 }
116
117 static naRef f_clamp(naContext c, naRef me, int argc, naRef* args)
118 {
119     naRef a = naNumValue(argc > 0 ? args[0] : naNil());
120     naRef b = naNumValue(argc > 1 ? args[1] : naNil());
121     naRef x = naNumValue(argc > 2 ? args[2] : naNil());
122     
123     if(naIsNil(a) || naIsNil(b) || naIsNil(x))
124         naRuntimeError(c, "non numeric arguments to clamp()");
125     
126     if (a.num < b.num) b.num = a.num;
127     if (b.num > x.num) b.num = x.num;
128     return VALIDATE(b);
129 }
130
131 static naRef f_periodic(naContext c, naRef me, int argc, naRef* args)
132 {
133     double range;
134     naRef a = naNumValue(argc > 0 ? args[0] : naNil());
135     naRef b = naNumValue(argc > 1 ? args[1] : naNil());
136     naRef x = naNumValue(argc > 2 ? args[2] : naNil());
137     
138     if(naIsNil(a) || naIsNil(b) || naIsNil(x))
139         naRuntimeError(c, "non numeric arguments to periodic()");
140   
141     range = b.num - a.num;
142     x.num = x.num - range*floor((x.num - a.num)/range);
143     // two security checks that can only happen due to roundoff
144     if (x.num <= a.num)
145         x.num = a.num;
146     if (b.num <= x.num)
147         x.num = b.num;
148     return VALIDATE(x);
149       
150 //    x.num = SGMiscd::normalizePeriodic(a, b, x);
151     return VALIDATE(x);
152 }
153
154 static naRef f_round(naContext c, naRef me, int argc, naRef* args)
155 {
156     naRef a = naNumValue(argc > 0 ? args[0] : naNil());
157     naRef b = naNumValue(argc > 1 ? args[1] : naNil());
158 #ifdef _MSC_VER
159     double x,y;
160 #endif    
161     if(naIsNil(a))
162         naRuntimeError(c, "non numeric arguments to round()");
163     if (naIsNil(b))
164         b.num = 1.0;
165
166 #ifdef _MSC_VER // MSVC is not C99-compatible, no round() in math.h
167     y = a.num / b.num;
168     x = floor(y + 0.5);
169 #else
170     double x = round(a.num / b.num);
171 #endif
172     a.num = x * b.num;
173     
174     return VALIDATE(a);
175 }
176
177
178 static naRef f_tan(naContext c, naRef me, int argc, naRef* args)
179 {
180     naRef a = naNumValue(argc > 0 ? args[0] : naNil());    
181     if(naIsNil(a))
182         naRuntimeError(c, "non numeric arguments to tan()");
183     
184    a.num = tan(a.num);
185    return VALIDATE(a);
186 }
187
188 static naRef f_asin(naContext c, naRef me, int argc, naRef* args)
189 {
190     naRef a = naNumValue(argc > 0 ? args[0] : naNil());
191     if(naIsNil(a))
192         naRuntimeError(c, "non numeric argument to asin()");
193     a.num = asin(a.num);
194     return VALIDATE(a);
195 }
196
197 static naRef f_acos(naContext c, naRef me, int argc, naRef* args)
198 {
199     naRef a = naNumValue(argc > 0 ? args[0] : naNil());
200     if(naIsNil(a))
201         naRuntimeError(c, "non numeric argument to acos()");
202     a.num = acos(a.num);
203     return VALIDATE(a);
204 }
205
206 static naCFuncItem funcs[] = {
207     { "sin", f_sin },
208     { "cos", f_cos },
209     { "exp", f_exp },
210     { "ln", f_ln },
211     { "pow", f_pow },
212     { "sqrt", f_sqrt },
213     { "atan2", f_atan2 },
214     { "floor", f_floor },
215     { "ceil", f_ceil },
216     { "fmod", f_fmod },
217     { "clamp", f_clamp },
218     { "periodic", f_periodic },    
219     { "round", f_round }, 
220     { "tan", f_tan },   
221     { "acos", f_acos },
222     { "asin", f_asin },   
223     { 0 }
224 };
225
226
227
228 naRef naInit_math(naContext c)
229 {
230     naRef ns = naGenLib(c, funcs);
231     naAddSym(c, ns, "pi", naNum(3.14159265358979323846));
232     naAddSym(c, ns, "e", naNum(2.7182818284590452354));
233     return ns;
234 }