sqstdmath.cpp 13 KB

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