|
|
@@ -38,8 +38,8 @@ static SQInteger math_abs(HSQUIRRELVM v)
|
|
|
{
|
|
|
SQInteger n;
|
|
|
sq_getinteger(v,2,&n);
|
|
|
- sq_pushinteger(v,(SQInteger)abs((int)n));
|
|
|
- return 1;
|
|
|
+ sq_pushinteger(v,(SQInteger)abs((int)n));
|
|
|
+ return 1;
|
|
|
}
|
|
|
|
|
|
SINGLE_ARG_FUNC(sqrt)
|
|
|
@@ -57,6 +57,228 @@ TWO_ARGS_FUNC(pow)
|
|
|
SINGLE_ARG_FUNC(floor)
|
|
|
SINGLE_ARG_FUNC(ceil)
|
|
|
SINGLE_ARG_FUNC(exp)
|
|
|
+
|
|
|
+//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, "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, "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 char math_number_format_dec_point[2] = ".";
|
|
|
+static char math_number_format_thousand_sep[2] = ",";
|
|
|
+
|
|
|
+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] = '\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, 4, thousand_sep, math_number_format_thousand_sep);
|
|
|
+ char tmpbuf[64], resbuf[64];
|
|
|
+ char *s, *t; /* source, target */
|
|
|
+ char *dp;
|
|
|
+ int integral;
|
|
|
+ int 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ tmplen = scsnprintf(tmpbuf, sizeof(tmpbuf), "%.*f", dec, d);
|
|
|
+
|
|
|
+ resbuf[0] = '\0';
|
|
|
+
|
|
|
+ if (isdigit((int)tmpbuf[0])) {
|
|
|
+
|
|
|
+ /* find decimal point, if expected */
|
|
|
+ if (dec) {
|
|
|
+ dp = strpbrk(tmpbuf, ".,");
|
|
|
+ } 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 SQRegFunction mathlib_funcs[] = {
|
|
|
@@ -78,6 +300,13 @@ static SQRegFunction mathlib_funcs[] = {
|
|
|
_DECL_FUNC(rand,1,NULL),
|
|
|
_DECL_FUNC(fabs,2,_SC(".n")),
|
|
|
_DECL_FUNC(abs,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")),
|
|
|
{0,0},
|
|
|
};
|
|
|
#undef _DECL_FUNC
|
|
|
@@ -88,6 +317,9 @@ static SQRegFunction mathlib_funcs[] = {
|
|
|
|
|
|
SQRESULT sqstd_register_mathlib(HSQUIRRELVM v)
|
|
|
{
|
|
|
+ sq_pushstring(v,_SC("math"),-1);
|
|
|
+ sq_newclass(v,SQFalse);
|
|
|
+
|
|
|
SQInteger i=0;
|
|
|
while(mathlib_funcs[i].name!=0) {
|
|
|
sq_pushstring(v,mathlib_funcs[i].name,-1);
|
|
|
@@ -103,5 +335,7 @@ SQRESULT sqstd_register_mathlib(HSQUIRRELVM v)
|
|
|
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;
|
|
|
}
|