/fluffos/packages/math.c

https://github.com/quixadhal/bloodlines · C · 380 lines · 304 code · 56 blank · 20 comment · 67 complexity · 484385387919e17769d78db87282276b MD5 · raw file

  1. /*
  2. math.c: this file contains the math efunctions called from
  3. inside eval_instruction() in interpret.c.
  4. -- coded by Truilkan 93/02/21
  5. Added norm, dotprod, distance, angle, log2.
  6. Also added round() which works on floats. If you do work with floats,
  7. you'll discover it's actually more useful than you'd think.
  8. Added int args to the efuns as apppropriate.
  9. - Hamlet 20090516
  10. */
  11. #include <math.h>
  12. #include <limits.h>
  13. #ifdef LATTICE
  14. #include "/lpc_incl.h"
  15. #else
  16. #include "../lpc_incl.h"
  17. #include "../efun_protos.h"
  18. #endif
  19. #define SQUARE(n) ((n)*(n))
  20. #ifdef F_COS
  21. void
  22. f_cos (void)
  23. {
  24. sp->u.real = cos(sp->u.real);
  25. }
  26. #endif
  27. #ifdef F_SIN
  28. void
  29. f_sin (void)
  30. {
  31. sp->u.real = sin(sp->u.real);
  32. }
  33. #endif
  34. #ifdef F_TAN
  35. void
  36. f_tan (void)
  37. {
  38. /*
  39. * maybe should try to check that tan won't blow up (x != (Pi/2 + N*Pi))
  40. */
  41. sp->u.real = tan(sp->u.real);
  42. }
  43. #endif
  44. #ifdef F_ASIN
  45. void
  46. f_asin (void)
  47. {
  48. if (sp->u.real < -1.0) {
  49. error("math: asin(x) with (x < -1.0)\n");
  50. return;
  51. } else if (sp->u.real > 1.0) {
  52. error("math: asin(x) with (x > 1.0)\n");
  53. return;
  54. }
  55. sp->u.real = asin(sp->u.real);
  56. }
  57. #endif
  58. #ifdef F_ACOS
  59. void
  60. f_acos (void)
  61. {
  62. if (sp->u.real < -1.0) {
  63. error("math: acos(x) with (x < -1.0)\n");
  64. return;
  65. } else if (sp->u.real > 1.0) {
  66. error("math: acos(x) with (x > 1.0)\n");
  67. return;
  68. }
  69. sp->u.real = acos(sp->u.real);
  70. }
  71. #endif
  72. #ifdef F_ATAN
  73. void
  74. f_atan (void)
  75. {
  76. sp->u.real = atan(sp->u.real);
  77. }
  78. #endif
  79. #ifdef F_SQRT
  80. void
  81. f_sqrt (void)
  82. { float val;
  83. if(sp->type == T_NUMBER)
  84. val = (float) sp->u.number;
  85. else
  86. val = sp->u.real;
  87. if (val < 0.0) {
  88. error("math: sqrt(x) with (x < 0.0)\n");
  89. return;
  90. }
  91. sp->u.real = (float) sqrt(val);
  92. sp->type = T_REAL;
  93. }
  94. #endif
  95. #ifdef F_LOG
  96. void
  97. f_log (void)
  98. {
  99. if (sp->u.real <= 0.0) {
  100. error("math: log(x) with (x <= 0.0)\n");
  101. return;
  102. }
  103. sp->u.real = log(sp->u.real);
  104. }
  105. #endif
  106. #ifdef F_LOG10
  107. void
  108. f_log10 (void)
  109. {
  110. float val;
  111. if(sp->type == T_NUMBER)
  112. val = (float) sp->u.number;
  113. else
  114. val = sp->u.real;
  115. if (val <= 0.0) {
  116. error("math: log10(x) with (x <= 0.0)\n");
  117. return;
  118. }
  119. sp->u.real = log10(val);
  120. sp->type = T_REAL;
  121. }
  122. #endif
  123. #ifdef F_LOG2
  124. void
  125. f_log2 (void)
  126. {
  127. float val;
  128. if(sp->type == T_NUMBER)
  129. val = (float) sp->u.number;
  130. else
  131. val = sp->u.real;
  132. if (val <= 0.0) {
  133. error("math: log2(x) with (x <= 0.0)\n");
  134. return;
  135. }
  136. sp->u.real = (float) log2((double)val);
  137. sp->type = T_REAL;
  138. }
  139. #endif
  140. #ifdef F_POW
  141. void
  142. f_pow (void)
  143. {
  144. float val, val2;
  145. if((sp-1)->type == T_NUMBER)
  146. val = (float) (sp-1)->u.number;
  147. else
  148. val = (sp-1)->u.real;
  149. if(sp->type == T_NUMBER)
  150. val2 = (float) sp->u.number;
  151. else
  152. val2 = sp->u.real;
  153. (sp - 1)->u.real = pow(val, val2);
  154. sp--;
  155. sp->type = T_REAL;
  156. }
  157. #endif
  158. #ifdef F_EXP
  159. void
  160. f_exp (void)
  161. {
  162. sp->u.real = exp(sp->u.real);
  163. }
  164. #endif
  165. #ifdef F_FLOOR
  166. void
  167. f_floor (void)
  168. {
  169. sp->u.real = floor(sp->u.real);
  170. }
  171. #endif
  172. #ifdef F_CEIL
  173. void
  174. f_ceil (void)
  175. {
  176. sp->u.real = ceil(sp->u.real);
  177. }
  178. #endif
  179. #ifdef F_ROUND
  180. void f_round (void)
  181. {
  182. sp->u.real = (float) round(sp->u.real);
  183. }
  184. #endif
  185. #ifdef F_NORM
  186. /* The norm (magnitude) of a vector.
  187. Yes, you could use dotprod() below to implement norm(), but in the interest
  188. of speed, norm() has less cases.
  189. */
  190. static float norm(array_t *a) {
  191. int len = sp->u.arr->size;
  192. float total = 0.0;
  193. while(len-- > 0)
  194. if(a->item[len].type == T_NUMBER)
  195. total += SQUARE((float) a->item[len].u.number);
  196. else if(a->item[len].type == T_REAL)
  197. total += SQUARE(a->item[len].u.real);
  198. else {
  199. return -INT_MAX + 1;
  200. }
  201. return (float) sqrt(total);
  202. }
  203. void f_norm(void) {
  204. float val = norm(sp->u.arr);
  205. if(val == (-INT_MAX + 1)) {
  206. pop_stack();
  207. error("norm: invalid argument 1.\n");
  208. return;
  209. }
  210. pop_stack();
  211. push_real(val);
  212. }
  213. #endif
  214. #if defined(F_DOTPROD) | defined(F_DISTANCE) | defined(F_ANGLE)
  215. static float vector_op(array_t *a, array_t *b,
  216. float (*func)(const float, const float)) {
  217. int len = a->size;
  218. float total = 0.0;
  219. if(b->size != len) {
  220. return -INT_MAX;
  221. }
  222. while(len-- > 0) {
  223. if(b->item[len].type == T_NUMBER) {
  224. if(a->item[len].type == T_NUMBER)
  225. total += func((float) a->item[len].u.number,
  226. (float) b->item[len].u.number);
  227. else if(a->item[len].type == T_REAL)
  228. total += func(a->item[len].u.real,
  229. (float) b->item[len].u.number);
  230. else {
  231. return -INT_MAX + 1;
  232. }
  233. }
  234. else if(b->item[len].type == T_REAL) {
  235. if(a->item[len].type == T_NUMBER)
  236. total += func((float) a->item[len].u.number,
  237. b->item[len].u.real);
  238. else if(a->item[len].type == T_REAL)
  239. total += func(a->item[len].u.real, b->item[len].u.real);
  240. else {
  241. return -INT_MAX + 1;
  242. }
  243. }
  244. else {
  245. return -INT_MAX + 2;
  246. }
  247. }
  248. return total;
  249. }
  250. #endif
  251. #ifdef F_DOTPROD
  252. static float dotprod_mult(const float a, const float b) {
  253. return a * b;
  254. }
  255. /* dot product of two vectors */
  256. static float dotprod(array_t *a, array_t *b) {
  257. return vector_op(a, b, dotprod_mult);
  258. }
  259. void f_dotprod(void) {
  260. float total = vector_op((sp-1)->u.arr, sp->u.arr, dotprod_mult);
  261. if(total == -INT_MAX) {
  262. pop_2_elems();
  263. error("dotprod: cannot take the dotprod of vectors of different sizes.\n");
  264. return;
  265. }
  266. if((total == (-INT_MAX + 1)) || (total == (-INT_MAX + 2))) {
  267. pop_2_elems();
  268. error("dotprod: invalid arg %d.\n", (total + INT_MAX));
  269. return;
  270. }
  271. pop_2_elems();
  272. push_real(total);
  273. }
  274. #endif
  275. #ifdef F_DISTANCE
  276. static float distance_mult(const float a, const float b) {
  277. return SQUARE(b - a);
  278. }
  279. /* The (Euclidian) distance between two points */
  280. void f_distance(void) {
  281. float total = vector_op((sp-1)->u.arr, sp->u.arr, distance_mult);
  282. if(total == -INT_MAX) {
  283. pop_2_elems();
  284. error("distance: cannot take the distance of vectors of different sizes.\n");
  285. return;
  286. }
  287. if((total == (-INT_MAX + 1)) || (total == (-INT_MAX + 2))) {
  288. pop_2_elems();
  289. error("distance: invalid arg %d.\n", (total + INT_MAX));
  290. return;
  291. }
  292. pop_2_elems();
  293. push_real((float)sqrt(total));
  294. }
  295. #endif
  296. #ifdef F_ANGLE
  297. void f_angle(void) {
  298. float dot, norma, normb;
  299. dot = dotprod((sp-1)->u.arr, sp->u.arr);
  300. if(dot <= (-INT_MAX + 2)) {
  301. pop_2_elems();
  302. if(dot == -INT_MAX)
  303. error("angle: cannot calculate the angle between vectors of different sizes.\n");
  304. else
  305. error("angle: invalid arg %d.\n", (dot + INT_MAX));
  306. return;
  307. }
  308. norma = norm((sp-1)->u.arr);
  309. if(norma <= (-INT_MAX + 1)) {
  310. pop_2_elems();
  311. error("angle: invalid argument 1.\n");
  312. return;
  313. }
  314. normb = norm(sp->u.arr);
  315. if(normb <= (-INT_MAX + 1)) {
  316. pop_2_elems();
  317. error("angle: invalid argument 2.\n");
  318. return;
  319. }
  320. pop_2_elems();
  321. push_real((float)acos( dot / (norma * normb) ));
  322. }
  323. #endif