Skip to content

Commit 2aab1ec

Browse files
authored
Merge pull request #49 from rajithv/mpfr_mpc
[WIP] Ruby Wrappers for Real MPFR and Complex MPC
2 parents f23599d + 8e536cf commit 2aab1ec

File tree

11 files changed

+224
-13
lines changed

11 files changed

+224
-13
lines changed

ext/symengine/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ set(RUBY_WRAPPER_SRC
33
ruby_symbol.c
44
ruby_integer.c
55
ruby_real_double.c
6+
ruby_real_mpfr.c
67
ruby_complex.c
78
ruby_complex_double.c
89
ruby_constant.c

ext/symengine/ruby_constant.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,19 @@ VALUE cconstant_euler_gamma() {
2626
VALUE cconstant_i() {
2727
return cconstant_const(basic_const_I, c_complex);
2828
}
29+
30+
VALUE cconstant_have_mpfr() {
31+
#ifdef HAVE_SYMENGINE_MPFR
32+
return Qtrue;
33+
#else
34+
return Qfalse;
35+
#endif //HAVE_SYMENGINE_MPFR
36+
}
37+
38+
VALUE cconstant_have_mpc() {
39+
#ifdef HAVE_SYMENGINE_MPC
40+
return Qtrue;
41+
#else
42+
return Qfalse;
43+
#endif //HAVE_SYMENGINE_MPC
44+
}

ext/symengine/ruby_constant.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,8 @@ VALUE cconstant_euler_gamma();
1717

1818
VALUE cconstant_i();
1919

20+
VALUE cconstant_have_mpfr();
21+
22+
VALUE cconstant_have_mpc();
23+
2024
#endif //RUBY_CONSTANTS_H_

ext/symengine/ruby_real_mpfr.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#include "ruby_real_mpfr.h"
2+
3+
#ifdef HAVE_SYMENGINE_MPFR
4+
VALUE crealmpfr_init(VALUE self, VALUE num_value, VALUE prec_value)
5+
{
6+
basic_struct *cresult;
7+
double d;
8+
char *c;
9+
int prec = NUM2INT(prec_value);
10+
11+
Data_Get_Struct(self, basic_struct, cresult);
12+
13+
switch( TYPE(num_value) ) {
14+
case T_FLOAT:
15+
d = RFLOAT_VALUE(num_value);
16+
real_mpfr_set_d(cresult, d, prec);
17+
break;
18+
case T_STRING:
19+
c = RSTRING_PTR(num_value);
20+
real_mpfr_set_str(cresult, c, prec);
21+
break;
22+
case T_DATA:
23+
c = rb_obj_classname(num_value);
24+
if (strcmp(c, "BigDecimal") == 0) {
25+
c = RSTRING_PTR(rb_funcall(num_value, rb_intern("to_s"), 1, rb_str_new2("F")));
26+
real_mpfr_set_str(cresult, c, prec);
27+
break;
28+
}
29+
default:
30+
rb_raise(rb_eTypeError, "Invalid Type: Float, BigDecimal or String required.");
31+
break;
32+
}
33+
34+
return self;
35+
}
36+
37+
VALUE crealmpfr_to_float(VALUE self)
38+
{
39+
// TODO: Make the following method work
40+
//VALUE result;
41+
//basic cbasic_operand1;
42+
//basic_new_stack(cbasic_operand1);
43+
//sympify(self, cbasic_operand1);
44+
//result = rb_float_new(real_mpfr_get_d(cbasic_operand1));
45+
46+
return rb_funcall(rb_funcall(self, rb_intern("to_s"), 0, NULL), rb_intern("to_f"), 0, NULL);
47+
}
48+
#endif //HAVE_SYMENGINE_MPFR
49+

ext/symengine/ruby_real_mpfr.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#ifndef RUBY_REAL_MPFR_H_
2+
#define RUBY_REAL_MPFR_H_
3+
4+
#include <ruby.h>
5+
#include <symengine/cwrapper.h>
6+
7+
#include "symengine.h"
8+
#include "symengine_utils.h"
9+
10+
#ifdef HAVE_SYMENGINE_MPFR
11+
VALUE crealmpfr_init(VALUE self, VALUE num_value, VALUE prec_value);
12+
VALUE crealmpfr_to_float(VALUE self);
13+
#endif //HAVE_SYMENGINE_MPFR
14+
15+
#endif //RUBY_REAL_MPFR_H_

ext/symengine/symengine.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "ruby_constant.h"
77
#include "ruby_complex.h"
88
#include "ruby_complex_double.h"
9+
#include "ruby_real_mpfr.h"
910
#include "ruby_function.h"
1011
#include "ruby_ntheory.h"
1112
#include "ruby_utils.h"
@@ -85,6 +86,20 @@ void Init_symengine() {
8586
rb_define_method(c_complex_double, "real", ccomplex_double_real_part, 0);
8687
rb_define_method(c_complex_double, "imaginary", ccomplex_double_imaginary_part, 0);
8788

89+
#ifdef HAVE_SYMENGINE_MPFR
90+
//RealMPFR class
91+
c_real_mpfr = rb_define_class_under(m_symengine, "RealMPFR", c_basic);
92+
rb_define_alloc_func(c_real_mpfr, cbasic_alloc);
93+
rb_define_method(c_real_mpfr, "initialize", crealmpfr_init, 2);
94+
rb_define_method(c_real_mpfr, "to_f", crealmpfr_to_float, 0);
95+
#endif //HAVE_SYMENGINE_MPFR
96+
97+
#ifdef HAVE_SYMENGINE_MPC
98+
//ComplexMPC class
99+
c_complex_mpc = rb_define_class_under(m_symengine, "ComplexMPC", c_basic);
100+
rb_define_alloc_func(c_complex_mpc, cbasic_alloc);
101+
#endif //HAVE_SYMENGINE_MPC
102+
88103
//Constant class
89104
c_constant = rb_define_class_under(m_symengine, "Constant", c_basic);
90105

@@ -93,6 +108,8 @@ void Init_symengine() {
93108
rb_define_const(m_symengine, "E", cconstant_e());
94109
rb_define_const(m_symengine, "EULER_GAMMA", cconstant_euler_gamma());
95110
rb_define_const(m_symengine, "I", cconstant_i());
111+
rb_define_const(m_symengine, "HAVE_MPFR", cconstant_have_mpfr());
112+
rb_define_const(m_symengine, "HAVE_MPC", cconstant_have_mpc());
96113

97114
//Add class
98115
c_add = rb_define_class_under(m_symengine, "Add", c_basic);

ext/symengine/symengine.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ VALUE c_real_double;
1414
VALUE c_rational;
1515
VALUE c_complex;
1616
VALUE c_complex_double;
17+
#ifdef HAVE_SYMENGINE_MPFR
18+
VALUE c_real_mpfr;
19+
#endif //HAVE_SYMENGINE_MPFR
20+
#ifdef HAVE_SYMENGINE_MPC
21+
VALUE c_complex_mpc;
22+
#endif //HAVE_SYMENGINE_MPC
1723
VALUE c_constant;
1824
VALUE c_add;
1925
VALUE c_mul;

ext/symengine/symengine_utils.c

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
void sympify(VALUE operand2, basic_struct *cbasic_operand2) {
55

66
basic_struct *temp;
7-
VALUE new_operand2, num, den;
8-
VALUE real, imag;
7+
VALUE new_operand2;
8+
VALUE a, b;
99
double f;
10+
char *c;
11+
rb_cBigDecimal = CLASS_OF(rb_eval_string("BigDecimal.new('0.0001')"));
1012

1113
switch(TYPE(operand2)) {
1214
case T_FIXNUM:
@@ -20,15 +22,15 @@ void sympify(VALUE operand2, basic_struct *cbasic_operand2) {
2022
break;
2123

2224
case T_RATIONAL:
23-
num = rb_funcall(operand2, rb_intern("numerator"), 0, NULL);
24-
den = rb_funcall(operand2, rb_intern("denominator"), 0, NULL);
25+
a = rb_funcall(operand2, rb_intern("numerator"), 0, NULL);
26+
b = rb_funcall(operand2, rb_intern("denominator"), 0, NULL);
2527

2628
basic num_basic, den_basic;
2729
basic_new_stack(num_basic);
2830
basic_new_stack(den_basic);
2931

30-
get_symintfromval(num, num_basic);
31-
get_symintfromval(den, den_basic);
32+
get_symintfromval(a, num_basic);
33+
get_symintfromval(b, den_basic);
3234

3335
rational_set(cbasic_operand2, num_basic, den_basic);
3436

@@ -37,17 +39,17 @@ void sympify(VALUE operand2, basic_struct *cbasic_operand2) {
3739
break;
3840

3941
case T_COMPLEX:
40-
real = rb_funcall(operand2, rb_intern("real"), 0, NULL);
41-
imag = rb_funcall(operand2, rb_intern("imaginary"), 0, NULL);
42+
a = rb_funcall(operand2, rb_intern("real"), 0, NULL);
43+
b = rb_funcall(operand2, rb_intern("imaginary"), 0, NULL);
4244

4345
basic real_basic;
4446
basic imag_basic;
4547

4648
basic_new_stack(real_basic);
4749
basic_new_stack(imag_basic);
4850

49-
sympify(real, real_basic);
50-
sympify(imag, imag_basic);
51+
sympify(a, real_basic);
52+
sympify(b, imag_basic);
5153

5254
basic_const_I(cbasic_operand2);
5355
basic_mul(cbasic_operand2, cbasic_operand2, imag_basic);
@@ -59,10 +61,18 @@ void sympify(VALUE operand2, basic_struct *cbasic_operand2) {
5961
break;
6062

6163
case T_DATA:
64+
c = rb_obj_classname(operand2);
65+
#ifdef HAVE_SYMENGINE_MPFR
66+
if(CLASS_OF(operand2) == rb_cBigDecimal){
67+
c = RSTRING_PTR( rb_funcall(operand2, rb_intern("to_s"), 1, rb_str_new2("F")) );
68+
real_mpfr_set_str(cbasic_operand2, c, 200);
69+
break;
70+
}
71+
#endif //HAVE_SYMENGINE_MPFR
72+
6273
Data_Get_Struct(operand2, basic_struct, temp);
6374
basic_assign(cbasic_operand2, temp);
6475
break;
65-
6676
}
6777
}
6878

@@ -87,12 +97,20 @@ VALUE Klass_of_Basic(const basic_struct *basic_ptr) {
8797
return c_integer;
8898
case SYMENGINE_REAL_DOUBLE:
8999
return c_real_double;
100+
#ifdef HAVE_SYMENGINE_MPFR
101+
case SYMENGINE_REAL_MPFR:
102+
return c_real_mpfr;
103+
#endif //HAVE_SYMENGINE_MPFR
90104
case SYMENGINE_RATIONAL:
91105
return c_rational;
92106
case SYMENGINE_COMPLEX:
93107
return c_complex;
94108
case SYMENGINE_COMPLEX_DOUBLE:
95109
return c_complex_double;
110+
#ifdef HAVE_SYMENGINE_MPC
111+
case SYMENGINE_COMPLEX_MPC:
112+
return c_complex_mpc;
113+
#endif //HAVE_SYMENGINE_MPFR
96114
case SYMENGINE_CONSTANT:
97115
return c_constant;
98116
case SYMENGINE_ADD:

ext/symengine/symengine_utils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include "ruby_basic.h"
66
#include "symengine/cwrapper.h"
77

8+
VALUE rb_cBigDecimal;
9+
810
//Returns the pointer wrapped inside the Ruby VALUE
911
void sympify(VALUE operand2, basic_struct *cbasic_operand2);
1012
//Returns the pointer wrapped inside the Ruby Fixnum or Bignum

spec/real_mpfr_spec.rb

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
require 'bigdecimal'
2+
3+
if SymEngine::HAVE_MPFR
4+
5+
describe SymEngine::RealMPFR do
6+
describe 'Convert BigDemcimal to RealMPFR' do
7+
shared_examples 'simple real check' do
8+
subject { SymEngine(value) }
9+
10+
it { is_expected.to be_a SymEngine::RealMPFR }
11+
its(:to_f) { is_expected.to eq value.to_f }
12+
end
13+
14+
context 'positive BigDecimal' do
15+
let(:value) { BigDecimal("12.3") }
16+
17+
it_behaves_like 'simple real check'
18+
end
19+
20+
context 'negative BigDecimal' do
21+
let(:value) { BigDecimal("-12.3") }
22+
23+
it_behaves_like 'simple real check'
24+
end
25+
end
26+
27+
describe 'Initialize RealMPFR' do
28+
shared_examples 'simple real check' do
29+
subject { SymEngine::RealMPFR.new(value, 200) }
30+
31+
it { is_expected.to be_a SymEngine::RealMPFR }
32+
its(:to_f) { is_expected.to eq value.to_f }
33+
end
34+
35+
context 'positive BigDecimal' do
36+
let(:value) { BigDecimal("12.3") }
37+
38+
it_behaves_like 'simple real check'
39+
end
40+
41+
context 'negative BigDecimal' do
42+
let(:value) { BigDecimal("-12.3") }
43+
44+
it_behaves_like 'simple real check'
45+
end
46+
47+
context 'positive Float' do
48+
let(:value) { 12.3 }
49+
50+
it_behaves_like 'simple real check'
51+
end
52+
53+
context 'negative Float' do
54+
let(:value) { 12.3 }
55+
56+
it_behaves_like 'simple real check'
57+
end
58+
59+
context 'String representation of positive value' do
60+
let(:value) { "12.3" }
61+
62+
it_behaves_like 'simple real check'
63+
end
64+
65+
context 'String representation of negative value' do
66+
let(:value) { "-12.3" }
67+
68+
it_behaves_like 'simple real check'
69+
end
70+
end
71+
72+
if SymEngine::HAVE_MPC
73+
describe SymEngine::ComplexMPC do
74+
let(:i) { SymEngine::I }
75+
let(:real) { SymEngine(BigDecimal("34.5")) }
76+
let(:imag) { SymEngine(BigDecimal("65.8")) }
77+
78+
subject { real + i * imag }
79+
it { is_expected.to be_a SymEngine::ComplexMPC }
80+
end
81+
end
82+
83+
end
84+
end

0 commit comments

Comments
 (0)