sqstdmath.cpp 8.2 KB

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