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))
10 static int valid(double d)
12 union { double d; unsigned long long ull; } u;
14 return ((u.ull >> 52) & 0x7ff) != 0x7ff;
17 static naRef die(naContext c, const char* fn)
19 naRuntimeError(c, "floating point error in math.%s()", fn);
23 static naRef f_sin(naContext c, naRef me, int argc, naRef* args)
25 naRef a = naNumValue(argc > 0 ? args[0] : naNil());
27 naRuntimeError(c, "non numeric argument to sin()");
32 static naRef f_cos(naContext c, naRef me, int argc, naRef* args)
34 naRef a = naNumValue(argc > 0 ? args[0] : naNil());
36 naRuntimeError(c, "non numeric argument to cos()");
41 static naRef f_exp(naContext c, naRef me, int argc, naRef* args)
43 naRef a = naNumValue(argc > 0 ? args[0] : naNil());
45 naRuntimeError(c, "non numeric argument to exp()");
50 static naRef f_ln(naContext c, naRef me, int argc, naRef* args)
52 naRef a = naNumValue(argc > 0 ? args[0] : naNil());
54 naRuntimeError(c, "non numeric argument to ln()");
59 static naRef f_sqrt(naContext c, naRef me, int argc, naRef* args)
61 naRef a = naNumValue(argc > 0 ? args[0] : naNil());
63 naRuntimeError(c, "non numeric argument to sqrt()");
68 static naRef f_pow(naContext c, naRef me, int argc, naRef* args)
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);
78 static naRef f_atan2(naContext c, naRef me, int argc, naRef* args)
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);
88 static naRef f_floor(naContext c, naRef me, int argc, naRef* args)
90 naRef a = naNumValue(argc > 0 ? args[0] : naNil());
92 naRuntimeError(c, "non numeric argument to floor()");
97 static naRef f_ceil(naContext c, naRef me, int argc, naRef* args)
99 naRef a = naNumValue(argc > 0 ? args[0] : naNil());
101 naRuntimeError(c, "non numeric argument to ceil()");
106 static naRef f_fmod(naContext c, naRef me, int argc, naRef* args)
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()");
113 a.num = fmod(a.num, b.num);
117 static naRef f_clamp(naContext c, naRef me, int argc, naRef* args)
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());
123 if(naIsNil(a) || naIsNil(b) || naIsNil(x))
124 naRuntimeError(c, "non numeric arguments to clamp()");
126 if (a.num < b.num) b.num = a.num;
127 if (b.num > x.num) b.num = x.num;
131 static naRef f_periodic(naContext c, naRef me, int argc, naRef* args)
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());
138 if(naIsNil(a) || naIsNil(b) || naIsNil(x))
139 naRuntimeError(c, "non numeric arguments to periodic()");
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
150 // x.num = SGMiscd::normalizePeriodic(a, b, x);
154 static naRef f_round(naContext c, naRef me, int argc, naRef* args)
156 naRef a = naNumValue(argc > 0 ? args[0] : naNil());
157 naRef b = naNumValue(argc > 1 ? args[1] : naNil());
162 naRuntimeError(c, "non numeric arguments to round()");
166 #ifdef _MSC_VER // MSVC is not C99-compatible, no round() in math.h
170 double x = round(a.num / b.num);
178 static naRef f_tan(naContext c, naRef me, int argc, naRef* args)
180 naRef a = naNumValue(argc > 0 ? args[0] : naNil());
182 naRuntimeError(c, "non numeric arguments to tan()");
188 static naRef f_asin(naContext c, naRef me, int argc, naRef* args)
190 naRef a = naNumValue(argc > 0 ? args[0] : naNil());
192 naRuntimeError(c, "non numeric argument to asin()");
197 static naRef f_acos(naContext c, naRef me, int argc, naRef* args)
199 naRef a = naNumValue(argc > 0 ? args[0] : naNil());
201 naRuntimeError(c, "non numeric argument to acos()");
206 static naCFuncItem funcs[] = {
213 { "atan2", f_atan2 },
214 { "floor", f_floor },
217 { "clamp", f_clamp },
218 { "periodic", f_periodic },
219 { "round", f_round },
228 naRef naInit_math(naContext c)
230 naRef ns = naGenLib(c, funcs);
231 naAddSym(c, ns, "pi", naNum(3.14159265358979323846));
232 naAddSym(c, ns, "e", naNum(2.7182818284590452354));