sqstdmath.cpp 11 KB

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