summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-cmath/src
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2021-02-05 22:27:27 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2021-02-05 22:27:27 +0900
commita0050541d1a4743721f805a71abfd9c898877fc7 (patch)
treee2b244d86718e0608675619c12caa091b99fc2d7 /mrbgems/mruby-cmath/src
parentd898002096ca20471a657a69ca25aec5e25cf6f0 (diff)
downloadmruby-a0050541d1a4743721f805a71abfd9c898877fc7.tar.gz
mruby-a0050541d1a4743721f805a71abfd9c898877fc7.zip
Add `mruby-cmath` gem to the core.
This gem uses C99 `_Complex` features. You need a C compiler that supports `_Complex` to enable this gem. All `gcc`, `clang`, `VC` support `_Complex` so there should not be a big problem.
Diffstat (limited to 'mrbgems/mruby-cmath/src')
-rw-r--r--mrbgems/mruby-cmath/src/cmath.c193
1 files changed, 193 insertions, 0 deletions
diff --git a/mrbgems/mruby-cmath/src/cmath.c b/mrbgems/mruby-cmath/src/cmath.c
new file mode 100644
index 000000000..e938c77b1
--- /dev/null
+++ b/mrbgems/mruby-cmath/src/cmath.c
@@ -0,0 +1,193 @@
+/*
+** cmath.c - Math module with complex numbers
+**
+** See Copyright Notice in mruby.h
+*/
+
+/*
+** This `mruby-cmath` gem uses C99 _Complex features
+** You need C compler that support C99+
+*/
+
+#include <mruby.h>
+
+#ifdef MRB_NO_FLOAT
+# error CMath conflicts with 'MRB_NO_FLOAT' configuration
+#endif
+
+#include <math.h>
+#include <complex.h>
+
+mrb_value mrb_complex_new(mrb_state *mrb, mrb_float real, mrb_float imag);
+void mrb_complex_get(mrb_state *mrb, mrb_value cpx, mrb_float*, mrb_float*);
+
+static mrb_bool
+cmath_get_complex(mrb_state *mrb, mrb_value c, mrb_float *r, mrb_float *i)
+{
+ if (mrb_integer_p(c)) {
+ *r = (mrb_float)mrb_integer(c);
+ *i = 0;
+ return FALSE;
+ }
+ else if (mrb_float_p(c)) {
+ *r = mrb_float(c);
+ *i = 0;
+ return FALSE;
+ }
+ else if (mrb_obj_is_kind_of(mrb, c, mrb_class_get(mrb, "Complex"))) {
+ mrb_complex_get(mrb, c, r, i);
+ return TRUE;
+ }
+ else {
+ mrb_raise(mrb, E_TYPE_ERROR, "Numeric required");
+ return FALSE;
+ }
+}
+
+#ifdef MRB_USE_FLOAT32
+typedef float complex mrb_complex;
+#define F(x) x##f
+#else
+typedef double complex mrb_complex;
+#define F(x) x
+#endif
+
+#define DEF_CMATH_METHOD(name) \
+static mrb_value \
+cmath_ ## name(mrb_state *mrb, mrb_value self)\
+{\
+ mrb_value z = mrb_get_arg1(mrb);\
+ mrb_float real, imag;\
+ if (cmath_get_complex(mrb, z, &real, &imag)) {\
+ mrb_complex c = real + imag*I;\
+ c = F(c ## name)(c);\
+ return mrb_complex_new(mrb, creal(c), cimag(c));\
+ }\
+ return mrb_float_value(mrb, F(name)(real));\
+}
+
+/* exp(z): return the exponential of z */
+DEF_CMATH_METHOD(exp)
+
+/* log(z): return the natural logarithm of z, with branch cut along the negative real axis */
+static mrb_value
+cmath_log(mrb_state *mrb, mrb_value self) {
+ mrb_value z;
+ mrb_float base;
+ mrb_float real, imag;
+
+ mrb_int n = mrb_get_args(mrb, "o|f", &z, &base);
+ if (n == 1) base = M_E;
+ if (cmath_get_complex(mrb, z, &real, &imag) || real < 0.0) {
+ mrb_complex c = real + imag*I;
+ c = F(clog)(c);
+ if (n == 2) {
+ c /= clog(base);
+ }
+ return mrb_complex_new(mrb, creal(c), cimag(c));
+ }
+ if (n == 1) return mrb_float_value(mrb, F(log)(real));
+ return mrb_float_value(mrb, F(log)(real)/F(log)(base));
+}
+
+/* log10(z): return the base-10 logarithm of z, with branch cut along the negative real axis */
+static mrb_value
+cmath_log10(mrb_state *mrb, mrb_value self) {
+ mrb_value z = mrb_get_arg1(mrb);
+ mrb_float real, imag;
+ if (cmath_get_complex(mrb, z, &real, &imag) || real < 0.0) {
+ mrb_complex c = real + imag*I;
+ c = F(clog)(c)/log(10);
+ return mrb_complex_new(mrb, creal(c), cimag(c));
+ }
+ return mrb_float_value(mrb, F(log10)(real));
+}
+
+/* log2(z): return the base-2 logarithm of z, with branch cut along the negative real axis */
+static mrb_value
+cmath_log2(mrb_state *mrb, mrb_value self) {
+ mrb_value z = mrb_get_arg1(mrb);
+ mrb_float real, imag;
+ if (cmath_get_complex(mrb, z, &real, &imag) || real < 0.0) {
+ mrb_complex c = real + imag*I;
+ c = F(clog)(c)/log(2);
+ return mrb_complex_new(mrb, creal(c), cimag(c));
+ }
+ return mrb_float_value(mrb, F(log2)(real));
+}
+
+/* sqrt(z): return square root of z */
+static mrb_value
+cmath_sqrt(mrb_state *mrb, mrb_value self) {
+ mrb_value z = mrb_get_arg1(mrb);
+ mrb_float real, imag;
+ if (cmath_get_complex(mrb, z, &real, &imag) || real < 0.0) {
+ mrb_complex c = real + imag*I;
+ c = F(csqrt)(c);
+ return mrb_complex_new(mrb, creal(c), cimag(c));
+ }
+ return mrb_float_value(mrb, F(sqrt)(real));
+}
+
+/* sin(z): sine function */
+DEF_CMATH_METHOD(sin)
+/* cos(z): cosine function */
+DEF_CMATH_METHOD(cos)
+/* tan(z): tangent function */
+DEF_CMATH_METHOD(tan)
+/* asin(z): arc sine function */
+DEF_CMATH_METHOD(asin)
+/* acos(z): arc cosine function */
+DEF_CMATH_METHOD(acos)
+/* atan(z): arg tangent function */
+DEF_CMATH_METHOD(atan)
+/* sinh(z): hyperbolic sine function */
+DEF_CMATH_METHOD(sinh)
+/* cosh(z): hyperbolic cosine function */
+DEF_CMATH_METHOD(cosh)
+/* tanh(z): hyperbolic tangent function */
+DEF_CMATH_METHOD(tanh)
+/* asinh(z): inverse hyperbolic sine function */
+DEF_CMATH_METHOD(asinh)
+/* acosh(z): inverse hyperbolic cosine function */
+DEF_CMATH_METHOD(acosh)
+/* atanh(z): inverse hyperbolic tangent function */
+DEF_CMATH_METHOD(atanh)
+
+/* ------------------------------------------------------------------------*/
+
+void
+mrb_mruby_cmath_gem_init(mrb_state* mrb)
+{
+ struct RClass *cmath;
+ cmath = mrb_define_module(mrb, "CMath");
+
+ mrb_include_module(mrb, cmath, mrb_module_get(mrb, "Math"));
+
+ mrb_define_module_function(mrb, cmath, "sin", cmath_sin, MRB_ARGS_REQ(1));
+ mrb_define_module_function(mrb, cmath, "cos", cmath_cos, MRB_ARGS_REQ(1));
+ mrb_define_module_function(mrb, cmath, "tan", cmath_tan, MRB_ARGS_REQ(1));
+
+ mrb_define_module_function(mrb, cmath, "asin", cmath_asin, MRB_ARGS_REQ(1));
+ mrb_define_module_function(mrb, cmath, "acos", cmath_acos, MRB_ARGS_REQ(1));
+ mrb_define_module_function(mrb, cmath, "atan", cmath_atan, MRB_ARGS_REQ(1));
+
+ mrb_define_module_function(mrb, cmath, "sinh", cmath_sinh, MRB_ARGS_REQ(1));
+ mrb_define_module_function(mrb, cmath, "cosh", cmath_cosh, MRB_ARGS_REQ(1));
+ mrb_define_module_function(mrb, cmath, "tanh", cmath_tanh, MRB_ARGS_REQ(1));
+
+ mrb_define_module_function(mrb, cmath, "asinh", cmath_asinh, MRB_ARGS_REQ(1));
+ mrb_define_module_function(mrb, cmath, "acosh", cmath_acosh, MRB_ARGS_REQ(1));
+ mrb_define_module_function(mrb, cmath, "atanh", cmath_atanh, MRB_ARGS_REQ(1));
+
+ mrb_define_module_function(mrb, cmath, "exp", cmath_exp, MRB_ARGS_REQ(1));
+ mrb_define_module_function(mrb, cmath, "log", cmath_log, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
+ mrb_define_module_function(mrb, cmath, "log2", cmath_log2, MRB_ARGS_REQ(1));
+ mrb_define_module_function(mrb, cmath, "log10", cmath_log10, MRB_ARGS_REQ(1));
+ mrb_define_module_function(mrb, cmath, "sqrt", cmath_sqrt, MRB_ARGS_REQ(1));
+}
+
+void
+mrb_mruby_cmath_gem_final(mrb_state* mrb)
+{
+}