sqstdmath.cpp 9.3 KB

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