Beispiel #1
0
/*
 *  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);
}
Beispiel #2
0
/*
 *  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);
}
Beispiel #3
0
/*
 *  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);
}
Beispiel #4
0
/*
 *  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);
}
Beispiel #5
0
OCINumber *oci8_set_integer(OCINumber *result, VALUE self, OCIError *errhp)
{
    OCINumber work;

    set_oci_number_from_num(&work, self, 1, errhp);
    chkerr(OCINumberTrunc(errhp, &work, 0, result));
    return result;
}
Beispiel #6
0
static void bind_integer_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
{
    OCIError *errhp = oci8_errhp;
    OCINumber num;

    set_oci_number_from_num(&num, val, 1, errhp);
    oci_lc(OCINumberTrunc(errhp, &num, 0, (OCINumber*)data));
}
Beispiel #7
0
/*
 *  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);
}
Beispiel #8
0
/*
 *  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);
}
Beispiel #9
0
static VALUE onum_initialize(int argc, VALUE *argv, VALUE self)
{
    OCIError *errhp = oci8_errhp;
    VALUE val;
    VALUE fmt;
    VALUE nls_params;

    if (rb_scan_args(argc, argv, "03", &val /* 0 */, &fmt /* nil */, &nls_params /* nil */) == 0) {
        OCINumberSetZero(errhp, _NUMBER(self));
    } else if (RTEST(rb_obj_is_kind_of(val, rb_cNumeric))) {
        set_oci_number_from_num(_NUMBER(self), val, 1, errhp);
    } else {
        set_oci_number_from_str(_NUMBER(self), val, fmt, nls_params, errhp);
    }
    return Qnil;
}
Beispiel #10
0
/*
 *  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);
}
Beispiel #11
0
/*
 *  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);
}
Beispiel #12
0
/*
 *  call-seq:
 *    onum <=> other   -> -1, 0, +1
 *
 *  Returns -1, 0, or +1 depending on whether <i>onum</i> is less than,
 *  equal to, or greater than <i>other</i>. This is the basis for the
 *  tests in <code>Comparable</code>.
 */
static VALUE onum_cmp(VALUE lhs, VALUE rhs)
{
    OCIError *errhp = oci8_errhp;
    OCINumber n;
    sword r;

    /* change to OCINumber */
    if (!set_oci_number_from_num(&n, rhs, 0, errhp))
        return rb_num_coerce_cmp(lhs, rhs, id_cmp);
    /* compare */
    chkerr(OCINumberCmp(errhp, _NUMBER(lhs), &n, &r));
    if (r > 0) {
        return INT2FIX(1);
    } else if (r == 0) {
        return INT2FIX(0);
    } else {
        return INT2FIX(-1);
    }
}
Beispiel #13
0
/*
 *  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);
}
Beispiel #14
0
OCINumber *oci8_set_ocinumber(OCINumber *result, VALUE self, OCIError *errhp)
{
    set_oci_number_from_num(result, self, 1, errhp);
    return result;
}
Beispiel #15
0
/* 1 - success, 0 - error */
static int set_oci_number_from_num(OCINumber *result, VALUE num, int force, OCIError *errhp)
{
    signed long sl;

    if (!RTEST(rb_obj_is_kind_of(num, rb_cNumeric)))
        rb_raise(rb_eTypeError, "expect Numeric but %s", rb_class2name(CLASS_OF(num)));
    if (rb_respond_to(num, id_finite_p) && !RTEST(rb_funcall(num, id_finite_p, 0))) {
        rb_raise(rb_eTypeError, "cannot accept number which isn't finite.");
    }
    switch (rb_type(num)) {
    case T_FIXNUM:
        /* set from long. */
        sl = NUM2LONG(num);
        chkerr(OCINumberFromInt(errhp, &sl, sizeof(sl), OCI_NUMBER_SIGNED, result));
        return 1;
    case T_FLOAT:
        /* set from double. */
        oci8_dbl_to_onum(result, NUM2DBL(num), errhp);
        return 1;
    case T_BIGNUM:
        /* change via string. */
        num = rb_big2str(num, 10);
        set_oci_number_from_str(result, num, Qnil, Qnil, errhp);
        return 1;
    }
    if (RTEST(rb_obj_is_instance_of(num, cOCINumber))) {
        /* OCI::Number */
        chkerr(OCINumberAssign(errhp, DATA_PTR(num), result));
        return 1;
    }
    if (rb_respond_to(num, id_split)) {
        /* BigDecimal */
        VALUE split = rb_funcall(num, id_split, 0);

        if (TYPE(split) == T_ARRAY && RARRAY_LEN(split) == 4) {
            /*
             * sign, significant_digits, base, exponent = num.split
             * onum = sign * "0.#{significant_digits}".to_f * (base ** exponent)
             */
            VALUE *ary = RARRAY_PTR(split);
            int sign;
            OCINumber digits;
            int exponent;
            int digits_len;
            OCINumber work;

            /* check sign */
            if (TYPE(ary[0]) != T_FIXNUM) {
                goto is_not_big_decimal;
            }
            sign = FIX2INT(ary[0]);
            /* check digits */
            StringValue(ary[1]);
            digits_len = RSTRING_LEN(ary[1]);
            set_oci_number_from_str(&digits, ary[1], Qnil, Qnil, errhp);
            /* check base */
            if (TYPE(ary[2]) != T_FIXNUM || FIX2LONG(ary[2]) != 10) {
                goto is_not_big_decimal;
            }
            /* check exponent */
            if (TYPE(ary[3]) != T_FIXNUM) {
                goto is_not_big_decimal;
            }
            exponent = FIX2INT(ary[3]);

            chkerr(OCINumberShift(errhp, &digits, exponent - digits_len, &work));
            if (sign >= 0) {
                chkerr(OCINumberAssign(errhp, &work, result));
            } else {
                chkerr(OCINumberNeg(errhp, &work, result));
            }
            return 1;
        }
    }
is_not_big_decimal:
    if (rb_respond_to(num, id_numerator) && rb_respond_to(num, id_denominator)) {
        /* Rational */
        OCINumber numerator;
        OCINumber denominator;

        if (set_oci_number_from_num(&numerator, rb_funcall(num, id_numerator, 0), 0, errhp) &&
            set_oci_number_from_num(&denominator, rb_funcall(num, id_denominator, 0), 0, errhp)) {
            chkerr(OCINumberDiv(errhp, &numerator, &denominator, result));
            return 1;
        }
    }
    if (force) {
        /* change via string as a last resort. */
        /* TODO: if error, raise TypeError instead of OCI::Error */
        set_oci_number_from_str(result, num, Qnil, Qnil, errhp);
        return 1;
    }
    return 0;
}
Beispiel #16
0
static void bind_ocinumber_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
{
    set_oci_number_from_num((OCINumber*)data, val, 1, oci8_errhp);
}