ext/mpfr/ruby_mpfr.c in ruby-mpfr-0.0.9 vs ext/mpfr/ruby_mpfr.c in ruby-mpfr-0.0.10

- old
+ new

@@ -1,88 +1,112 @@ #include "ruby_mpfr.h" +#include <stdbool.h> #define MPFR_DUMP_NUMBER 'A' #define MPFR_DUMP_PZERO 'B' #define MPFR_DUMP_MZERO 'C' #define MPFR_DUMP_PINF 'D' #define MPFR_DUMP_MINF 'E' #define MPFR_DUMP_NAN 'F' -static ID eqq, to_s, new, class, method_defined, object_id; +#define MPFR_P(obj) RTEST(rb_funcall(__mpfr_class__, eqq, 1, obj)) + +static ID eqq, to_s, new, class, method_defined, object_id, to_fr, + id_rndn, id_rndz, id_rndu, id_rndd, id_rnda; static VALUE __mpfr_class__, __sym_to_s__, __sym_to_str__; /* ------------------------------ Precision and Rounding Mode Start ------------------------------ */ #define VALID_RND(rnd_mode) (rnd_mode >= MPFR_RNDN && rnd_mode < ((MPFR_RNDA)+1)) #define SPECIAL_FUNC_STATE "@@special_func_state" /* Convert VALUE rnd (rounding mode number) to C integer and */ /* return it if it is valid as rounding mode number. */ mp_rnd_t r_mpfr_rnd_from_value(VALUE rnd) { - mp_rnd_t r = (mp_rnd_t)NUM2INT(rnd); - if(!VALID_RND(r)){ - rb_raise(rb_eArgError, "Argument must be Rounding Mode."); + ID rnd_id = SYM2ID(rnd); + if (rnd_id == id_rndn) { + return MPFR_RNDN; + } else if (rnd_id == id_rndz) { + return MPFR_RNDZ; + } else if (rnd_id == id_rndu) { + return MPFR_RNDU; + } else if (rnd_id == id_rndd) { + return MPFR_RNDD; + } else if (rnd_id == id_rnda) { + return MPFR_RNDA; } - return r; + rb_raise(rb_eArgError, "Argument must be Rounding Mode."); + /* rb_raise(rb_eArgError, "Argument must be Rounding Mode: %s", rb_class2name(rnd)); */ } /* If argc equals max, convert last argument to rounding mode number. */ /* Otherwise, return defoult rounding mode number. */ mp_rnd_t r_mpfr_rnd_from_optional_argument(int min, int max, int argc, VALUE *argv) { - mp_rnd_t rnd; if(argc >= min && argc <= max){ if(argc == max){ - rnd = r_mpfr_rnd_from_value(argv[max-1]); - }else{ - rnd = mpfr_get_default_rounding_mode(); + return r_mpfr_rnd_from_value(argv[max-1]); } - }else{ - rb_raise(rb_eArgError, "Invalid number of arguments."); + return mpfr_get_default_rounding_mode(); } - return rnd; + rb_raise(rb_eArgError, "Invalid number of arguments."); } /* If argc equals max, convert last argument to precision number. */ /* Otherwise, return defoult precision number. */ mp_rnd_t r_mpfr_prec_from_optional_argument(int min, int max, int argc, VALUE *argv) { - mp_prec_t prec; if(argc >= min && argc <= max){ if(argc == max){ - prec = NUM2INT(argv[max - 1]); - }else{ - prec = mpfr_get_default_prec(); + return NUM2INT(argv[max - 1]); } - }else{ - rb_raise(rb_eArgError, "Invalid number of arguments."); + return mpfr_get_default_prec(); } - return prec; + rb_raise(rb_eArgError, "Invalid number of arguments."); } /* min is a minimum number of arguments. */ /* max is a maximum number of arguments. */ void r_mpfr_get_rnd_prec_from_optional_arguments(mp_rnd_t *rnd, mp_prec_t *prec, int min, int max, int argc, VALUE *argv) { if(argc >= min && argc <= max){ - if(argc >= max - 1){ - *rnd = r_mpfr_rnd_from_value(argv[max - 2]); - }else{ + if (argc == max - 1) { + switch(TYPE(argv[max - 2])){ + case T_SYMBOL: + *prec = mpfr_get_default_prec(); + *rnd = r_mpfr_rnd_from_value(argv[max - 2]); + return; + case T_FIXNUM: + *prec = NUM2INT(argv[max - 2]); + *rnd = mpfr_get_default_rounding_mode(); + return; + } + } else if (argc == max) { + switch(TYPE(argv[max - 2])){ + case T_SYMBOL: + *rnd = r_mpfr_rnd_from_value(argv[max - 2]); + if (FIXNUM_P(argv[max - 1])) { + *prec = NUM2INT(argv[max - 1]); + return; + } + case T_FIXNUM: + *prec = NUM2INT(argv[max - 2]); + if (SYMBOL_P(argv[max - 1])) { + *rnd = r_mpfr_rnd_from_value(argv[max - 1]); + return; + } + } + } else { + *prec = mpfr_get_default_prec(); *rnd = mpfr_get_default_rounding_mode(); + return; } - if(argc == max){ - *prec = NUM2INT(argv[max - 1]); - }else{ - *prec = mpfr_get_default_prec(); - } - }else{ - rb_raise(rb_eArgError, "Invalid number of arguments."); } + rb_raise(rb_eArgError, "Invalid number of arguments or invalid type of an argument."); } - /* Set the default MPFR precision in bits. */ static VALUE r_mpfr_set_default_prec(VALUE self, VALUE prec) { int set_prec = NUM2INT(prec); if(set_prec <= 0){ @@ -99,23 +123,44 @@ } /* Set the default rounding mode. The default rounding mode is MPFR::RNDN. */ static VALUE r_mpfr_set_default_rounding_mode(VALUE self, VALUE rnd) { - mp_rnd_t a = NUM2INT(rnd); - if(VALID_RND(a)){ - mpfr_set_default_rounding_mode(a); - }else{ - rb_raise(rb_eArgError, "Argument must be Rounding Mode."); + ID rnd_id = SYM2ID(rnd); + if (rnd_id == id_rndn) { + mpfr_set_default_rounding_mode(MPFR_RNDN); + } else if (rnd_id == id_rndz) { + mpfr_set_default_rounding_mode(MPFR_RNDZ); + } else if (rnd_id == id_rndu) { + mpfr_set_default_rounding_mode(MPFR_RNDU); + } else if (rnd_id == id_rndd) { + mpfr_set_default_rounding_mode(MPFR_RNDD); + } else if (rnd_id == id_rnda) { + mpfr_set_default_rounding_mode(MPFR_RNDA); } - return INT2FIX(mpfr_get_default_rounding_mode()); + return rnd; } /* Get the default rounding mode. */ static VALUE r_mpfr_get_default_rounding_mode(VALUE self) { - return INT2NUM(mpfr_get_default_rounding_mode()); + switch (mpfr_get_default_rounding_mode()) { + case MPFR_RNDN: + return ID2SYM(id_rndn); + case MPFR_RNDZ: + return ID2SYM(id_rndz); + case MPFR_RNDU: + return ID2SYM(id_rndu); + case MPFR_RNDD: + return ID2SYM(id_rndd); + case MPFR_RNDA: + return ID2SYM(id_rnda); + case MPFR_RNDF: + case MPFR_RNDNA: + rb_raise(rb_eStandardError, "Unsupported rounding mode."); + } + rb_raise(rb_eStandardError, "Invalid rounding mode."); } /* ------------------------------ Precision and Rounding Mode End ------------------------------ */ /* ------------------------------ Exception Related Functions Start ------------------------------ */ @@ -335,11 +380,11 @@ } } void r_mpfr_set_robj(MPFR *ptr, VALUE obj, mp_rnd_t rnd) { - if(RTEST(rb_funcall(__mpfr_class__, eqq, 1, obj))){ + if(MPFR_P(obj)){ MPFR *ptr_obj; r_mpfr_get_struct(ptr_obj, obj); mpfr_set(ptr, ptr_obj, rnd); }else{ switch(TYPE(obj)){ @@ -354,22 +399,39 @@ break; case T_BIGNUM: r_mpfr_convert_to_str_set(ptr, obj, rnd); break; default: - rb_raise(rb_eArgError, "Invalid class %s for making MPFR.", rb_class2name(obj)); + if(rb_respond_to(obj, to_fr)){ + MPFR *ptr_obj; + volatile VALUE tmp = rb_funcall(obj, to_fr, 0); + r_mpfr_get_struct(ptr_obj, tmp); + mpfr_set(ptr, ptr_obj, rnd); + } else { + rb_raise(rb_eArgError, "Invalid class %s for making MPFR.", rb_class2name(obj)); + } break; } } } +VALUE r_mpfr_robj_to_mpfr(VALUE obj, int argc, VALUE *argv) +{ + if (rb_respond_to(obj, to_fr)) { + return rb_funcall2(obj, to_fr, argc, argv); + } + rb_raise(rb_eArgError, "The object of %s can not been converted to MPFR.", rb_class2name(obj)); +} + /* If obj is MPFR instance, then this method returns obj. */ /* Otherwise it returns MPFR.new(obj). */ VALUE r_mpfr_new_fr_obj(VALUE obj) { - if(RTEST(rb_funcall(__mpfr_class__, eqq, 1, obj))){ + if(MPFR_P(obj)){ return obj; + }else if (rb_respond_to(obj, to_fr)) { + return rb_funcall(obj, to_fr, 0); }else{ return rb_funcall(__mpfr_class__, new, 1, obj); } } @@ -378,43 +440,72 @@ MPFR *ptr; r_mpfr_make_struct(self, ptr); return self; } -static void r_mpfr_set_initial_value(MPFR *ptr, int argc, VALUE *argv) +/* Return new MPFR instance. The same arguments as MPFR.new is acceptable. */ +static VALUE r_mpfr_global_new(int argc, VALUE *argv, VALUE self) { + MPFR *ptr; + VALUE val; + mp_prec_t prec; + mp_rnd_t rnd; switch(argc){ case 0: - mpfr_init(ptr); + r_mpfr_make_struct_init(val, ptr); mpfr_set_nan(ptr); - break; + return val; case 1: - mpfr_init(ptr); - r_mpfr_set_robj(ptr, argv[0], mpfr_get_default_rounding_mode()); + prec = mpfr_get_default_prec(); + rnd = mpfr_get_default_rounding_mode(); break; case 2: - case 3: - if(argc == 2){ - mpfr_init(ptr); - }else{ - mpfr_init2(ptr, NUM2INT(argv[2])); + if (SYMBOL_P(argv[1])) { + rnd = r_mpfr_rnd_from_value(argv[1]); + prec = mpfr_get_default_prec(); + } else if (FIXNUM_P(argv[1])) { + prec = NUM2INT(argv[1]); + rnd = mpfr_get_default_rounding_mode(); + } else { + rb_raise(rb_eArgError, "Invalid argument."); } - r_mpfr_set_robj(ptr, argv[0], r_mpfr_rnd_from_value(argv[1])); break; + case 3: + r_mpfr_get_rnd_prec_from_optional_arguments(&rnd, &prec, 1, 3, argc, argv); + break; default: rb_raise(rb_eArgError, "Invalid number of arguments."); break; } -} - -/* Return new MPFR instance. The same arguments as MPFR.new is acceptable. */ -static VALUE r_mpfr_global_new(int argc, VALUE *argv, VALUE self) -{ - MPFR *ptr; - VALUE val; - r_mpfr_make_struct(val, ptr); - r_mpfr_set_initial_value(ptr, argc, argv); + if(MPFR_P(argv[0])){ + MPFR *ptr_obj; + r_mpfr_get_struct(ptr_obj, argv[0]); + r_mpfr_make_struct_init2(val, ptr, prec); + mpfr_set(ptr, ptr_obj, rnd); + }else{ + switch(TYPE(argv[0])){ + case T_STRING: + r_mpfr_make_struct_init2(val, ptr, prec); + mpfr_set_str(ptr, StringValuePtr(argv[0]), 10, rnd); + break; + case T_FLOAT: + r_mpfr_make_struct_init2(val, ptr, prec); + mpfr_set_d(ptr, NUM2DBL(argv[0]), rnd); + break; + case T_FIXNUM: + r_mpfr_make_struct_init2(val, ptr, prec); + mpfr_set_si(ptr, FIX2LONG(argv[0]), rnd); + break; + case T_BIGNUM: + r_mpfr_make_struct_init2(val, ptr, prec); + r_mpfr_convert_to_str_set(ptr, argv[0], rnd); + break; + default: + val = r_mpfr_robj_to_mpfr(argv[0], argc - 1, argv + 1); + break; + } + } return val; } /* This method returns MPFR instance. @@ -424,11 +515,41 @@ */ static VALUE r_mpfr_initialize(int argc, VALUE *argv, VALUE self) { MPFR *ptr; r_mpfr_get_struct(ptr, self); - r_mpfr_set_initial_value(ptr, argc, argv); + switch(argc){ + case 0: + mpfr_init(ptr); + mpfr_set_nan(ptr); + break; + case 1: + mpfr_init(ptr); + r_mpfr_set_robj(ptr, argv[0], mpfr_get_default_rounding_mode()); + break; + case 2: + if (SYMBOL_P(argv[1])) { + mpfr_init(ptr); + r_mpfr_set_robj(ptr, argv[0], r_mpfr_rnd_from_value(argv[1])); + } else if (FIXNUM_P(argv[1])) { + mpfr_init2(ptr, NUM2INT(argv[1])); + r_mpfr_set_robj(ptr, argv[0], mpfr_get_default_rounding_mode()); + } + break; + case 3: + { + mp_prec_t prec; + mp_rnd_t rnd; + r_mpfr_get_rnd_prec_from_optional_arguments(&rnd, &prec, 1, 3, argc, argv); + mpfr_init2(ptr, prec); + r_mpfr_set_robj(ptr, argv[0], rnd); + } + break; + default: + rb_raise(rb_eArgError, "Invalid number of arguments."); + break; + } return Qtrue; } /* This method is the method of initialization for copying object. */ static VALUE r_mpfr_initialize_copy(VALUE self, VALUE other) @@ -442,16 +563,11 @@ } /* Return array which have MPFR instance converted to from p1 and self. */ static VALUE r_mpfr_coerce(VALUE self, VALUE other) { - VALUE val_other; - MPFR *ptr_self, *ptr_other; - r_mpfr_get_struct(ptr_self, self); - r_mpfr_make_struct_init2(val_other, ptr_other, mpfr_get_prec(ptr_self)); - r_mpfr_set_robj(ptr_other, other, mpfr_get_default_rounding_mode()); - return rb_ary_new3(2, val_other, self); + return rb_ary_new3(2, r_mpfr_global_new(1, &other, r_mpfr_class), self); } /* Return NaN. This method takes one optional argument meaning precision. */ static VALUE r_mpfr_nan(int argc, VALUE *argv, VALUE self) { @@ -583,11 +699,11 @@ /* Swap the values self and p1 efficiently. p1 must be MPFR object. */ static VALUE r_mpfr_swap(VALUE self, VALUE other) { MPFR *ptr_self, *ptr_other; r_mpfr_get_struct(ptr_self, self); - if(RTEST(rb_funcall(__mpfr_class__, eqq, 1, other))){ + if(MPFR_P(other)){ r_mpfr_get_struct(ptr_other, other); }else{ rb_raise(rb_eArgError, "Argument must be MPFR object."); } mpfr_swap(ptr_self, ptr_other); @@ -720,21 +836,25 @@ MPFR *ptr_self, *ptr_other, *ptr_return; VALUE val_ret; r_mpfr_get_struct(ptr_self, self); r_mpfr_make_struct_init(val_ret, ptr_return); - if(RTEST(rb_funcall(__mpfr_class__, eqq, 1, other))){ + if(MPFR_P(other)){ r_mpfr_get_struct(ptr_other, other); mpfr_add(ptr_return, ptr_self, ptr_other, mpfr_get_default_rounding_mode()); }else if(TYPE(other) == T_FIXNUM){ mpfr_add_si(ptr_return, ptr_self, FIX2LONG(other), mpfr_get_default_rounding_mode()); }else if(TYPE(other) == T_FLOAT){ mpfr_add_d(ptr_return, ptr_self, NUM2DBL(other), mpfr_get_default_rounding_mode()); }else if(TYPE(other) == T_BIGNUM){ volatile VALUE tmp = rb_funcall(__mpfr_class__, new, 1, other); r_mpfr_get_struct(ptr_other, tmp); mpfr_add(ptr_return, ptr_self, ptr_other, mpfr_get_default_rounding_mode()); + }else if(rb_respond_to(other, to_fr)){ + volatile VALUE tmp = rb_funcall(other, to_fr, 0); + r_mpfr_get_struct(ptr_other, tmp); + mpfr_add(ptr_return, ptr_self, ptr_other, mpfr_get_default_rounding_mode()); }else{ rb_raise(rb_eArgError, "Argument must be MPFR, Fixnum, Float, or Bignum."); } return val_ret; } @@ -745,21 +865,25 @@ MPFR *ptr_self, *ptr_other, *ptr_return; VALUE val_ret; r_mpfr_get_struct(ptr_self, self); r_mpfr_make_struct_init(val_ret, ptr_return); - if(RTEST(rb_funcall(__mpfr_class__, eqq, 1, other))){ + if(MPFR_P(other)){ r_mpfr_get_struct(ptr_other, other); mpfr_sub(ptr_return, ptr_self, ptr_other, mpfr_get_default_rounding_mode()); }else if(TYPE(other) == T_FIXNUM){ mpfr_sub_si(ptr_return, ptr_self, FIX2LONG(other), mpfr_get_default_rounding_mode()); }else if(TYPE(other) == T_FLOAT){ mpfr_sub_d(ptr_return, ptr_self, NUM2DBL(other), mpfr_get_default_rounding_mode()); }else if(TYPE(other) == T_BIGNUM){ volatile VALUE tmp = rb_funcall(__mpfr_class__, new, 1, other); r_mpfr_get_struct(ptr_other, tmp); mpfr_sub(ptr_return, ptr_self, ptr_other, mpfr_get_default_rounding_mode()); + }else if(rb_respond_to(other, to_fr)){ + volatile VALUE tmp = rb_funcall(other, to_fr, 0); + r_mpfr_get_struct(ptr_other, tmp); + mpfr_sub(ptr_return, ptr_self, ptr_other, mpfr_get_default_rounding_mode()); }else{ rb_raise(rb_eArgError, "Argument must be MPFR, Fixnum, Float, or Bignum."); } return val_ret; } @@ -770,21 +894,25 @@ MPFR *ptr_self, *ptr_other, *ptr_return; VALUE val_ret; r_mpfr_get_struct(ptr_self, self); r_mpfr_make_struct_init(val_ret, ptr_return); - if(RTEST(rb_funcall(__mpfr_class__, eqq, 1, other))){ + if(MPFR_P(other)){ r_mpfr_get_struct(ptr_other, other); mpfr_mul(ptr_return, ptr_self, ptr_other, mpfr_get_default_rounding_mode()); }else if(TYPE(other) == T_FIXNUM){ mpfr_mul_si(ptr_return, ptr_self, FIX2LONG(other), mpfr_get_default_rounding_mode()); }else if(TYPE(other) == T_FLOAT){ mpfr_mul_d(ptr_return, ptr_self, NUM2DBL(other), mpfr_get_default_rounding_mode()); }else if(TYPE(other) == T_BIGNUM){ volatile VALUE tmp = rb_funcall(__mpfr_class__, new, 1, other); r_mpfr_get_struct(ptr_other, tmp); mpfr_mul(ptr_return, ptr_self, ptr_other, mpfr_get_default_rounding_mode()); + }else if(rb_respond_to(other, to_fr)){ + volatile VALUE tmp = rb_funcall(other, to_fr, 0); + r_mpfr_get_struct(ptr_other, tmp); + mpfr_mul(ptr_return, ptr_self, ptr_other, mpfr_get_default_rounding_mode()); }else{ rb_raise(rb_eArgError, "Argument must be MPFR, Fixnum, Float, or Bignum."); } return val_ret; } @@ -795,21 +923,25 @@ MPFR *ptr_self, *ptr_other, *ptr_return; VALUE val_ret; r_mpfr_get_struct(ptr_self, self); r_mpfr_make_struct_init(val_ret, ptr_return); - if(RTEST(rb_funcall(__mpfr_class__, eqq, 1, other))){ + if(MPFR_P(other)){ r_mpfr_get_struct(ptr_other, other); mpfr_div(ptr_return, ptr_self, ptr_other, mpfr_get_default_rounding_mode()); }else if(TYPE(other) == T_FIXNUM){ mpfr_div_si(ptr_return, ptr_self, FIX2LONG(other), mpfr_get_default_rounding_mode()); }else if(TYPE(other) == T_FLOAT){ mpfr_div_d(ptr_return, ptr_self, NUM2DBL(other), mpfr_get_default_rounding_mode()); }else if(TYPE(other) == T_BIGNUM){ volatile VALUE tmp = rb_funcall(__mpfr_class__, new, 1, other); r_mpfr_get_struct(ptr_other, tmp); mpfr_div(ptr_return, ptr_self, ptr_other, mpfr_get_default_rounding_mode()); + }else if(rb_respond_to(other, to_fr)){ + volatile VALUE tmp = rb_funcall(other, to_fr, 0); + r_mpfr_get_struct(ptr_other, tmp); + mpfr_div(ptr_return, ptr_self, ptr_other, mpfr_get_default_rounding_mode()); }else{ rb_raise(rb_eArgError, "Argument must be MPFR, Fixnum, Float, or Bignum."); } return val_ret; } @@ -873,11 +1005,11 @@ VALUE val_ret; volatile VALUE tmp_argv0 = r_mpfr_new_fr_obj(argv[0]); r_mpfr_get_struct(ptr_arg1, tmp_argv0); r_mpfr_make_struct_init2(val_ret, ptr_return, prec); - if(RTEST(rb_funcall(__mpfr_class__, eqq, 1, argv[1]))){ + if(MPFR_P(argv[1])){ r_mpfr_get_struct(ptr_arg2, argv[1]); mpfr_add(ptr_return, ptr_arg1, ptr_arg2, rnd); }else if(TYPE(argv[1]) == T_FIXNUM){ mpfr_add_si(ptr_return, ptr_arg1, FIX2LONG(argv[1]), rnd); }else{ @@ -897,11 +1029,11 @@ VALUE val_ret; volatile VALUE tmp_argv0 = r_mpfr_new_fr_obj(argv[0]); r_mpfr_get_struct(ptr_arg1, tmp_argv0); r_mpfr_make_struct_init2(val_ret, ptr_return, prec); - if(RTEST(rb_funcall(__mpfr_class__, eqq, 1, argv[1]))){ + if(MPFR_P(argv[1])){ r_mpfr_get_struct(ptr_arg2, argv[1]); mpfr_sub(ptr_return, ptr_arg1, ptr_arg2, rnd); }else if(TYPE(argv[1]) == T_FIXNUM){ mpfr_sub_si(ptr_return, ptr_arg1, FIX2LONG(argv[1]), rnd); }else{ @@ -921,11 +1053,11 @@ VALUE val_ret; volatile VALUE tmp_argv0 = r_mpfr_new_fr_obj(argv[0]); r_mpfr_get_struct(ptr_arg1, tmp_argv0); r_mpfr_make_struct_init2(val_ret, ptr_return, prec); - if(RTEST(rb_funcall(__mpfr_class__, eqq, 1, argv[1]))){ + if(MPFR_P(argv[1])){ r_mpfr_get_struct(ptr_arg2, argv[1]); mpfr_mul(ptr_return, ptr_arg1, ptr_arg2, rnd); }else if(TYPE(argv[1]) == T_FIXNUM){ mpfr_mul_si(ptr_return, ptr_arg1, FIX2LONG(argv[1]), rnd); }else{ @@ -945,11 +1077,11 @@ VALUE val_ret; volatile VALUE tmp_argv0 = r_mpfr_new_fr_obj(argv[0]); r_mpfr_get_struct(ptr_arg1, tmp_argv0); r_mpfr_make_struct_init2(val_ret, ptr_return, prec); - if(RTEST(rb_funcall(__mpfr_class__, eqq, 1, argv[1]))){ + if(MPFR_P(argv[1])){ r_mpfr_get_struct(ptr_arg2, argv[1]); mpfr_div(ptr_return, ptr_arg1, ptr_arg2, rnd); }else if(TYPE(argv[1]) == T_FIXNUM){ mpfr_div_si(ptr_return, ptr_arg1, FIX2LONG(argv[1]), rnd); }else{ @@ -1126,11 +1258,11 @@ { MPFR *ptr_self, *ptr_other; r_mpfr_get_struct(ptr_self, self); int val_ret; - if(RTEST(rb_funcall(__mpfr_class__, eqq, 1, other))){ + if(MPFR_P(other)){ r_mpfr_get_struct(ptr_other, other); val_ret = mpfr_cmp(ptr_self, ptr_other); }else if(TYPE(other) == T_FIXNUM){ val_ret = mpfr_cmp_si(ptr_self, FIX2LONG(other)); }else if(TYPE(other) == T_FLOAT){ @@ -1889,11 +2021,11 @@ /* Return [sin, cos] such as mpfr_sin_cos(sin, cos, p1, rnd). */ static VALUE r_mpfr_math_sin_cos(int argc, VALUE *argv, VALUE self) { mp_rnd_t rnd; mp_prec_t prec; - r_mpfr_get_rnd_prec_from_optional_arguments(&rnd, &prec, 2, 4, argc, argv); + r_mpfr_get_rnd_prec_from_optional_arguments(&rnd, &prec, 1, 3, argc, argv); MPFR *ptr_arg1, *ptr_return1, *ptr_return2; VALUE val_ret1, val_ret2; volatile VALUE tmp_argv0 = r_mpfr_new_fr_obj(argv[0]); r_mpfr_get_struct(ptr_arg1, tmp_argv0); r_mpfr_make_struct_init2(val_ret1, ptr_return1, prec); @@ -2547,11 +2679,11 @@ /* Calculate sum of MPFR objects. */ static VALUE r_mpfr_math_sum(int argc, VALUE *argv, VALUE self){ int num; for (num = 0; num < argc; num += 1) { - if(!RTEST(rb_funcall(__mpfr_class__, eqq, 1, argv[num]))){ break; } + if(!MPFR_P(argv[num])){ break; } } mp_rnd_t rnd; mp_prec_t prec; r_mpfr_get_rnd_prec_from_optional_arguments(&rnd, &prec, num, num + 2, argc, argv); @@ -2708,10 +2840,49 @@ } } return self; } +/* Conversion to MPFR. */ + +/* Convert to MPFR. */ +static VALUE r_mpfr_float_to_fr (int argc, VALUE *argv, VALUE self) +{ + MPFR *ptr_return; + VALUE val_ret; + mp_rnd_t rnd; + mp_prec_t prec; + r_mpfr_get_rnd_prec_from_optional_arguments(&rnd, &prec, 0, 2, argc, argv); + r_mpfr_make_struct_init2(val_ret, ptr_return, prec); + mpfr_set_d(ptr_return, NUM2DBL(self), rnd); + return val_ret; +} + +/* Convert to MPFR. */ +static VALUE r_mpfr_fixnum_to_fr (int argc, VALUE *argv, VALUE self) +{ + MPFR *ptr_return; + VALUE val_ret; + mp_prec_t prec; + prec = r_mpfr_prec_from_optional_argument(0, 1, argc, argv); + r_mpfr_make_struct_init2(val_ret, ptr_return, prec); + mpfr_set_si(ptr_return, NUM2INT(self), MPFR_RNDN); + return val_ret; +} + +/* Convert to MPFR. */ +static VALUE r_mpfr_bignum_to_fr (int argc, VALUE *argv, VALUE self) +{ + MPFR *ptr_return; + VALUE val_ret; + mp_prec_t prec; + prec = r_mpfr_prec_from_optional_argument(0, 1, argc, argv); + r_mpfr_make_struct_init2(val_ret, ptr_return, prec); + r_mpfr_convert_to_str_set(ptr_return, self, MPFR_RNDN); + return val_ret; +} + void Init_mpfr() { /* ------------------------------ Class MPFR Start ------------------------------ */ /* @@ -2768,10 +2939,25 @@ == Conversion to String MPFR#to_s makes a string corresponding to mpfr_printf("%.Re", fr). If you want to adjust format of string, you can MPFR#to_strf. MPFR#to_strf(format) returns a string corresponding to mpfr_printf(format, fr). + + == Conversion to MPFR + + ruby-mpfr defines methods 'to_fr' for Float, Fixnum, and Bignum and + uses these methods to convert an object of MPFR. + In particular, MPFR() uses method 'to_fr'. + The method 'to_fr' must accept two optional arguments that are rounding mode and precision + if you want to define a method 'to_fr' for your class. + + == Conversion between MPFR and GMP (experimental) + + We can use ruby-mpfr with gmp bindings of ruby (https://github.com/srawlins/gmp). + If we add require 'mpfr/gmp' in ruby code, + some conversion methods between MPFR and GMP are added. + */ r_mpfr_class = rb_define_class("MPFR", rb_cNumeric); rb_include_module(r_mpfr_class, rb_mComparable); /* ------------------------------ Class MPFR End ------------------------------ */ @@ -2796,20 +2982,26 @@ /* Integer that is macro MPFR_EMAX_DEFAULT. */ rb_define_const(r_mpfr_class, "EMAX_DEFAULT", INT2NUM(MPFR_EMAX_DEFAULT)); /* Integer whichi is MPFR_EMIN_DEFAULT. */ rb_define_const(r_mpfr_class, "EMIN_DEFAULT", INT2NUM(MPFR_EMIN_DEFAULT)); + id_rndn = rb_intern("RNDN"); + id_rndz = rb_intern("RNDZ"); + id_rndu = rb_intern("RNDU"); + id_rndd = rb_intern("RNDD"); + id_rnda = rb_intern("RNDA"); + /* Integer that is macro MPFR_RNDN. */ - rb_define_const(r_mpfr_class, "RNDN", INT2NUM(MPFR_RNDN)); + rb_define_const(r_mpfr_class, "RNDN", ID2SYM(id_rndn)); /* Integer that is macro MPFR_RNDZ. */ - rb_define_const(r_mpfr_class, "RNDZ", INT2NUM(MPFR_RNDZ)); + rb_define_const(r_mpfr_class, "RNDZ", ID2SYM(id_rndz)); /* Integer that is macro MPFR_RNDU. */ - rb_define_const(r_mpfr_class, "RNDU", INT2NUM(MPFR_RNDU)); + rb_define_const(r_mpfr_class, "RNDU", ID2SYM(id_rndu)); /* Integer that is macro MPFR_RNDD. */ - rb_define_const(r_mpfr_class, "RNDD", INT2NUM(MPFR_RNDD)); + rb_define_const(r_mpfr_class, "RNDD", ID2SYM(id_rndd)); /* Integer that is macro MPFR_RNDD. */ - rb_define_const(r_mpfr_class, "RNDA", INT2NUM(MPFR_RNDA)); + rb_define_const(r_mpfr_class, "RNDA", ID2SYM(id_rnda)); /* ------------------------------ Constants End ------------------------------ */ rb_define_singleton_method(r_mpfr_class, "get_version", r_mpfr_get_version, 0); rb_define_singleton_method(r_mpfr_class, "get_patches", r_mpfr_get_patches, 0); @@ -3112,15 +3304,24 @@ /* ------------------------------ MPFR::Math Miscellaneous Functions End ------------------------------ */ /* ------------------------------ Module MPFR::Math End ------------------------------ */ + /* ------------------------------ Conversion to MPFR Start ------------------------------ */ + + rb_define_method(rb_cFloat, "to_fr", r_mpfr_float_to_fr, -1); + rb_define_method(rb_cFixnum, "to_fr", r_mpfr_fixnum_to_fr, -1); + rb_define_method(rb_cBignum, "to_fr", r_mpfr_bignum_to_fr, -1); + + /* ------------------------------ Conversion to MPFR End ------------------------------ */ + eqq = rb_intern("==="); to_s = rb_intern("to_s"); new = rb_intern("new"); class = rb_intern("class"); method_defined = rb_intern("method_defined?"); object_id = rb_intern("object_id"); + to_fr = rb_intern("to_fr"); __mpfr_class__ = rb_eval_string("MPFR"); __sym_to_s__ = rb_eval_string(":to_s"); __sym_to_str__ = rb_eval_string(":to_str");