/artichoke-backend/vendor/mruby/mrbgems/mruby-cmath/src/cmath.c

https://github.com/artichoke/Artichoke · C · 269 lines · 201 code · 41 blank · 27 comment · 30 complexity · 13fa31bcd1211f5e895f1ff78f1a5ea0 MD5 · raw file

  1. /*
  2. ** cmath.c - Math module with complex numbers
  3. **
  4. ** See Copyright Notice in mruby.h
  5. */
  6. /*
  7. ** This `mruby-cmath` gem uses C99 _Complex features
  8. ** You need C compiler that support C99+
  9. */
  10. #include <mruby.h>
  11. #ifdef MRB_NO_FLOAT
  12. # error CMath conflicts with 'MRB_NO_FLOAT' configuration
  13. #endif
  14. #include <complex.h>
  15. mrb_value mrb_complex_new(mrb_state *mrb, mrb_float real, mrb_float imag);
  16. void mrb_complex_get(mrb_state *mrb, mrb_value cpx, mrb_float*, mrb_float*);
  17. static mrb_bool
  18. cmath_get_complex(mrb_state *mrb, mrb_value c, mrb_float *r, mrb_float *i)
  19. {
  20. if (mrb_integer_p(c)) {
  21. *r = (mrb_float)mrb_integer(c);
  22. *i = 0;
  23. return FALSE;
  24. }
  25. else if (mrb_float_p(c)) {
  26. *r = mrb_float(c);
  27. *i = 0;
  28. return FALSE;
  29. }
  30. else if (mrb_obj_is_kind_of(mrb, c, mrb_class_get(mrb, "Complex"))) {
  31. mrb_complex_get(mrb, c, r, i);
  32. return TRUE;
  33. }
  34. else {
  35. mrb_raise(mrb, E_TYPE_ERROR, "Numeric required");
  36. return FALSE;
  37. }
  38. }
  39. #ifdef MRB_USE_FLOAT32
  40. #define F(x) x##f
  41. #else
  42. #define F(x) x
  43. #endif
  44. #if defined(_WIN32) && !defined(__MINGW32__)
  45. #ifdef MRB_USE_FLOAT32
  46. typedef _Fcomplex mrb_complex;
  47. #define CX(r,i) _FCbuild(r,i)
  48. #else
  49. typedef _Dcomplex mrb_complex;
  50. #define CX(r,i) _Cbuild(r,i)
  51. #endif
  52. static mrb_complex
  53. CXDIVf(mrb_complex x, mrb_float y)
  54. {
  55. return CX(creal(x)/y, cimag(x)/y);
  56. }
  57. static mrb_complex
  58. CXDIVc(mrb_complex a, mrb_complex b)
  59. {
  60. mrb_float ratio, den;
  61. mrb_float abr, abi, cr, ci;
  62. if ((abr = creal(b)) < 0)
  63. abr = - abr;
  64. if ((abi = cimag(b)) < 0)
  65. abi = - abi;
  66. if (abr <= abi) {
  67. ratio = creal(b) / cimag(b) ;
  68. den = cimag(a) * (1 + ratio*ratio);
  69. cr = (creal(a)*ratio + cimag(a)) / den;
  70. ci = (cimag(a)*ratio - creal(a)) / den;
  71. }
  72. else {
  73. ratio = cimag(b) / creal(b) ;
  74. den = creal(a) * (1 + ratio*ratio);
  75. cr = (creal(a) + cimag(a)*ratio) / den;
  76. ci = (cimag(a) - creal(a)*ratio) / den;
  77. }
  78. return CX(cr, ci);
  79. }
  80. #else
  81. #if defined(__cplusplus) && (defined(__APPLE__) || (defined(__clang__) && (defined(__FreeBSD__) || defined(__OpenBSD__))))
  82. #ifdef MRB_USE_FLOAT32
  83. typedef std::complex<float> mrb_complex;
  84. #else
  85. typedef std::complex<double> mrb_complex;
  86. #endif /* MRB_USE_FLOAT32 */
  87. #define CX(r,i) mrb_complex(r,i)
  88. #define creal(c) c.real()
  89. #define cimag(c) c.imag()
  90. #define FC(n) F(n)
  91. #else /* cpp */
  92. #ifdef MRB_USE_FLOAT32
  93. typedef float _Complex mrb_complex;
  94. #else
  95. typedef double _Complex mrb_complex;
  96. #endif /* MRB_USE_FLOAT32 */
  97. #define CX(r,i) ((r)+(i)*_Complex_I)
  98. #endif
  99. #define CXDIVf(x,y) (x)/(y)
  100. #define CXDIVc(x,y) (x)/(y)
  101. #endif
  102. #ifndef FC
  103. #define FC(n) F(c ## n)
  104. #endif
  105. #define DEF_CMATH_METHOD(name) \
  106. static mrb_value \
  107. cmath_ ## name(mrb_state *mrb, mrb_value self)\
  108. {\
  109. mrb_value z = mrb_get_arg1(mrb);\
  110. mrb_float real, imag;\
  111. if (cmath_get_complex(mrb, z, &real, &imag)) {\
  112. mrb_complex c = CX(real,imag);\
  113. c = FC(name)(c);\
  114. return mrb_complex_new(mrb, creal(c), cimag(c));\
  115. }\
  116. return mrb_float_value(mrb, F(name)(real));\
  117. }
  118. /* exp(z): return the exponential of z */
  119. DEF_CMATH_METHOD(exp)
  120. /* log(z): return the natural logarithm of z, with branch cut along the negative real axis */
  121. static mrb_value
  122. cmath_log(mrb_state *mrb, mrb_value self) {
  123. mrb_value z;
  124. mrb_float base;
  125. mrb_float real, imag;
  126. mrb_int n = mrb_get_args(mrb, "o|f", &z, &base);
  127. #ifndef M_E
  128. #define M_E F(exp)(1.0)
  129. #endif
  130. if (n == 1) base = M_E;
  131. if (cmath_get_complex(mrb, z, &real, &imag) || real < 0.0) {
  132. mrb_complex c = CX(real,imag);
  133. c = FC(log)(c);
  134. if (n == 2) c = CXDIVc(c, FC(log)(CX(base,0)));
  135. return mrb_complex_new(mrb, creal(c), cimag(c));
  136. }
  137. if (n == 1) return mrb_float_value(mrb, F(log)(real));
  138. return mrb_float_value(mrb, F(log)(real)/F(log)(base));
  139. }
  140. /* log10(z): return the base-10 logarithm of z, with branch cut along the negative real axis */
  141. static mrb_value
  142. cmath_log10(mrb_state *mrb, mrb_value self) {
  143. mrb_value z = mrb_get_arg1(mrb);
  144. mrb_float real, imag;
  145. if (cmath_get_complex(mrb, z, &real, &imag) || real < 0.0) {
  146. mrb_complex c = CX(real,imag);
  147. c = CXDIVf(FC(log)(c),log(10));
  148. return mrb_complex_new(mrb, creal(c), cimag(c));
  149. }
  150. return mrb_float_value(mrb, F(log10)(real));
  151. }
  152. /* log2(z): return the base-2 logarithm of z, with branch cut along the negative real axis */
  153. static mrb_value
  154. cmath_log2(mrb_state *mrb, mrb_value self) {
  155. mrb_value z = mrb_get_arg1(mrb);
  156. mrb_float real, imag;
  157. if (cmath_get_complex(mrb, z, &real, &imag) || real < 0.0) {
  158. mrb_complex c = CX(real,imag);
  159. c = CXDIVf(FC(log)(c),log(2.0));
  160. return mrb_complex_new(mrb, creal(c), cimag(c));
  161. }
  162. return mrb_float_value(mrb, F(log2)(real));
  163. }
  164. /* sqrt(z): return square root of z */
  165. static mrb_value
  166. cmath_sqrt(mrb_state *mrb, mrb_value self) {
  167. mrb_value z = mrb_get_arg1(mrb);
  168. mrb_float real, imag;
  169. if (cmath_get_complex(mrb, z, &real, &imag) || real < 0.0) {
  170. mrb_complex c = CX(real,imag);
  171. c = FC(sqrt)(c);
  172. return mrb_complex_new(mrb, creal(c), cimag(c));
  173. }
  174. return mrb_float_value(mrb, F(sqrt)(real));
  175. }
  176. /* sin(z): sine function */
  177. DEF_CMATH_METHOD(sin)
  178. /* cos(z): cosine function */
  179. DEF_CMATH_METHOD(cos)
  180. /* tan(z): tangent function */
  181. DEF_CMATH_METHOD(tan)
  182. /* asin(z): arc sine function */
  183. DEF_CMATH_METHOD(asin)
  184. /* acos(z): arc cosine function */
  185. DEF_CMATH_METHOD(acos)
  186. /* atan(z): arg tangent function */
  187. DEF_CMATH_METHOD(atan)
  188. /* sinh(z): hyperbolic sine function */
  189. DEF_CMATH_METHOD(sinh)
  190. /* cosh(z): hyperbolic cosine function */
  191. DEF_CMATH_METHOD(cosh)
  192. /* tanh(z): hyperbolic tangent function */
  193. DEF_CMATH_METHOD(tanh)
  194. /* asinh(z): inverse hyperbolic sine function */
  195. DEF_CMATH_METHOD(asinh)
  196. /* acosh(z): inverse hyperbolic cosine function */
  197. DEF_CMATH_METHOD(acosh)
  198. /* atanh(z): inverse hyperbolic tangent function */
  199. DEF_CMATH_METHOD(atanh)
  200. /* ------------------------------------------------------------------------*/
  201. void
  202. mrb_mruby_cmath_gem_init(mrb_state* mrb)
  203. {
  204. struct RClass *cmath;
  205. cmath = mrb_define_module(mrb, "CMath");
  206. mrb_include_module(mrb, cmath, mrb_module_get(mrb, "Math"));
  207. mrb_define_module_function(mrb, cmath, "sin", cmath_sin, MRB_ARGS_REQ(1));
  208. mrb_define_module_function(mrb, cmath, "cos", cmath_cos, MRB_ARGS_REQ(1));
  209. mrb_define_module_function(mrb, cmath, "tan", cmath_tan, MRB_ARGS_REQ(1));
  210. mrb_define_module_function(mrb, cmath, "asin", cmath_asin, MRB_ARGS_REQ(1));
  211. mrb_define_module_function(mrb, cmath, "acos", cmath_acos, MRB_ARGS_REQ(1));
  212. mrb_define_module_function(mrb, cmath, "atan", cmath_atan, MRB_ARGS_REQ(1));
  213. mrb_define_module_function(mrb, cmath, "sinh", cmath_sinh, MRB_ARGS_REQ(1));
  214. mrb_define_module_function(mrb, cmath, "cosh", cmath_cosh, MRB_ARGS_REQ(1));
  215. mrb_define_module_function(mrb, cmath, "tanh", cmath_tanh, MRB_ARGS_REQ(1));
  216. mrb_define_module_function(mrb, cmath, "asinh", cmath_asinh, MRB_ARGS_REQ(1));
  217. mrb_define_module_function(mrb, cmath, "acosh", cmath_acosh, MRB_ARGS_REQ(1));
  218. mrb_define_module_function(mrb, cmath, "atanh", cmath_atanh, MRB_ARGS_REQ(1));
  219. mrb_define_module_function(mrb, cmath, "exp", cmath_exp, MRB_ARGS_REQ(1));
  220. mrb_define_module_function(mrb, cmath, "log", cmath_log, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
  221. mrb_define_module_function(mrb, cmath, "log2", cmath_log2, MRB_ARGS_REQ(1));
  222. mrb_define_module_function(mrb, cmath, "log10", cmath_log10, MRB_ARGS_REQ(1));
  223. mrb_define_module_function(mrb, cmath, "sqrt", cmath_sqrt, MRB_ARGS_REQ(1));
  224. }
  225. void
  226. mrb_mruby_cmath_gem_final(mrb_state* mrb)
  227. {
  228. }