mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user