2
0
Эх сурвалжийг харах

Added new functions and moved math to a table called math like in Lua to don't pollute the global namespace.
roundf rounds a float number to a specified number of decimals
broundf also rounds a float number to a specified number of decimals but using banker's round method
number_format formats a supplied number using a decimal and thousand separator, if not supplied it uses global values for it.
number_format_set_thousand_sep, number_format_get_thousand_sep, number_format_set_dec_point, number_format_get_dec_point get/set the default values used by number_format.

mingodad 13 жил өмнө
parent
commit
86e9e91820
1 өөрчлөгдсөн 236 нэмэгдсэн , 2 устгасан
  1. 236 2
      sqstdlib/sqstdmath.cpp

+ 236 - 2
sqstdlib/sqstdmath.cpp

@@ -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;
 }