X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fnasal%2Fmathlib.c;h=f2434b3cfe1dafe38cdfeba827716d8b91c1dc66;hb=e036dfc5bf691e2cb467f27010c3291f5b1c13a7;hp=d6fc020f74877474b3b2ee108f6d0b99bb4c66fc;hpb=979d3da69c085733d573af7298a3fd95fb4574a3;p=simgear.git diff --git a/simgear/nasal/mathlib.c b/simgear/nasal/mathlib.c index d6fc020f..f2434b3c 100644 --- a/simgear/nasal/mathlib.c +++ b/simgear/nasal/mathlib.c @@ -1,19 +1,32 @@ -#ifdef _MSC_VER -#define _USE_MATH_DEFINES -#endif - #include #include #include "nasal.h" +// Toss a runtime error for any NaN or Inf values produced. Note that +// this assumes an IEEE 754 format. +#define VALIDATE(r) (valid(r.num) ? (r) : die(c, __FUNCTION__+2)) + +static int valid(double d) +{ + union { double d; unsigned long long ull; } u; + u.d = d; + return ((u.ull >> 52) & 0x7ff) != 0x7ff; +} + +static naRef die(naContext c, const char* fn) +{ + naRuntimeError(c, "floating point error in math.%s()", fn); + return naNil(); +} + static naRef f_sin(naContext c, naRef me, int argc, naRef* args) { naRef a = naNumValue(argc > 0 ? args[0] : naNil()); if(naIsNil(a)) naRuntimeError(c, "non numeric argument to sin()"); a.num = sin(a.num); - return a; + return VALIDATE(a); } static naRef f_cos(naContext c, naRef me, int argc, naRef* args) @@ -22,7 +35,7 @@ static naRef f_cos(naContext c, naRef me, int argc, naRef* args) if(naIsNil(a)) naRuntimeError(c, "non numeric argument to cos()"); a.num = cos(a.num); - return a; + return VALIDATE(a); } static naRef f_exp(naContext c, naRef me, int argc, naRef* args) @@ -31,7 +44,7 @@ static naRef f_exp(naContext c, naRef me, int argc, naRef* args) if(naIsNil(a)) naRuntimeError(c, "non numeric argument to exp()"); a.num = exp(a.num); - return a; + return VALIDATE(a); } static naRef f_ln(naContext c, naRef me, int argc, naRef* args) @@ -40,7 +53,7 @@ static naRef f_ln(naContext c, naRef me, int argc, naRef* args) if(naIsNil(a)) naRuntimeError(c, "non numeric argument to ln()"); a.num = log(a.num); - return a; + return VALIDATE(a); } static naRef f_sqrt(naContext c, naRef me, int argc, naRef* args) @@ -49,7 +62,17 @@ static naRef f_sqrt(naContext c, naRef me, int argc, naRef* args) if(naIsNil(a)) naRuntimeError(c, "non numeric argument to sqrt()"); a.num = sqrt(a.num); - return a; + return VALIDATE(a); +} + +static naRef f_pow(naContext c, naRef me, int argc, naRef* args) +{ + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + naRef b = naNumValue(argc > 1 ? args[1] : naNil()); + if(naIsNil(a) || naIsNil(b)) + naRuntimeError(c, "non numeric argument to pow()"); + a.num = pow(a.num, b.num); + return VALIDATE(a); } static naRef f_atan2(naContext c, naRef me, int argc, naRef* args) @@ -59,37 +82,153 @@ static naRef f_atan2(naContext c, naRef me, int argc, naRef* args) if(naIsNil(a) || naIsNil(b)) naRuntimeError(c, "non numeric argument to atan2()"); a.num = atan2(a.num, b.num); - return a; + return VALIDATE(a); } -static struct func { char* name; naCFunction func; } funcs[] = { +static naRef f_floor(naContext c, naRef me, int argc, naRef* args) +{ + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + if(naIsNil(a)) + naRuntimeError(c, "non numeric argument to floor()"); + a.num = floor(a.num); + return VALIDATE(a); +} + +static naRef f_ceil(naContext c, naRef me, int argc, naRef* args) +{ + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + if(naIsNil(a)) + naRuntimeError(c, "non numeric argument to ceil()"); + a.num = ceil(a.num); + return VALIDATE(a); +} + +static naRef f_fmod(naContext c, naRef me, int argc, naRef* args) +{ + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + naRef b = naNumValue(argc > 1 ? args[1] : naNil()); + if(naIsNil(a) || naIsNil(b)) + naRuntimeError(c, "non numeric arguments to fmod()"); + + a.num = fmod(a.num, b.num); + return VALIDATE(a); +} + +static naRef f_clamp(naContext c, naRef me, int argc, naRef* args) +{ + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + naRef b = naNumValue(argc > 1 ? args[1] : naNil()); + naRef x = naNumValue(argc > 2 ? args[2] : naNil()); + + if(naIsNil(a) || naIsNil(b) || naIsNil(x)) + naRuntimeError(c, "non numeric arguments to clamp()"); + + if (a.num < b.num) b.num = a.num; + if (b.num > x.num) b.num = x.num; + return VALIDATE(b); +} + +static naRef f_periodic(naContext c, naRef me, int argc, naRef* args) +{ + double range; + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + naRef b = naNumValue(argc > 1 ? args[1] : naNil()); + naRef x = naNumValue(argc > 2 ? args[2] : naNil()); + + if(naIsNil(a) || naIsNil(b) || naIsNil(x)) + naRuntimeError(c, "non numeric arguments to periodic()"); + + range = b.num - a.num; + x.num = x.num - range*floor((x.num - a.num)/range); + // two security checks that can only happen due to roundoff + if (x.num <= a.num) + x.num = a.num; + if (b.num <= x.num) + x.num = b.num; + return VALIDATE(x); + +// x.num = SGMiscd::normalizePeriodic(a, b, x); + return VALIDATE(x); +} + +static naRef f_round(naContext c, naRef me, int argc, naRef* args) +{ + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + naRef b = naNumValue(argc > 1 ? args[1] : naNil()); +#ifdef _MSC_VER + double x,y; +#endif + if(naIsNil(a)) + naRuntimeError(c, "non numeric arguments to round()"); + if (naIsNil(b)) + b.num = 1.0; + +#ifdef _MSC_VER // MSVC is not C99-compatible, no round() in math.h + y = a.num / b.num; + x = floor(y + 0.5); +#else + double x = round(a.num / b.num); +#endif + a.num = x * b.num; + + return VALIDATE(a); +} + + +static naRef f_tan(naContext c, naRef me, int argc, naRef* args) +{ + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + if(naIsNil(a)) + naRuntimeError(c, "non numeric arguments to tan()"); + + a.num = tan(a.num); + return VALIDATE(a); +} + +static naRef f_asin(naContext c, naRef me, int argc, naRef* args) +{ + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + if(naIsNil(a)) + naRuntimeError(c, "non numeric argument to asin()"); + a.num = asin(a.num); + return VALIDATE(a); +} + +static naRef f_acos(naContext c, naRef me, int argc, naRef* args) +{ + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + if(naIsNil(a)) + naRuntimeError(c, "non numeric argument to acos()"); + a.num = acos(a.num); + return VALIDATE(a); +} + +static naCFuncItem funcs[] = { { "sin", f_sin }, { "cos", f_cos }, { "exp", f_exp }, { "ln", f_ln }, + { "pow", f_pow }, { "sqrt", f_sqrt }, { "atan2", f_atan2 }, + { "floor", f_floor }, + { "ceil", f_ceil }, + { "fmod", f_fmod }, + { "clamp", f_clamp }, + { "periodic", f_periodic }, + { "round", f_round }, + { "tan", f_tan }, + { "acos", f_acos }, + { "asin", f_asin }, + { 0 } }; -naRef naMathLib(naContext c) -{ - naRef name, namespace = naNewHash(c); - int i, n = sizeof(funcs)/sizeof(struct func); - for(i=0; i