sqstdmath.cpp 11 KB

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