diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2021-02-05 22:27:27 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2021-02-05 22:27:27 +0900 |
| commit | a0050541d1a4743721f805a71abfd9c898877fc7 (patch) | |
| tree | e2b244d86718e0608675619c12caa091b99fc2d7 /mrbgems/mruby-cmath/src | |
| parent | d898002096ca20471a657a69ca25aec5e25cf6f0 (diff) | |
| download | mruby-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.c | 193 |
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) +{ +} |
