| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374 |
- /* see copyright notice in squirrel.h */
- #include <squirrel.h>
- #include <math.h>
- #include <stdlib.h>
- #include <sqstdmath.h>
- #define SINGLE_ARG_FUNC(_funcname) static SQRESULT math_##_funcname(HSQUIRRELVM v){ \
- SQFloat f; \
- sq_getfloat(v,2,&f); \
- sq_pushfloat(v,(SQFloat)_funcname(f)); \
- return 1; \
- }
- #define TWO_ARGS_FUNC(_funcname) static SQRESULT math_##_funcname(HSQUIRRELVM v){ \
- SQFloat p1,p2; \
- sq_getfloat(v,2,&p1); \
- sq_getfloat(v,3,&p2); \
- sq_pushfloat(v,(SQFloat)_funcname(p1,p2)); \
- return 1; \
- }
- #define BOOL_SINGLE_ARG_FUNC(_funcname) static SQRESULT math_##_funcname(HSQUIRRELVM v){ \
- SQFloat f; \
- sq_getfloat(v,2,&f); \
- sq_pushbool(v,(SQBool)_funcname(f)); \
- return 1; \
- }
- static SQRESULT math_srand(HSQUIRRELVM v)
- {
- SQInteger i;
- if(SQ_FAILED(sq_getinteger(v,2,&i)))
- return sq_throwerror(v,_SC("invalid param"));
- srand((unsigned int)i);
- return 0;
- }
- static SQRESULT math_rand(HSQUIRRELVM v)
- {
- sq_pushinteger(v,rand());
- return 1;
- }
- static SQRESULT math_random(HSQUIRRELVM v) {
- SQ_FUNC_VARS(v);
- /* the `%' avoids the (rare) case of r==1, and is needed also because on
- some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
- SQFloat r = (SQFloat)(rand()%RAND_MAX) / (SQFloat)RAND_MAX;
- if (_top_==1) { /* no arguments: range [0,1) */
- sq_pushfloat(v, r);
- } else if (_top_<=3) { /* int range [1,u] or [l,u] */
- SQ_GET_INTEGER(v, 2, u);
- SQ_OPT_INTEGER(v, 3, l, 1);
- SQFloat d;
- if(l<=u) return sq_throwerror(v, _SC("interval is empty"));
- d= floor(r*(u-l+1));
- int tmp = d;
- sq_pushinteger(v, l+tmp);
- } else return sq_throwerror(v, _SC("wrong number of arguments"));
- return 1;
- }
- static SQRESULT math_abs(HSQUIRRELVM v)
- {
- SQInteger n;
- sq_getinteger(v,2,&n);
- sq_pushinteger(v,(SQInteger)abs((int)n));
- return 1;
- }
- SINGLE_ARG_FUNC(sqrt)
- SINGLE_ARG_FUNC(fabs)
- SINGLE_ARG_FUNC(sin)
- SINGLE_ARG_FUNC(cos)
- SINGLE_ARG_FUNC(asin)
- SINGLE_ARG_FUNC(acos)
- SINGLE_ARG_FUNC(log)
- SINGLE_ARG_FUNC(log10)
- SINGLE_ARG_FUNC(tan)
- SINGLE_ARG_FUNC(atan)
- TWO_ARGS_FUNC(atan2)
- TWO_ARGS_FUNC(pow)
- SINGLE_ARG_FUNC(floor)
- SINGLE_ARG_FUNC(ceil)
- SINGLE_ARG_FUNC(exp)
- BOOL_SINGLE_ARG_FUNC(isnan);
- BOOL_SINGLE_ARG_FUNC(isfinite);
- //DAD start
- #include <string.h>
- #include <stdio.h>
- #include <ctype.h>
- SQ_OPT_STRING_STRLEN();
- /* mathB_roundf: rounds real value x to the d-th digit; patched Dec 22, 2007 for negative values */
- static SQRESULT math_roundf (HSQUIRRELVM v) {
- SQ_FUNC_VARS(v);
- SQ_GET_FLOAT(v, 2, x);
- SQ_OPT_INTEGER(v, 3, dec_places, 0);
- SQFloat dec_factor;
- if( dec_places>15 || dec_places<0 ) return sq_throwerror(v, _SC("decimal places out of range 0-15"));
- switch(dec_places){
- case 0: dec_factor = 1.0; break;
- case 1: dec_factor = 10.0; break;
- case 2: dec_factor = 100.0; break;
- case 3: dec_factor = 1000.0; break;
- case 4: dec_factor = 10000.0; break;
- case 5: dec_factor = 100000.0; break;
- case 6: dec_factor = 1000000.0; break;
- default: dec_factor = pow((double)10.0, dec_places);
- }
- if (x < 0)
- sq_pushfloat(v, ceil(dec_factor*x-0.5) / dec_factor);
- else
- sq_pushfloat(v, floor(dec_factor*x+0.5) / dec_factor);
- return 1;
- }
- static SQRESULT math_broundf (HSQUIRRELVM v) {
- SQ_FUNC_VARS(v);
- SQ_GET_FLOAT(v, 2, num);
- SQ_OPT_INTEGER(v, 3, dec_places, 0);
- SQFloat dec_factor, tmp, itmp;
- int neg;
- if( dec_places>15 || dec_places<0 ) return sq_throwerror(v, _SC("decimal places out of range 0-15"));
- neg = num < 0;
- switch(dec_places){
- case 0: dec_factor = 1.0; break;
- case 1: dec_factor = 10.0; break;
- case 2: dec_factor = 100.0; break;
- case 3: dec_factor = 1000.0; break;
- case 4: dec_factor = 10000.0; break;
- case 5: dec_factor = 100000.0; break;
- case 6: dec_factor = 1000000.0; break;
- default: dec_factor = pow((double)10.0, dec_places);
- }
- tmp = num * dec_factor;
- itmp = floor(tmp + (neg ? -0.5 : 0.5));
- // Handle rounding of .5 in a special manner
- if(tmp - floor(tmp) == 0.5){
- tmp = itmp / 2;
- if(tmp != floor(tmp) ) { // Is itmp odd
- // Reduce Magnitude by 1 to make even
- if(neg) itmp++;
- else itmp--;
- }
- }
- sq_pushfloat(v, itmp / dec_factor);
- return 1;
- }
- static SQChar math_number_format_dec_point[2] = _SC(".");
- static SQChar math_number_format_thousand_sep[2] = _SC(",");
- static SQRESULT math_number_format_get_dec_point(HSQUIRRELVM v) {
- sq_pushstring(v, math_number_format_dec_point, -1);
- return 1;
- }
- static SQRESULT math_number_format_set_dec_point(HSQUIRRELVM v) {
- SQ_FUNC_VARS_NO_TOP(v);
- SQ_GET_STRING(v, 2, dec_point);
- math_number_format_dec_point[0] = *dec_point;
- math_number_format_dec_point[1] = _SC('\0');
- return 0;
- }
- static SQRESULT math_number_format_get_thousand_sep(HSQUIRRELVM v) {
- sq_pushstring(v, math_number_format_thousand_sep, -1);
- return 1;
- }
- static SQRESULT math_number_format_set_thousand_sep(HSQUIRRELVM v) {
- SQ_FUNC_VARS_NO_TOP(v);
- SQ_GET_STRING(v, 2, thousand_sep);
- math_number_format_thousand_sep[0] = *thousand_sep;
- math_number_format_thousand_sep[1] = '\0';
- return 0;
- }
- static SQRESULT math_number_format(HSQUIRRELVM v) {
- SQ_FUNC_VARS(v);
- SQ_GET_FLOAT(v, 2, d);
- SQ_OPT_INTEGER(v, 3, dec, 2);
- SQ_OPT_STRING(v, 4, dec_point, math_number_format_dec_point);
- SQ_OPT_STRING(v, 5, thousand_sep, math_number_format_thousand_sep);
- SQChar tmpbuf[64], resbuf[64];
- SQChar *s, *t; /* source, target */
- SQChar *dp;
- int integral;
- size_t tmplen, reslen=0;
- int count=0;
- int is_negative=0;
- int trim_right_zeros=0;
- if (d < 0) {
- is_negative = 1;
- d = -d;
- }
- if (dec < 0) {
- trim_right_zeros = 1;
- dec = -dec;
- }
- int idec = dec; //on 64 bits there is a warning here about SQInteger/int
- tmplen = scsprintf(tmpbuf, sizeof(tmpbuf), _SC("%.*f"), idec, d);
- resbuf[0] = _SC('\0');
- if (isdigit((int)tmpbuf[0])) {
- /* find decimal point, if expected */
- if (dec) {
- dp = scstrpbrk(tmpbuf, _SC(".,"));
- } else {
- dp = NULL;
- }
- /* calculate the length of the return buffer */
- if (dp) {
- integral = dp - tmpbuf;
- } else {
- /* no decimal point was found */
- integral = tmplen;
- }
- /* allow for thousand separators */
- if (*thousand_sep) {
- integral += (integral-1) / 3;
- }
- reslen = integral;
- if (dec) {
- reslen += dec;
- if (*dec_point) {
- reslen++;
- }
- }
- /* add a byte for minus sign */
- if (is_negative) {
- reslen++;
- }
- if(sizeof(resbuf) >= reslen+1) {
- s = tmpbuf+tmplen-1;
- t = resbuf+reslen;
- *t-- = '\0';
- /* copy the decimal places.
- * Take care, as the sprintf implementation may return less places than
- * we requested due to internal buffer limitations */
- if (dec) {
- int declen = dp ? s - dp : 0;
- int topad = dec > declen ? dec - declen : 0;
- /* pad with '0's */
- while (topad--) {
- *t-- = '0';
- }
- if (dp) {
- s -= declen + 1; /* +1 to skip the point */
- t -= declen;
- /* now copy the chars after the point */
- memcpy(t + 1, dp + 1, declen);
- }
- /* add decimal point */
- if (*dec_point) {
- *t-- = *dec_point;
- }
- }
- /* copy the numbers before the decimal point, adding thousand
- * separator every three digits */
- while(s >= tmpbuf) {
- *t-- = *s--;
- if (*thousand_sep && (++count%3)==0 && s>=tmpbuf) {
- *t-- = *thousand_sep;
- }
- }
- /* and a minus sign, if needed */
- if (is_negative) {
- *t-- = '-';
- }
- /* trim right zeros */
- if (*dec_point && trim_right_zeros) {
- for(t=resbuf+reslen-1; *t != *dec_point; t--){
- if (*t == '0') *t = '\0';
- else break;
- }
- if (*t == *dec_point) *t = '\0';
- }
- }
- }
- sq_pushstring(v, resbuf, -1);
- return 1;
- }
- //DAD end
- #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),math_##name,nparams,tycheck}
- static const SQRegFunction mathlib_funcs[] = {
- _DECL_FUNC(sqrt,2,_SC(".n")),
- _DECL_FUNC(sin,2,_SC(".n")),
- _DECL_FUNC(cos,2,_SC(".n")),
- _DECL_FUNC(asin,2,_SC(".n")),
- _DECL_FUNC(acos,2,_SC(".n")),
- _DECL_FUNC(log,2,_SC(".n")),
- _DECL_FUNC(log10,2,_SC(".n")),
- _DECL_FUNC(tan,2,_SC(".n")),
- _DECL_FUNC(atan,2,_SC(".n")),
- _DECL_FUNC(atan2,3,_SC(".nn")),
- _DECL_FUNC(pow,3,_SC(".nn")),
- _DECL_FUNC(floor,2,_SC(".n")),
- _DECL_FUNC(ceil,2,_SC(".n")),
- _DECL_FUNC(exp,2,_SC(".n")),
- _DECL_FUNC(srand,2,_SC(".n")),
- _DECL_FUNC(rand,1,NULL),
- _DECL_FUNC(random,-1,_SC(".ii")),
- _DECL_FUNC(fabs,2,_SC(".n")),
- _DECL_FUNC(abs,2,_SC(".n")),
- _DECL_FUNC(isnan,2,_SC(".n")),
- _DECL_FUNC(isfinite,2,_SC(".n")),
- _DECL_FUNC(roundf,-2,_SC(".ni")),
- _DECL_FUNC(broundf,-2,_SC(".ni")),
- _DECL_FUNC(number_format,-2,_SC(".niss")),
- _DECL_FUNC(number_format_get_dec_point,1,_SC(".")),
- _DECL_FUNC(number_format_set_dec_point,2,_SC(".s")),
- _DECL_FUNC(number_format_get_thousand_sep,1,_SC(".")),
- _DECL_FUNC(number_format_set_thousand_sep,2,_SC(".s")),
- {NULL,(SQFUNCTION)0,0,NULL}
- };
- #undef _DECL_FUNC
- #ifndef M_PI
- #define M_PI (3.14159265358979323846)
- #endif
- SQRESULT sqstd_register_mathlib(HSQUIRRELVM v)
- {
- sq_pushstring(v,_SC("math"),-1);
- sq_newtable(v);
- SQInteger i=0;
- while(mathlib_funcs[i].name!=0) {
- sq_pushstring(v,mathlib_funcs[i].name,-1);
- sq_newclosure(v,mathlib_funcs[i].f,0);
- sq_setparamscheck(v,mathlib_funcs[i].nparamscheck,mathlib_funcs[i].typemask);
- sq_setnativeclosurename(v,-1,mathlib_funcs[i].name);
- sq_newslot(v,-3,SQFalse);
- i++;
- }
- sq_pushstring(v,_SC("RAND_MAX"),-1);
- sq_pushinteger(v,RAND_MAX);
- sq_newslot(v,-3,SQFalse);
- sq_pushstring(v,_SC("PI"),-1);
- sq_pushfloat(v,(SQFloat)M_PI);
- sq_newslot(v,-3,SQFalse);
- sq_newslot(v,-3,SQTrue); //insert math
- return SQ_OK;
- }
|