sqstdmath.cpp 11 KB

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