/* * call-seq: * onum * other -> number * * Returns the product of <i>onum</i> and <i>other</i>. */ static VALUE onum_mul(VALUE lhs, VALUE rhs) { OCIError *errhp = oci8_errhp; OCINumber n; OCINumber r; switch (rboci8_type(rhs)) { case T_FIXNUM: case T_BIGNUM: if (set_oci_number_from_num(&n, rhs, 0, errhp)) { chkerr(OCINumberMul(errhp, _NUMBER(lhs), &n, &r)); return oci8_make_ocinumber(&r, errhp); } break; case RBOCI8_T_ORANUMBER: chkerr(OCINumberMul(errhp, _NUMBER(lhs), _NUMBER(rhs), &r)); return oci8_make_ocinumber(&r, errhp); case T_FLOAT: return rb_funcall(onum_to_f(lhs), oci8_id_mul_op, 1, rhs); case RBOCI8_T_RATIONAL: return rb_funcall(onum_to_r(lhs), oci8_id_mul_op, 1, rhs); case RBOCI8_T_BIGDECIMAL: return rb_funcall(onum_to_d(lhs), oci8_id_mul_op, 1, rhs); } return rb_num_coerce_bin(lhs, rhs, oci8_id_mul_op); }
/* * call-seq: * OCI8::Math.atan2(y, x) -> oranumber * * Computes the arc tangent given <i>y</i> and <i>x</i>. Returns * -PI..PI. */ static VALUE omath_atan2(VALUE self, VALUE Ycoordinate, VALUE Xcoordinate) { OCIError *errhp = oci8_errhp; OCINumber nY; OCINumber nX; OCINumber rv; boolean is_zero; sword sign; set_oci_number_from_num(&nX, Xcoordinate, 1, errhp); set_oci_number_from_num(&nY, Ycoordinate, 1, errhp); /* check zero */ chkerr(OCINumberIsZero(errhp, &nX, &is_zero)); if (is_zero) { chkerr(OCINumberSign(errhp, &nY, &sign)); switch (sign) { case 0: return INT2FIX(0); /* atan2(0, 0) => 0 or ERROR? */ case 1: return oci8_make_ocinumber(&const_PI2, errhp); /* atan2(positive, 0) => PI/2 */ case -1: return oci8_make_ocinumber(&const_mPI2, errhp); /* atan2(negative, 0) => -PI/2 */ } } /* atan2 */ chkerr(OCINumberArcTan2(errhp, &nY, &nX, &rv)); return oci8_make_ocinumber(&rv, errhp); }
static VALUE onum_coerce(VALUE self, VALUE other) { signed long sl; OCINumber n; switch(rboci8_type(other)) { case T_FIXNUM: sl = NUM2LONG(other); chkerr(OCINumberFromInt(oci8_errhp, &sl, sizeof(sl), OCI_NUMBER_SIGNED, &n)); return rb_assoc_new(oci8_make_ocinumber(&n, oci8_errhp), self); case T_BIGNUM: /* change via string. */ other = rb_big2str(other, 10); set_oci_number_from_str(&n, other, Qnil, Qnil, oci8_errhp); return rb_assoc_new(oci8_make_ocinumber(&n, oci8_errhp), self); case T_FLOAT: return rb_assoc_new(other, onum_to_f(self)); case RBOCI8_T_RATIONAL: return rb_assoc_new(other, onum_to_r(self)); case RBOCI8_T_BIGDECIMAL: return rb_assoc_new(other, onum_to_d(self)); } rb_raise(rb_eTypeError, "Can't coerce %s to %s", rb_class2name(CLASS_OF(other)), rb_class2name(cOCINumber)); }
/* * call-seq: * onum / integer -> oranumber * onum / numeric -> numeric * * Returns the result of dividing <i>onum</i> by <i>other</i>. */ static VALUE onum_div(VALUE lhs, VALUE rhs) { OCIError *errhp = oci8_errhp; OCINumber n; OCINumber r; boolean is_zero; switch (rboci8_type(rhs)) { case T_FIXNUM: if (rhs == INT2FIX(0)) { rb_num_zerodiv(); } case T_BIGNUM: if (set_oci_number_from_num(&n, rhs, 0, errhp)) { chkerr(OCINumberDiv(errhp, _NUMBER(lhs), &n, &r)); return oci8_make_ocinumber(&r, errhp); } break; case RBOCI8_T_ORANUMBER: chkerr(OCINumberIsZero(errhp, _NUMBER(rhs), &is_zero)); if (is_zero) { rb_num_zerodiv(); } chkerr(OCINumberDiv(errhp, _NUMBER(lhs), _NUMBER(rhs), &r)); return oci8_make_ocinumber(&r, errhp); case T_FLOAT: return rb_funcall(onum_to_f(lhs), oci8_id_div_op, 1, rhs); case RBOCI8_T_RATIONAL: return rb_funcall(onum_to_r(lhs), oci8_id_div_op, 1, rhs); case RBOCI8_T_BIGDECIMAL: return rb_funcall(onum_to_d(lhs), oci8_id_div_op, 1, rhs); } return rb_num_coerce_bin(lhs, rhs, oci8_id_div_op); }
/* * call-seq: * OCI8::Math.log(numeric) -> oranumber * OCI8::Math.log(numeric, base_num) -> oranumber * * Returns the natural logarithm of <i>numeric</i> for one argument. * Returns the base <i>base_num</i> logarithm of <i>numeric</i> for two arguments. */ static VALUE omath_log(int argc, VALUE *argv, VALUE obj) { OCIError *errhp = oci8_errhp; VALUE num, base; OCINumber n; OCINumber b; OCINumber r; sword sign; rb_scan_args(argc, argv, "11", &num, &base); set_oci_number_from_num(&n, num, 1, errhp); chkerr(OCINumberSign(errhp, &n, &sign)); if (sign <= 0) rb_raise(rb_eRangeError, "nonpositive value for log"); if (NIL_P(base)) { chkerr(OCINumberLn(errhp, &n, &r)); } else { set_oci_number_from_num(&b, base, 1, errhp); chkerr(OCINumberSign(errhp, &b, &sign)); if (sign <= 0) rb_raise(rb_eRangeError, "nonpositive value for the base of log"); chkerr(OCINumberCmp(errhp, &b, &const_p1, &sign)); if (sign == 0) rb_raise(rb_eRangeError, "base 1 for log"); chkerr(OCINumberLog(errhp, &b, &n, &r)); } return oci8_make_ocinumber(&r, errhp); }
/* * call-seq: * -onum -> oranumber * * Returns a negated <code>OraNumber</code>. */ static VALUE onum_neg(VALUE self) { OCIError *errhp = oci8_errhp; OCINumber r; chkerr(OCINumberNeg(errhp, _NUMBER(self), &r)); return oci8_make_ocinumber(&r, errhp); }
/* * call-seq: * onum.shift(fixnum) -> oranumber * * Returns <i>onum</i> * 10**<i>fixnum</i> * This method is available on Oracle 8.1 client or upper. */ static VALUE onum_shift(VALUE self, VALUE exp) { OCIError *errhp = oci8_errhp; OCINumber result; chkerr(OCINumberShift(errhp, _NUMBER(self), NUM2INT(exp), &result)); return oci8_make_ocinumber(&result, errhp); }
/* * call-seq: * onum.abs -> oranumber * * Returns the absolute value of <i>onum</i>. * */ static VALUE onum_abs(VALUE self) { OCIError *errhp = oci8_errhp; OCINumber result; chkerr(OCINumberAbs(errhp, _NUMBER(self), &result)); return oci8_make_ocinumber(&result, errhp); }
/* * call-seq: * onum.round_prec(digits) -> oranumber * * Rounds <i>onum</i> to a specified number of decimal digits. * This method is available on Oracle 8.1 client or upper. * * OraNumber.new(1.234).round_prec(2) #=> 1.2 * OraNumber.new(12.34).round_prec(2) #=> 12 * OraNumber.new(123.4).round_prec(2) #=> 120 */ static VALUE onum_round_prec(VALUE self, VALUE ndigs) { OCIError *errhp = oci8_errhp; OCINumber r; chkerr(OCINumberPrec(errhp, _NUMBER(self), NUM2INT(ndigs), &r)); return oci8_make_ocinumber(&r, errhp); }
/* * call-seq: * OCI8::Math.tanh() -> oranumber * * Computes the hyperbolic tangent of <i>x</i> (expressed in * radians). */ static VALUE omath_tanh(VALUE obj, VALUE num) { OCIError *errhp = oci8_errhp; OCINumber n; OCINumber r; oci_lc(OCINumberHypTan(errhp, TO_OCINUM(&n, num, errhp), &r)); return oci8_make_ocinumber(&r, errhp); }
/* * call-seq: * OCI8::Math.tan(x) -> oranumber * * Returns the tangent of <i>x</i> (expressed in radians). */ static VALUE omath_tan(VALUE obj, VALUE radian) { OCIError *errhp = oci8_errhp; OCINumber r; OCINumber rv; chkerr(OCINumberTan(errhp, TO_OCINUM(&r, radian, errhp), &rv)); return oci8_make_ocinumber(&rv, errhp); }
/* * call-seq: * OCI8::Math.cos(x) -> oranumber * * Computes the cosine of <i>x</i> (expressed in radians). Returns * -1..1. */ static VALUE omath_cos(VALUE obj, VALUE radian) { OCIError *errhp = oci8_errhp; OCINumber r; OCINumber rv; oci_lc(OCINumberCos(errhp, TO_OCINUM(&r, radian, errhp), &rv)); return oci8_make_ocinumber(&rv, errhp); }
/* * call-seq: * OCI8::Math.exp(x) -> oranumber * * Returns e**x. */ static VALUE omath_exp(VALUE obj, VALUE num) { OCIError *errhp = oci8_errhp; OCINumber n; OCINumber r; chkerr(OCINumberExp(errhp, TO_OCINUM(&n, num, errhp), &r)); return oci8_make_ocinumber(&r, errhp); }
/* * call-seq: * onum.truncate -> integer * onum.truncate(decplace) -> oranumber * * Truncates <i>onum</i> to the <code>Integer</code> when no argument. * Truncates <i>onum</i> to a specified decimal place <i>decplace</i> when one argument. */ static VALUE onum_trunc(int argc, VALUE *argv, VALUE self) { OCIError *errhp = oci8_errhp; VALUE decplace; OCINumber r; rb_scan_args(argc, argv, "01", &decplace /* 0 */); chkerr(OCINumberTrunc(errhp, _NUMBER(self), NIL_P(decplace) ? 0 : NUM2INT(decplace), &r)); return oci8_make_ocinumber(&r, errhp); }
/* * call-seq: * onum.round -> integer * onum.round(decplace) -> oranumber * * Rounds <i>onum</i> to the nearest <code>Integer</code> when no argument. * Rounds <i>onum</i> to a specified decimal place <i>decplace</i> when one argument. * * OraNumber.new(1.234).round(1) #=> 1.2 * OraNumber.new(1.234).round(2) #=> 1.23 * OraNumber.new(1.234).round(3) #=> 1.234 */ static VALUE onum_round(int argc, VALUE *argv, VALUE self) { OCIError *errhp = oci8_errhp; VALUE decplace; OCINumber r; rb_scan_args(argc, argv, "01", &decplace /* 0 */); chkerr(OCINumberRound(errhp, _NUMBER(self), NIL_P(decplace) ? 0 : NUM2INT(decplace), &r)); if (argc == 0) { return oci8_make_integer(&r, errhp); } else { return oci8_make_ocinumber(&r, errhp); } }
/* * call-seq: * OCI8::Math.log10(numeric) -> oranumber * * Returns the base 10 logarithm of <i>numeric</i>. */ static VALUE omath_log10(VALUE obj, VALUE num) { OCIError *errhp = oci8_errhp; OCINumber n; OCINumber r; sword sign; set_oci_number_from_num(&n, num, 1, errhp); chkerr(OCINumberSign(errhp, &n, &sign)); if (sign <= 0) rb_raise(rb_eRangeError, "nonpositive value for log10"); chkerr(OCINumberLog(errhp, &const_p10, &n, &r)); return oci8_make_ocinumber(&r, errhp); }
/* * call-seq: * onum ** other -> oranumber * * Raises <i>onum</i> the <i>other</i> power. */ static VALUE onum_power(VALUE lhs, VALUE rhs) { OCIError *errhp = oci8_errhp; OCINumber n; OCINumber r; if (FIXNUM_P(rhs)) { chkerr(OCINumberIntPower(errhp, _NUMBER(lhs), FIX2INT(rhs), &r)); } else { /* change to OCINumber */ if (!set_oci_number_from_num(&n, rhs, 0, errhp)) return rb_num_coerce_bin(lhs, rhs, id_power); chkerr(OCINumberPower(errhp, _NUMBER(lhs), &n, &r)); } return oci8_make_ocinumber(&r, errhp); }
/* * call-seq: * OraNumber._load(string) -> oranumber * * Unmarshal a dumped <code>OraNumber</code> object. */ static VALUE onum_s_load(VALUE klass, VALUE str) { unsigned char *c; size_t size; OCINumber num; Check_Type(str, T_STRING); c = RSTRING_ORATEXT(str); size = RSTRING_LEN(str); if (size == 0 || size != c[0] + 1u || size > sizeof(num)) { rb_raise(rb_eTypeError, "marshaled OCI::Number format differ"); } memset(&num, 0, sizeof(num)); memcpy(&num, c, size); return oci8_make_ocinumber(&num, oci8_errhp); }
/* * call-seq: * OCI8::Math.sqrt(numeric) -> oranumber * * Returns the non-negative square root of <i>numeric</i>. */ static VALUE omath_sqrt(VALUE obj, VALUE num) { OCIError *errhp = oci8_errhp; OCINumber n; OCINumber r; sword sign; set_oci_number_from_num(&n, num, 1, errhp); /* check whether num is negative */ chkerr(OCINumberSign(errhp, &n, &sign)); if (sign < 0) { errno = EDOM; rb_sys_fail("sqrt"); } chkerr(OCINumberSqrt(errhp, &n, &r)); return oci8_make_ocinumber(&r, errhp); }
/* * call-seq: * onum % other -> oranumber * * Returns the modulo after division of <i>onum</i> by <i>other</i>. */ static VALUE onum_mod(VALUE lhs, VALUE rhs) { OCIError *errhp = oci8_errhp; OCINumber n; OCINumber r; boolean is_zero; /* change to OCINumber */ if (!set_oci_number_from_num(&n, rhs, 0, errhp)) return rb_num_coerce_bin(lhs, rhs, '%'); /* check whether argument is not zero. */ chkerr(OCINumberIsZero(errhp, &n, &is_zero)); if (is_zero) rb_num_zerodiv(); /* modulo */ chkerr(OCINumberMod(errhp, _NUMBER(lhs), &n, &r)); return oci8_make_ocinumber(&r, errhp); }
/* * call-seq: * OCI8::Math.asin(x) -> oranumber * * Computes the arc sine of <i>x</i>. Returns 0..PI. */ static VALUE omath_asin(VALUE obj, VALUE num) { OCIError *errhp = oci8_errhp; OCINumber n; OCINumber r; sword sign; set_oci_number_from_num(&n, num, 1, errhp); /* check upper bound */ chkerr(OCINumberCmp(errhp, &n, &const_p1, &sign)); if (sign > 0) rb_raise(rb_eRangeError, "out of range for asin"); /* check lower bound */ chkerr(OCINumberCmp(errhp, &n, &const_m1, &sign)); if (sign < 0) rb_raise(rb_eRangeError, "out of range for asin"); /* asin */ chkerr(OCINumberArcSin(errhp, &n, &r)); return oci8_make_ocinumber(&r, errhp); }
/* * bind_ocinumber */ static VALUE bind_ocinumber_get(oci8_bind_t *obind, void *data, void *null_struct) { return oci8_make_ocinumber((OCINumber*)data, oci8_errhp); }
void Init_oci_number(VALUE cOCI8, OCIError *errhp) { VALUE mMath; OCINumber num1, num2; VALUE obj_PI; signed long sl; id_power = rb_intern("**"); id_cmp = rb_intern("<=>"); id_finite_p = rb_intern("finite?"); id_split = rb_intern("split"); id_numerator = rb_intern("numerator"); id_denominator = rb_intern("denominator"); id_Rational = rb_intern("Rational"); id_BigDecimal = rb_intern("BigDecimal"); cOCINumber = rb_define_class("OraNumber", rb_cNumeric); mMath = rb_define_module_under(cOCI8, "Math"); /* constants for internal use. */ /* set const_p1 */ sl = 1; OCINumberFromInt(errhp, &sl, sizeof(sl), OCI_NUMBER_SIGNED, &const_p1); /* set const_p10 */ sl = 10; OCINumberFromInt(errhp, &sl, sizeof(sl), OCI_NUMBER_SIGNED, &const_p10); /* set const_m1 */ sl = -1; OCINumberFromInt(errhp, &sl, sizeof(sl), OCI_NUMBER_SIGNED, &const_m1); /* set const_PI2 */ sl = 2; OCINumberSetPi(errhp, &num1); OCINumberFromInt(errhp, &sl, sizeof(sl), OCI_NUMBER_SIGNED, &num2); OCINumberDiv(errhp, &num1 /* PI */, &num2 /* 2 */, &const_PI2); /* set const_mPI2 */ OCINumberNeg(errhp, &const_PI2 /* PI/2 */, &const_mPI2); /* PI */ OCINumberSetPi(errhp, &num1); obj_PI = oci8_make_ocinumber(&num1, errhp); /* The ratio of the circumference of a circle to its diameter. */ rb_define_const(mMath, "PI", obj_PI); /* * module functions of OCI::Math. */ rb_define_module_function(mMath, "atan2", omath_atan2, 2); rb_define_module_function(mMath, "cos", omath_cos, 1); rb_define_module_function(mMath, "sin", omath_sin, 1); rb_define_module_function(mMath, "tan", omath_tan, 1); rb_define_module_function(mMath, "acos", omath_acos, 1); rb_define_module_function(mMath, "asin", omath_asin, 1); rb_define_module_function(mMath, "atan", omath_atan, 1); rb_define_module_function(mMath, "cosh", omath_cosh, 1); rb_define_module_function(mMath, "sinh", omath_sinh, 1); rb_define_module_function(mMath, "tanh", omath_tanh, 1); rb_define_module_function(mMath, "exp", omath_exp, 1); rb_define_module_function(mMath, "log", omath_log, -1); rb_define_module_function(mMath, "log10", omath_log10, 1); rb_define_module_function(mMath, "sqrt", omath_sqrt, 1); rb_define_alloc_func(cOCINumber, onum_s_alloc); /* methods of OCI::Number */ rb_define_method(rb_cObject, "OraNumber", onum_f_new, -1); rb_define_method_nodoc(cOCINumber, "initialize", onum_initialize, -1); rb_define_method_nodoc(cOCINumber, "initialize_copy", onum_initialize_copy, 1); rb_define_method_nodoc(cOCINumber, "coerce", onum_coerce, 1); rb_include_module(cOCINumber, rb_mComparable); rb_define_method(cOCINumber, "-@", onum_neg, 0); rb_define_method(cOCINumber, "+", onum_add, 1); rb_define_method(cOCINumber, "-", onum_sub, 1); rb_define_method(cOCINumber, "*", onum_mul, 1); rb_define_method(cOCINumber, "/", onum_div, 1); rb_define_method(cOCINumber, "%", onum_mod, 1); rb_define_method(cOCINumber, "**", onum_power, 1); rb_define_method(cOCINumber, "<=>", onum_cmp, 1); rb_define_method(cOCINumber, "floor", onum_floor, 0); rb_define_method(cOCINumber, "ceil", onum_ceil, 0); rb_define_method(cOCINumber, "round", onum_round, -1); rb_define_method(cOCINumber, "truncate", onum_trunc, -1); rb_define_method(cOCINumber, "round_prec", onum_round_prec, 1); rb_define_method(cOCINumber, "to_s", onum_to_s, 0); rb_define_method(cOCINumber, "to_char", onum_to_char, -1); rb_define_method(cOCINumber, "to_i", onum_to_i, 0); rb_define_method(cOCINumber, "to_f", onum_to_f, 0); rb_define_method(cOCINumber, "to_r", onum_to_r, 0); rb_define_method(cOCINumber, "to_d", onum_to_d, 0); rb_define_method(cOCINumber, "has_decimal_part?", onum_has_decimal_part_p, 0); rb_define_method_nodoc(cOCINumber, "to_onum", onum_to_onum, 0); rb_define_method(cOCINumber, "zero?", onum_zero_p, 0); rb_define_method(cOCINumber, "abs", onum_abs, 0); rb_define_method(cOCINumber, "shift", onum_shift, 1); rb_define_method(cOCINumber, "dump", onum_dump, 0); rb_define_method_nodoc(cOCINumber, "hash", onum_hash, 0); rb_define_method_nodoc(cOCINumber, "inspect", onum_inspect, 0); /* methods for marshaling */ rb_define_method(cOCINumber, "_dump", onum__dump, -1); rb_define_singleton_method(cOCINumber, "_load", onum_s_load, 1); oci8_define_bind_class("OraNumber", &bind_ocinumber_vtable); oci8_define_bind_class("Integer", &bind_integer_vtable); oci8_define_bind_class("Float", &bind_float_vtable); }