complex.c: overhaul complex operators.

- define `MRB_TT_COMPLEX`
- change object structure (`struct RComplex`)
- add memory management for `MRB_TT_COMPLEX`
- avoid operator overloading as much as possible
- as a result, performance improved a log
- should work with and without `Rational` defined
This commit is contained in:
Yukihiro "Matz" Matsumoto
2021-03-19 10:30:16 +09:00
parent 08f9d5bab5
commit d3184e4a6d
5 changed files with 171 additions and 105 deletions
+1 -1
View File
@@ -2,6 +2,6 @@ MRuby::Gem::Specification.new('mruby-complex') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
spec.summary = 'Complex class'
spec.build.cc.defines << "MRB_USE_COMPLEX"
spec.add_dependency 'mruby-math', core: 'mruby-math'
end
+1 -16
View File
@@ -81,7 +81,7 @@ class Complex < Numeric
alias_method :conj, :conjugate
def fdiv(numeric)
Complex(real.to_f / numeric, imaginary.to_f / numeric)
Complex(real / numeric, imaginary / numeric)
end
def polar
@@ -108,21 +108,6 @@ class Complex < Numeric
alias_method :imag, :imaginary
[Integer, Float].each do |cls|
cls.class_eval do
[:+, :-, :*, :/, :==].each do |op|
original_operator_name = :"__original_operator_#{op}_complex"
alias_method original_operator_name, op
define_method op do |rhs|
if rhs.is_a? Complex
Complex(self).__send__(op, rhs)
else
__send__(original_operator_name, rhs)
end
end
end
end
end
Numeric.class_eval do
def i
Complex(0, self)
+87 -46
View File
@@ -8,65 +8,59 @@
# error Complex conflicts with 'MRB_NO_FLOAT' configuration
#endif
struct mrb_complex {
mrb_float real;
mrb_float imaginary;
};
#ifdef MRB_USE_FLOAT32
#define F(x) x##f
#else
#define F(x) x
#endif
#if defined(MRB_64BIT) || defined(MRB_USE_FLOAT32)
struct mrb_complex {
mrb_float real;
mrb_float imaginary;
};
#define COMPLEX_USE_ISTRUCT
/* use TT_ISTRUCT */
#include <mruby/istruct.h>
#define complex_ptr(mrb, v) (struct mrb_complex*)mrb_istruct_ptr(v)
#if defined(MRB_32BIT) && !defined(MRB_USE_FLOAT32)
static struct RBasic*
complex_alloc(mrb_state *mrb, struct RClass *c, struct mrb_complex **p)
{
struct RIStruct *s;
s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c);
*p = (struct mrb_complex*)s->inline_data;
return (struct RBasic*)s;
}
#else
/* use TT_DATA */
#include <mruby/data.h>
static const struct mrb_data_type mrb_complex_type = {"Complex", mrb_free};
static struct RBasic*
complex_alloc(mrb_state *mrb, struct RClass *c, struct mrb_complex **p)
{
struct RData *d;
Data_Make_Struct(mrb, c, struct mrb_complex, &mrb_complex_type, *p, d);
return (struct RBasic*)d;
}
struct RComplex {
MRB_OBJECT_HEADER;
struct mrb_complex *p;
};
static struct mrb_complex*
complex_ptr(mrb_state *mrb, mrb_value v)
{
struct mrb_complex *p;
struct RComplex *r = (struct RComplex*)mrb_obj_ptr(v);
p = DATA_GET_PTR(mrb, v, &mrb_complex_type, struct mrb_complex);
if (!p) {
if (!r->p) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized complex");
}
return p;
return r->p;
}
#else
#define COMPLEX_INLINE
struct RComplex {
MRB_OBJECT_HEADER;
struct mrb_complex r;
};
#define complex_ptr(mrb, v) (&((struct RComplex*)mrb_obj_ptr(v))->r)
#endif
static struct RBasic*
complex_alloc(mrb_state *mrb, struct RClass *c, struct mrb_complex **p)
{
struct RComplex *s;
s = (struct RComplex*)mrb_obj_alloc(mrb, MRB_TT_COMPLEX, c);
#ifdef COMPLEX_INLINE
*p = &s->r;
#else
*p = s->p = (struct mrb_complex*)mrb_malloc(mrb, sizeof(struct mrb_complex));
#endif
return (struct RBasic*)s;
}
void
mrb_complex_get(mrb_state *mrb, mrb_value cpx, mrb_float *r, mrb_float *i)
{
@@ -229,19 +223,62 @@ complex_div(mrb_state *mrb, mrb_value self)
return complex_new(mrb, F(ldexp)(zr.s, zr.x), F(ldexp)(zi.s, zi.x));
}
#ifndef MRB_USE_RATIONAL
mrb_int mrb_num_div_int(mrb_state *mrb, mrb_int x, mrb_int y);
/* 15.2.8.3.4 */
/*
* redefine Integer#/
*/
static mrb_value
int_div(mrb_state *mrb, mrb_value x)
{
mrb_value y = mrb_get_arg1(mrb);
mrb_int a = mrb_integer(x);
if (mrb_integer_p(y)) {
mrb_int div = mrb_num_div_int(mrb, a, mrb_integer(y));
return mrb_int_value(mrb, div);
}
switch (mrb_type(y)) {
case MRB_TT_COMPLEX:
return mrb_funcall_id(mrb, x, MRB_OPSYM(div), 1, y);
default:
return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y));
}
}
/* 15.2.9.3.19(x) */
/*
* redefine Integer#quo
*/
static mrb_value
int_quo(mrb_state *mrb, mrb_value x)
{
mrb_value y = mrb_get_arg1(mrb);
mrb_int a = mrb_integer(x);
switch (mrb_type(y)) {
case MRB_TT_COMPLEX:
return mrb_funcall_id(mrb, x, MRB_OPSYM(div), 1, y);
default:
return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y));
}
}
#endif
void mrb_mruby_complex_gem_init(mrb_state *mrb)
{
struct RClass *comp;
#ifdef COMPLEX_USE_ISTRUCT
mrb_assert(sizeof(struct mrb_complex) < ISTRUCT_DATA_SIZE);
#ifdef COMPLEX_INLINE
mrb_assert(sizeof(struct mrb_complex) < sizeof(void*)*3);
#endif
comp = mrb_define_class_id(mrb, MRB_SYM(Complex), mrb_class_get_id(mrb, MRB_SYM(Numeric)));
#ifdef COMPLEX_USE_ISTRUCT
MRB_SET_INSTANCE_TT(comp, MRB_TT_ISTRUCT);
#else
MRB_SET_INSTANCE_TT(comp, MRB_TT_DATA);
#endif
MRB_SET_INSTANCE_TT(comp, MRB_TT_COMPLEX);
mrb_undef_class_method(mrb, comp, "new");
mrb_define_class_method(mrb, comp, "rectangular", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
mrb_define_class_method(mrb, comp, "rect", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
@@ -252,6 +289,10 @@ void mrb_mruby_complex_gem_init(mrb_state *mrb)
mrb_define_method(mrb, comp, "to_i", complex_to_i, MRB_ARGS_NONE());
mrb_define_method(mrb, comp, "to_c", complex_to_c, MRB_ARGS_NONE());
mrb_define_method(mrb, comp, "__div__", complex_div, MRB_ARGS_REQ(1));
#ifndef MRB_USE_RATIONAL
mrb_define_method(mrb, mrb->integer_class, "/", int_div, MRB_ARGS_REQ(1)); /* overrride */
mrb_define_method(mrb, mrb->integer_class, "quo", int_quo, MRB_ARGS_REQ(1)); /* overrride */
#endif
}
void
+10 -3
View File
@@ -903,15 +903,22 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end)
}
break;
#if defined(MRB_INT64) && defined(MRB_32BIT)
#ifdef MRB_USE_RATIONAL
#if defined(MRB_USE_RATIONAL) && defined(MRB_INT64) && defined(MRB_32BIT)
case MRB_TT_RATIONAL:
{
struct RData *o = (struct RData*)obj;
mrb_free(mrb, obj->iv_tbl);
mrb_free(mrb, o->iv);
}
break;
#endif
#if defined(MRB_USE_COMPLEX) && defined(MRB_32BIT) && !defined(MRB_USE_FLOAT32)
case MRB_TT_COMPLEX:
{
struct RData *o = (struct RData*)obj;
mrb_free(mrb, o->iv);
}
break;
#endif
default:
+72 -39
View File
@@ -267,14 +267,18 @@ mrb_num_div_flo(mrb_state *mrb, mrb_float x, mrb_float y)
}
static mrb_value
flo_div(mrb_state *mrb, mrb_value xv)
flo_div(mrb_state *mrb, mrb_value x)
{
mrb_float x, y;
mrb_value y = mrb_get_arg1(mrb);
mrb_float a = mrb_float(x);
x = mrb_float(xv);
mrb_get_args(mrb, "f", &y);
x = mrb_num_div_flo(mrb, x, y);
return mrb_float_value(mrb, x);
if (mrb_float_p(y)) {
a = mrb_num_div_flo(mrb, a, mrb_float(y));
}
else {
a = mrb_num_div_flo(mrb, a, mrb_to_flo(mrb, y));
}
return mrb_float_value(mrb, a);
}
/* 15.2.9.3.16(x) */
@@ -348,6 +352,32 @@ flo_to_s(mrb_state *mrb, mrb_value flt)
return str;
}
/* 15.2.9.3.1 */
/*
* call-seq:
* float + other -> float
*
* Returns a new float which is the sum of <code>float</code>
* and <code>other</code>.
*/
static mrb_value
flo_add(mrb_state *mrb, mrb_value x)
{
mrb_value y = mrb_get_arg1(mrb);
mrb_float a = mrb_float(x);
switch (mrb_type(y)) {
case MRB_TT_FLOAT:
return mrb_float_value(mrb, a + mrb_float(y));
#if defined(MRB_USE_COMPLEX)
case MRB_TT_COMPLEX:
return mrb_funcall_id(mrb, y, MRB_OPSYM(add), 1, x);
#endif
default:
return mrb_float_value(mrb, a + mrb_to_flo(mrb, y));
}
}
/* 15.2.9.3.2 */
/*
* call-seq:
@@ -358,11 +388,22 @@ flo_to_s(mrb_state *mrb, mrb_value flt)
*/
static mrb_value
flo_minus(mrb_state *mrb, mrb_value x)
flo_sub(mrb_state *mrb, mrb_value x)
{
mrb_value y = mrb_get_arg1(mrb);
mrb_float a = mrb_float(x);
return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y));
switch (mrb_type(y)) {
case MRB_TT_FLOAT:
return mrb_float_value(mrb, a - mrb_float(y));
#if defined(MRB_USE_COMPLEX)
case MRB_TT_COMPLEX:
x = mrb_funcall_id(mrb, y, MRB_OPSYM(sub), 1, x);
return mrb_funcall_id(mrb, x, MRB_OPSYM(minus), 0);
#endif
default:
return mrb_float_value(mrb, a - mrb_to_flo(mrb, y));
}
}
/* 15.2.9.3.3 */
@@ -378,8 +419,18 @@ static mrb_value
flo_mul(mrb_state *mrb, mrb_value x)
{
mrb_value y = mrb_get_arg1(mrb);
mrb_float a = mrb_float(x);
return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y));
switch (mrb_type(y)) {
case MRB_TT_FLOAT:
return mrb_float_value(mrb, a * mrb_float(y));
#if defined(MRB_USE_COMPLEX)
case MRB_TT_COMPLEX:
return mrb_funcall_id(mrb, y, MRB_OPSYM(mul), 1, x);
#endif
default:
return mrb_float_value(mrb, a * mrb_to_flo(mrb, y));
}
}
static void
@@ -1328,7 +1379,7 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x)
#endif
static mrb_value
fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y)
int_plus(mrb_state *mrb, mrb_value x, mrb_value y)
{
mrb_int a;
@@ -1362,7 +1413,7 @@ MRB_API mrb_value
mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y)
{
if (mrb_integer_p(x)) {
return fixnum_plus(mrb, x, y);
return int_plus(mrb, x, y);
}
#ifndef MRB_NO_FLOAT
if (mrb_float_p(x)) {
@@ -1392,15 +1443,15 @@ mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y)
* result.
*/
static mrb_value
int_plus(mrb_state *mrb, mrb_value self)
int_add(mrb_state *mrb, mrb_value self)
{
mrb_value other = mrb_get_arg1(mrb);
return fixnum_plus(mrb, self, other);
return int_plus(mrb, self, other);
}
static mrb_value
fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y)
int_minus(mrb_state *mrb, mrb_value x, mrb_value y)
{
mrb_int a;
@@ -1434,7 +1485,7 @@ MRB_API mrb_value
mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y)
{
if (mrb_integer_p(x)) {
return fixnum_minus(mrb, x, y);
return int_minus(mrb, x, y);
}
#ifndef MRB_NO_FLOAT
if (mrb_float_p(x)) {
@@ -1465,11 +1516,11 @@ mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y)
* result.
*/
static mrb_value
int_minus(mrb_state *mrb, mrb_value self)
int_sub(mrb_state *mrb, mrb_value self)
{
mrb_value other = mrb_get_arg1(mrb);
return fixnum_minus(mrb, self, other);
return int_minus(mrb, self, other);
}
@@ -1685,24 +1736,6 @@ num_infinite_p(mrb_state *mrb, mrb_value self)
return mrb_false_value();
}
/* 15.2.9.3.1 */
/*
* call-seq:
* float + other -> float
*
* Returns a new float which is the sum of <code>float</code>
* and <code>other</code>.
*/
#ifndef MRB_NO_FLOAT
static mrb_value
flo_plus(mrb_state *mrb, mrb_value x)
{
mrb_value y = mrb_get_arg1(mrb);
return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y));
}
#endif
/* ------------------------------------------------------------------------*/
void
mrb_init_numeric(mrb_state *mrb)
@@ -1737,8 +1770,8 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, integer, "truncate", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.26 */
#endif
mrb_define_method(mrb, integer, "+", int_plus, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */
mrb_define_method(mrb, integer, "-", int_minus, MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */
mrb_define_method(mrb, integer, "+", int_add, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */
mrb_define_method(mrb, integer, "-", int_sub, MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */
mrb_define_method(mrb, integer, "*", int_mul, MRB_ARGS_REQ(1)); /* 15.2.8.3.3 */
mrb_define_method(mrb, integer, "%", int_mod, MRB_ARGS_REQ(1)); /* 15.2.8.3.5 */
mrb_define_method(mrb, integer, "/", int_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.6 */
@@ -1772,8 +1805,8 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, fl, "/", flo_div, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */
mrb_define_method(mrb, fl, "quo", flo_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */
mrb_define_method(mrb, fl, "div", flo_idiv, MRB_ARGS_REQ(1));
mrb_define_method(mrb, fl, "+", flo_plus, MRB_ARGS_REQ(1)); /* 15.2.9.3.3 */
mrb_define_method(mrb, fl, "-", flo_minus, MRB_ARGS_REQ(1)); /* 15.2.9.3.4 */
mrb_define_method(mrb, fl, "+", flo_add, MRB_ARGS_REQ(1)); /* 15.2.9.3.3 */
mrb_define_method(mrb, fl, "-", flo_sub, MRB_ARGS_REQ(1)); /* 15.2.9.3.4 */
mrb_define_method(mrb, fl, "*", flo_mul, MRB_ARGS_REQ(1)); /* 15.2.9.3.5 */
mrb_define_method(mrb, fl, "%", flo_mod, MRB_ARGS_REQ(1)); /* 15.2.9.3.7 */
mrb_define_method(mrb, fl, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.1 */