diff --git a/ext/symengine/CMakeLists.txt b/ext/symengine/CMakeLists.txt index 5c85b3a..2fe3b65 100644 --- a/ext/symengine/CMakeLists.txt +++ b/ext/symengine/CMakeLists.txt @@ -1,11 +1,13 @@ set(RUBY_WRAPPER_SRC ruby_basic.c ruby_symbol.c + ruby_number.c ruby_integer.c ruby_real_double.c ruby_real_mpfr.c ruby_complex.c ruby_complex_double.c + ruby_complex_mpc.c ruby_constant.c ruby_function.c ruby_ntheory.c diff --git a/ext/symengine/ruby_complex_mpc.c b/ext/symengine/ruby_complex_mpc.c new file mode 100644 index 0000000..6ddfc98 --- /dev/null +++ b/ext/symengine/ruby_complex_mpc.c @@ -0,0 +1,13 @@ +#include "ruby_complex_mpc.h" + +#ifdef HAVE_SYMENGINE_MPC +VALUE ccomplex_mpc_real_part(VALUE self) +{ + return function_onearg(complex_mpc_real_part, self); +} + +VALUE ccomplex_mpc_imaginary_part(VALUE self) +{ + return function_onearg(complex_mpc_imaginary_part, self); +} +#endif // HAVE_SYMENGINE_MPC diff --git a/ext/symengine/ruby_complex_mpc.h b/ext/symengine/ruby_complex_mpc.h new file mode 100644 index 0000000..4f79b0d --- /dev/null +++ b/ext/symengine/ruby_complex_mpc.h @@ -0,0 +1,15 @@ +#ifndef RUBY_COMPLEX_MPC_H_ +#define RUBY_COMPLEX_MPC_H_ + +#include +#include + +#include "symengine.h" +#include "symengine_utils.h" + +#ifdef HAVE_SYMENGINE_MPC +VALUE ccomplex_mpc_real_part(VALUE self); +VALUE ccomplex_mpc_imaginary_part(VALUE self); +#endif // HAVE_SYMENGINE_MPC + +#endif // RUBY_COMPLEX_MPC_H_ diff --git a/ext/symengine/ruby_number.c b/ext/symengine/ruby_number.c new file mode 100644 index 0000000..e2912fa --- /dev/null +++ b/ext/symengine/ruby_number.c @@ -0,0 +1,50 @@ +#include "ruby_number.h" + +int cnumber_comp(VALUE self, VALUE operand2) +{ + basic cbasic_operand1; + basic cbasic_operand2; + basic_new_stack(cbasic_operand1); + basic_new_stack(cbasic_operand2); + + basic cbasic_sub; + basic_new_stack(cbasic_sub); + + sympify(self, cbasic_operand1); + sympify(operand2, cbasic_operand2); + + if (is_a_Number(cbasic_operand2) == 0) { + rb_raise(rb_eTypeError, "Expected SymEngine::Number found %s ", + rb_obj_classname(operand2)); + } + + basic_sub(cbasic_sub, cbasic_operand1, cbasic_operand2); + + int sign = basic_number_sign(cbasic_sub); + + basic_free_stack(cbasic_operand1); + basic_free_stack(cbasic_operand2); + basic_free_stack(cbasic_sub); + + return sign; +} + +VALUE cnumber_lt(VALUE self, VALUE operand2) +{ + return cnumber_comp(self, operand2) == -1 ? Qtrue : Qfalse; +} + +VALUE cnumber_gt(VALUE self, VALUE operand2) +{ + return cnumber_comp(self, operand2) == 1 ? Qtrue : Qfalse; +} + +VALUE cnumber_lt_e(VALUE self, VALUE operand2) +{ + return cnumber_comp(self, operand2) == 1 ? Qfalse : Qtrue; +} + +VALUE cnumber_gt_e(VALUE self, VALUE operand2) +{ + return cnumber_comp(self, operand2) == -1 ? Qfalse : Qtrue; +} diff --git a/ext/symengine/ruby_number.h b/ext/symengine/ruby_number.h new file mode 100644 index 0000000..7777b93 --- /dev/null +++ b/ext/symengine/ruby_number.h @@ -0,0 +1,19 @@ +#ifndef RUBY_NUMBER_H_ +#define RUBY_NUMBER_H_ + +#include +#include + +#include "symengine_utils.h" + +int cnumber_comp(VALUE self, VALUE operand2); + +VALUE cnumber_lt(VALUE self, VALUE operand2); + +VALUE cnumber_gt(VALUE self, VALUE operand2); + +VALUE cnumber_lt_e(VALUE self, VALUE operand2); + +VALUE cnumber_gt_e(VALUE self, VALUE operand2); + +#endif // RUBY_NUMBER_H_ diff --git a/ext/symengine/ruby_utils.c b/ext/symengine/ruby_utils.c index 24ec50d..9973eb1 100644 --- a/ext/symengine/ruby_utils.c +++ b/ext/symengine/ruby_utils.c @@ -14,3 +14,18 @@ VALUE cutils_sympify(VALUE self, VALUE operand) return result; } + +VALUE cutils_evalf(VALUE self, VALUE operand, VALUE prec, VALUE real) +{ + VALUE result; + + basic_struct *cresult; + cresult = basic_new_heap(); + + sympify(operand, cresult); + basic_evalf(cresult, cresult, NUM2INT(prec), (real == Qtrue ? 1 : 0)); + result = Data_Wrap_Struct(Klass_of_Basic(cresult), NULL, cbasic_free_heap, + cresult); + + return result; +} diff --git a/ext/symengine/ruby_utils.h b/ext/symengine/ruby_utils.h index de004ff..65edbf2 100644 --- a/ext/symengine/ruby_utils.h +++ b/ext/symengine/ruby_utils.h @@ -5,5 +5,5 @@ // Returns the Ruby Value after going through sympify VALUE cutils_sympify(VALUE self, VALUE operand); - +VALUE cutils_evalf(VALUE self, VALUE operand, VALUE prec, VALUE real); #endif // RUBY_UTILS_H_ diff --git a/ext/symengine/symengine.c b/ext/symengine/symengine.c index 98908f7..11af6a9 100644 --- a/ext/symengine/symengine.c +++ b/ext/symengine/symengine.c @@ -2,10 +2,12 @@ #include "ruby_basic.h" #include "ruby_symbol.h" #include "ruby_integer.h" +#include "ruby_number.h" #include "ruby_real_double.h" #include "ruby_constant.h" #include "ruby_complex.h" #include "ruby_complex_double.h" +#include "ruby_complex_mpc.h" #include "ruby_real_mpfr.h" #include "ruby_function.h" #include "ruby_ntheory.h" @@ -58,35 +60,46 @@ void Init_symengine() rb_define_module_function(m_symengine, "convert", cutils_sympify, 1); rb_define_global_function("SymEngine", cutils_sympify, 1); + // evalf as a Module Level Function + rb_define_module_function(m_symengine, "_evalf", cutils_evalf, 3); + // Symbol class c_symbol = rb_define_class_under(m_symengine, "Symbol", c_basic); rb_define_alloc_func(c_symbol, cbasic_alloc); rb_define_method(c_symbol, "initialize", csymbol_init, 1); + // Number class + c_number = rb_define_class_under(m_symengine, "Number", c_basic); + rb_define_alloc_func(c_number, cbasic_alloc); + rb_define_method(c_number, ">", cnumber_gt, 1); + rb_define_method(c_number, "<", cnumber_lt, 1); + rb_define_method(c_number, ">=", cnumber_gt_e, 1); + rb_define_method(c_number, "<=", cnumber_lt_e, 1); + // Integer class - c_integer = rb_define_class_under(m_symengine, "Integer", c_basic); + c_integer = rb_define_class_under(m_symengine, "Integer", c_number); rb_define_alloc_func(c_integer, cbasic_alloc); rb_define_method(c_integer, "initialize", cinteger_init, 1); rb_define_method(c_integer, "%", cntheory_mod, 1); // RealDouble Class - c_real_double = rb_define_class_under(m_symengine, "RealDouble", c_basic); + c_real_double = rb_define_class_under(m_symengine, "RealDouble", c_number); rb_define_alloc_func(c_real_double, cbasic_alloc); rb_define_method(c_real_double, "to_f", crealdouble_to_float, 0); // Rational class - c_rational = rb_define_class_under(m_symengine, "Rational", c_basic); + c_rational = rb_define_class_under(m_symengine, "Rational", c_number); rb_define_alloc_func(c_rational, cbasic_alloc); // Complex class - c_complex = rb_define_class_under(m_symengine, "Complex", c_basic); + c_complex = rb_define_class_under(m_symengine, "Complex", c_number); rb_define_alloc_func(c_complex, cbasic_alloc); rb_define_method(c_complex, "real", ccomplex_real_part, 0); rb_define_method(c_complex, "imaginary", ccomplex_imaginary_part, 0); // ComplexDouble class c_complex_double - = rb_define_class_under(m_symengine, "ComplexDouble", c_basic); + = rb_define_class_under(m_symengine, "ComplexDouble", c_number); rb_define_alloc_func(c_complex_double, cbasic_alloc); rb_define_method(c_complex_double, "real", ccomplex_double_real_part, 0); rb_define_method(c_complex_double, "imaginary", @@ -94,7 +107,7 @@ void Init_symengine() #ifdef HAVE_SYMENGINE_MPFR // RealMPFR class - c_real_mpfr = rb_define_class_under(m_symengine, "RealMPFR", c_basic); + c_real_mpfr = rb_define_class_under(m_symengine, "RealMPFR", c_number); rb_define_alloc_func(c_real_mpfr, cbasic_alloc); rb_define_method(c_real_mpfr, "initialize", crealmpfr_init, 2); rb_define_method(c_real_mpfr, "to_f", crealmpfr_to_float, 0); @@ -102,8 +115,11 @@ void Init_symengine() #ifdef HAVE_SYMENGINE_MPC // ComplexMPC class - c_complex_mpc = rb_define_class_under(m_symengine, "ComplexMPC", c_basic); + c_complex_mpc = rb_define_class_under(m_symengine, "ComplexMPC", c_number); rb_define_alloc_func(c_complex_mpc, cbasic_alloc); + rb_define_method(c_complex_mpc, "real", ccomplex_mpc_real_part, 0); + rb_define_method(c_complex_mpc, "imaginary", ccomplex_mpc_imaginary_part, + 0); #endif // HAVE_SYMENGINE_MPC // Constant class diff --git a/ext/symengine/symengine.h b/ext/symengine/symengine.h index 9284f61..3f7b233 100644 --- a/ext/symengine/symengine.h +++ b/ext/symengine/symengine.h @@ -10,6 +10,7 @@ VALUE m_symengine; // variable names for classes begin with c VALUE c_basic; VALUE c_symbol; +VALUE c_number; VALUE c_integer; VALUE c_real_double; VALUE c_rational; diff --git a/ext/symengine/symengine_utils.c b/ext/symengine/symengine_utils.c index f17489a..43dfdb3 100644 --- a/ext/symengine/symengine_utils.c +++ b/ext/symengine/symengine_utils.c @@ -91,7 +91,7 @@ void sympify(VALUE operand2, basic_struct *cbasic_operand2) void get_symintfromval(VALUE operand2, basic_struct *cbasic_operand2) { if (TYPE(operand2) == T_FIXNUM) { - int i = NUM2INT(operand2); + long int i = NUM2LONG(operand2); integer_set_si(cbasic_operand2, i); } else if (TYPE(operand2) == T_BIGNUM) { VALUE Rb_Temp_String = rb_funcall(operand2, rb_intern("to_s"), 0, NULL); diff --git a/lib/symengine.rb b/lib/symengine.rb index e4d3477..a73590e 100644 --- a/lib/symengine.rb +++ b/lib/symengine.rb @@ -29,7 +29,10 @@ def symbols ary_or_string, *params end def Function(n) return SymEngine::UndefFunction.new(n) - end + end + def evalf(operand, prec=53, real=false) + return _evalf(operand, prec, real) + end end end diff --git a/lib/symengine/basic.rb b/lib/symengine/basic.rb index a46531c..6523e15 100644 --- a/lib/symengine/basic.rb +++ b/lib/symengine/basic.rb @@ -9,5 +9,10 @@ def inspect def free_symbols pr_free_symbols.to_set end + + def abs + return SymEngine::abs(self) + end + end end diff --git a/spec/evalf_spec.rb b/spec/evalf_spec.rb new file mode 100644 index 0000000..c833165 --- /dev/null +++ b/spec/evalf_spec.rb @@ -0,0 +1,27 @@ +describe 'SymEngine::evalf' do + context 'RealDouble values' do + subject { SymEngine::evalf(SymEngine::sin(SymEngine(2)), 53, true) } + it { is_expected.to be_a SymEngine::RealDouble } + it { is_expected.to be_within(1e-15).of(0.909297426825682) } + end + if SymEngine::HAVE_MPFR + context 'RealMPFR values' do + subject { SymEngine::evalf(SymEngine::PI * SymEngine(1963319607) - SymEngine(6167950454), 100, true) } + it { is_expected.to be_a SymEngine::RealMPFR } + it { is_expected.to be_within(SymEngine::RealMPFR.new("1e-41", 100)).of(SymEngine::RealMPFR.new("1.4973429143989597928099399837265e-10", 100)) } + end + end + context 'ComplexDouble values' do + subject { SymEngine::evalf(SymEngine::sin(1) * SymEngine::I, 53, false) } + it { is_expected.to be_a SymEngine::ComplexDouble } + its(:imaginary) { is_expected.to be_within(1e-15).of(0.841470984807897) } + end + + if SymEngine::HAVE_MPC + context 'ComplexMPC values' do + subject { SymEngine::evalf(SymEngine::sin(1) * SymEngine::I, 100, false) } + it { is_expected.to be_a SymEngine::ComplexMPC } + its(:imaginary) { is_expected.to be_within(SymEngine::RealMPFR.new("1e-32", 100)).of(SymEngine::RealMPFR.new("0.84147098480789650665250232163005", 100)) } + end + end +end diff --git a/symengine_version.txt b/symengine_version.txt index bc0c91d..6e61f5d 100644 --- a/symengine_version.txt +++ b/symengine_version.txt @@ -1 +1 @@ -0c17ca9d88f25881c6d0ca382c26b2eb392b9b48 +bb18f1c1f4cbc29765fe1bcbd2dbe9345279b659