sqstdmath.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /* see copyright notice in squirrel.h */
  2. #include <squirrel.h>
  3. #include <math.h>
  4. #include <stdlib.h>
  5. #include <sqstdmath.h>
  6. #define SINGLE_ARG_FUNC(_funcname) static SQInteger math_##_funcname(HSQUIRRELVM v){ \
  7. SQFloat f; \
  8. sq_getfloat(v,2,&f); \
  9. sq_pushfloat(v,(SQFloat)_funcname(f)); \
  10. return 1; \
  11. }
  12. #define TWO_ARGS_FUNC(_funcname) static SQInteger math_##_funcname(HSQUIRRELVM v){ \
  13. SQFloat p1,p2; \
  14. sq_getfloat(v,2,&p1); \
  15. sq_getfloat(v,3,&p2); \
  16. sq_pushfloat(v,(SQFloat)_funcname(p1,p2)); \
  17. return 1; \
  18. }
  19. static SQInteger math_srand(HSQUIRRELVM v)
  20. {
  21. SQInteger i;
  22. if(SQ_FAILED(sq_getinteger(v,2,&i)))
  23. return sq_throwerror(v,_SC("invalid param"));
  24. srand((unsigned int)i);
  25. return 0;
  26. }
  27. static SQInteger math_rand(HSQUIRRELVM v)
  28. {
  29. sq_pushinteger(v,rand());
  30. return 1;
  31. }
  32. static int math_random(HSQUIRRELVM v) {
  33. SQ_FUNC_VARS(v);
  34. /* the `%' avoids the (rare) case of r==1, and is needed also because on
  35. some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
  36. SQFloat r = (SQFloat)(rand()%RAND_MAX) / (SQFloat)RAND_MAX;
  37. if (_top_==1) { /* no arguments: range [0,1) */
  38. sq_pushfloat(v, r);
  39. } else if (_top_<=3) { /* int range [1,u] or [l,u] */
  40. SQ_GET_INTEGER(v, 2, u);
  41. SQ_OPT_INTEGER(v, 3, l, 1);
  42. SQFloat d;
  43. if(l<=u) return sq_throwerror(v, _SC("interval is empty"));
  44. d= floor(r*(u-l+1));
  45. int tmp = d;
  46. sq_pushinteger(v, l+tmp);
  47. } else return sq_throwerror(v, _SC("wrong number of arguments"));
  48. return 1;
  49. }
  50. static SQInteger math_abs(HSQUIRRELVM v)
  51. {
  52. SQInteger n;
  53. sq_getinteger(v,2,&n);
  54. sq_pushinteger(v,(SQInteger)abs((int)n));
  55. return 1;
  56. }
  57. SINGLE_ARG_FUNC(sqrt)
  58. SINGLE_ARG_FUNC(fabs)
  59. SINGLE_ARG_FUNC(sin)
  60. SINGLE_ARG_FUNC(cos)
  61. SINGLE_ARG_FUNC(asin)
  62. SINGLE_ARG_FUNC(acos)
  63. SINGLE_ARG_FUNC(log)
  64. SINGLE_ARG_FUNC(log10)
  65. SINGLE_ARG_FUNC(tan)
  66. SINGLE_ARG_FUNC(atan)
  67. TWO_ARGS_FUNC(atan2)
  68. TWO_ARGS_FUNC(pow)
  69. SINGLE_ARG_FUNC(floor)
  70. SINGLE_ARG_FUNC(ceil)
  71. SINGLE_ARG_FUNC(exp)
  72. //DAD start
  73. #include <string.h>
  74. #include <stdio.h>
  75. #include <ctype.h>
  76. SQ_OPT_STRING_STRLEN();
  77. /* mathB_roundf: rounds real value x to the d-th digit; patched Dec 22, 2007 for negative values */
  78. static SQRESULT math_roundf (HSQUIRRELVM v) {
  79. SQ_FUNC_VARS(v);
  80. SQ_GET_FLOAT(v, 2, x);
  81. SQ_OPT_INTEGER(v, 3, dec_places, 0);
  82. SQFloat dec_factor;
  83. if( dec_places>15 || dec_places<0 ) return sq_throwerror(v, "decimal places out of range 0-15");
  84. switch(dec_places){
  85. case 0: dec_factor = 1.0; break;
  86. case 1: dec_factor = 10.0; break;
  87. case 2: dec_factor = 100.0; break;
  88. case 3: dec_factor = 1000.0; break;
  89. case 4: dec_factor = 10000.0; break;
  90. case 5: dec_factor = 100000.0; break;
  91. case 6: dec_factor = 1000000.0; break;
  92. default: dec_factor = pow((double)10.0, dec_places);
  93. }
  94. if (x < 0)
  95. sq_pushfloat(v, ceil(dec_factor*x-0.5) / dec_factor);
  96. else
  97. sq_pushfloat(v, floor(dec_factor*x+0.5) / dec_factor);
  98. return 1;
  99. }
  100. static SQRESULT math_broundf (HSQUIRRELVM v) {
  101. SQ_FUNC_VARS(v);
  102. SQ_GET_FLOAT(v, 2, num);
  103. SQ_OPT_INTEGER(v, 3, dec_places, 0);
  104. SQFloat dec_factor, tmp, itmp;
  105. int neg;
  106. if( dec_places>15 || dec_places<0 ) return sq_throwerror(v, "decimal places out of range 0-15");
  107. neg = num < 0;
  108. switch(dec_places){
  109. case 0: dec_factor = 1.0; break;
  110. case 1: dec_factor = 10.0; break;
  111. case 2: dec_factor = 100.0; break;
  112. case 3: dec_factor = 1000.0; break;
  113. case 4: dec_factor = 10000.0; break;
  114. case 5: dec_factor = 100000.0; break;
  115. case 6: dec_factor = 1000000.0; break;
  116. default: dec_factor = pow((double)10.0, dec_places);
  117. }
  118. tmp = num * dec_factor;
  119. itmp = floor(tmp + (neg ? -0.5 : 0.5));
  120. // Handle rounding of .5 in a special manner
  121. if(tmp - floor(tmp) == 0.5){
  122. tmp = itmp / 2;
  123. if(tmp != floor(tmp) ) { // Is itmp odd
  124. // Reduce Magnitude by 1 to make even
  125. if(neg) itmp++;
  126. else itmp--;
  127. }
  128. }
  129. sq_pushfloat(v, itmp / dec_factor);
  130. return 1;
  131. }
  132. static char math_number_format_dec_point[2] = ".";
  133. static char math_number_format_thousand_sep[2] = ",";
  134. static SQRESULT math_number_format_get_dec_point(HSQUIRRELVM v) {
  135. sq_pushstring(v, math_number_format_dec_point, -1);
  136. return 1;
  137. }
  138. static SQRESULT math_number_format_set_dec_point(HSQUIRRELVM v) {
  139. SQ_FUNC_VARS_NO_TOP(v);
  140. SQ_GET_STRING(v, 2, dec_point);
  141. math_number_format_dec_point[0] = *dec_point;
  142. math_number_format_dec_point[1] = '\0';
  143. return 0;
  144. }
  145. static SQRESULT math_number_format_get_thousand_sep(HSQUIRRELVM v) {
  146. sq_pushstring(v, math_number_format_thousand_sep, -1);
  147. return 1;
  148. }
  149. static SQRESULT math_number_format_set_thousand_sep(HSQUIRRELVM v) {
  150. SQ_FUNC_VARS_NO_TOP(v);
  151. SQ_GET_STRING(v, 2, thousand_sep);
  152. math_number_format_thousand_sep[0] = *thousand_sep;
  153. math_number_format_thousand_sep[1] = '\0';
  154. return 0;
  155. }
  156. static SQRESULT math_number_format(HSQUIRRELVM v) {
  157. SQ_FUNC_VARS(v);
  158. SQ_GET_FLOAT(v, 2, d);
  159. SQ_OPT_INTEGER(v, 3, dec, 2);
  160. SQ_OPT_STRING(v, 4, dec_point, math_number_format_dec_point);
  161. SQ_OPT_STRING(v, 5, thousand_sep, math_number_format_thousand_sep);
  162. char tmpbuf[64], resbuf[64];
  163. char *s, *t; /* source, target */
  164. char *dp;
  165. int integral;
  166. int tmplen, reslen=0;
  167. int count=0;
  168. int is_negative=0;
  169. int trim_right_zeros=0;
  170. if (d < 0) {
  171. is_negative = 1;
  172. d = -d;
  173. }
  174. if (dec < 0) {
  175. trim_right_zeros = 1;
  176. dec = -dec;
  177. }
  178. tmplen = scsnprintf(tmpbuf, sizeof(tmpbuf), "%.*f", dec, d);
  179. resbuf[0] = '\0';
  180. if (isdigit((int)tmpbuf[0])) {
  181. /* find decimal point, if expected */
  182. if (dec) {
  183. dp = strpbrk(tmpbuf, ".,");
  184. } else {
  185. dp = NULL;
  186. }
  187. /* calculate the length of the return buffer */
  188. if (dp) {
  189. integral = dp - tmpbuf;
  190. } else {
  191. /* no decimal point was found */
  192. integral = tmplen;
  193. }
  194. /* allow for thousand separators */
  195. if (*thousand_sep) {
  196. integral += (integral-1) / 3;
  197. }
  198. reslen = integral;
  199. if (dec) {
  200. reslen += dec;
  201. if (*dec_point) {
  202. reslen++;
  203. }
  204. }
  205. /* add a byte for minus sign */
  206. if (is_negative) {
  207. reslen++;
  208. }
  209. if(sizeof(resbuf) >= reslen+1) {
  210. s = tmpbuf+tmplen-1;
  211. t = resbuf+reslen;
  212. *t-- = '\0';
  213. /* copy the decimal places.
  214. * Take care, as the sprintf implementation may return less places than
  215. * we requested due to internal buffer limitations */
  216. if (dec) {
  217. int declen = dp ? s - dp : 0;
  218. int topad = dec > declen ? dec - declen : 0;
  219. /* pad with '0's */
  220. while (topad--) {
  221. *t-- = '0';
  222. }
  223. if (dp) {
  224. s -= declen + 1; /* +1 to skip the point */
  225. t -= declen;
  226. /* now copy the chars after the point */
  227. memcpy(t + 1, dp + 1, declen);
  228. }
  229. /* add decimal point */
  230. if (*dec_point) {
  231. *t-- = *dec_point;
  232. }
  233. }
  234. /* copy the numbers before the decimal point, adding thousand
  235. * separator every three digits */
  236. while(s >= tmpbuf) {
  237. *t-- = *s--;
  238. if (*thousand_sep && (++count%3)==0 && s>=tmpbuf) {
  239. *t-- = *thousand_sep;
  240. }
  241. }
  242. /* and a minus sign, if needed */
  243. if (is_negative) {
  244. *t-- = '-';
  245. }
  246. /* trim right zeros */
  247. if (*dec_point && trim_right_zeros) {
  248. for(t=resbuf+reslen-1; *t != *dec_point; t--){
  249. if (*t == '0') *t = '\0';
  250. else break;
  251. }
  252. if (*t == *dec_point) *t = '\0';
  253. }
  254. }
  255. }
  256. sq_pushstring(v, resbuf, -1);
  257. return 1;
  258. }
  259. //DAD end
  260. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),math_##name,nparams,tycheck}
  261. static SQRegFunction mathlib_funcs[] = {
  262. _DECL_FUNC(sqrt,2,_SC(".n")),
  263. _DECL_FUNC(sin,2,_SC(".n")),
  264. _DECL_FUNC(cos,2,_SC(".n")),
  265. _DECL_FUNC(asin,2,_SC(".n")),
  266. _DECL_FUNC(acos,2,_SC(".n")),
  267. _DECL_FUNC(log,2,_SC(".n")),
  268. _DECL_FUNC(log10,2,_SC(".n")),
  269. _DECL_FUNC(tan,2,_SC(".n")),
  270. _DECL_FUNC(atan,2,_SC(".n")),
  271. _DECL_FUNC(atan2,3,_SC(".nn")),
  272. _DECL_FUNC(pow,3,_SC(".nn")),
  273. _DECL_FUNC(floor,2,_SC(".n")),
  274. _DECL_FUNC(ceil,2,_SC(".n")),
  275. _DECL_FUNC(exp,2,_SC(".n")),
  276. _DECL_FUNC(srand,2,_SC(".n")),
  277. _DECL_FUNC(rand,1,NULL),
  278. _DECL_FUNC(random,-1,_SC(".ii")),
  279. _DECL_FUNC(fabs,2,_SC(".n")),
  280. _DECL_FUNC(abs,2,_SC(".n")),
  281. _DECL_FUNC(roundf,-2,_SC(".ni")),
  282. _DECL_FUNC(broundf,-2,_SC(".ni")),
  283. _DECL_FUNC(number_format,-2,_SC(".niss")),
  284. _DECL_FUNC(number_format_get_dec_point,1,_SC(".")),
  285. _DECL_FUNC(number_format_set_dec_point,2,_SC(".s")),
  286. _DECL_FUNC(number_format_get_thousand_sep,1,_SC(".")),
  287. _DECL_FUNC(number_format_set_thousand_sep,2,_SC(".s")),
  288. {0,0},
  289. };
  290. #undef _DECL_FUNC
  291. #ifndef M_PI
  292. #define M_PI (3.14159265358979323846)
  293. #endif
  294. SQRESULT sqstd_register_mathlib(HSQUIRRELVM v)
  295. {
  296. sq_pushstring(v,_SC("math"),-1);
  297. sq_newtable(v);
  298. SQInteger i=0;
  299. while(mathlib_funcs[i].name!=0) {
  300. sq_pushstring(v,mathlib_funcs[i].name,-1);
  301. sq_newclosure(v,mathlib_funcs[i].f,0);
  302. sq_setparamscheck(v,mathlib_funcs[i].nparamscheck,mathlib_funcs[i].typemask);
  303. sq_setnativeclosurename(v,-1,mathlib_funcs[i].name);
  304. sq_newslot(v,-3,SQFalse);
  305. i++;
  306. }
  307. sq_pushstring(v,_SC("RAND_MAX"),-1);
  308. sq_pushinteger(v,RAND_MAX);
  309. sq_newslot(v,-3,SQFalse);
  310. sq_pushstring(v,_SC("PI"),-1);
  311. sq_pushfloat(v,(SQFloat)M_PI);
  312. sq_newslot(v,-3,SQFalse);
  313. sq_newslot(v,-3,SQTrue); //insert math
  314. return SQ_OK;
  315. }