首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

BigMath

提供数学函数。

例:

代码语言:javascript
复制
require "bigdecimal/math"

include BigMath

a = BigDecimal((PI(100)/2).to_s)
puts sin(a,100) # => 0.99999999999999999999......e0

公共类方法

exp(十进制,数字)→BigDecimal显示源

计算e(自然对数的底数)的值decimal增加到指定的精度位数。

如果decimal是无穷大,则返回Infinity。

如果decimal是NaN,则返回NaN。

代码语言:javascript
复制
static VALUE
BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
{
    ssize_t prec, n, i;
    Real* vx = NULL;
    VALUE one, d, y;
    int negative = 0;
    int infinite = 0;
    int nan = 0;
    double flo;

    prec = NUM2SSIZET(vprec);
    if (prec <= 0) {
        rb_raise(rb_eArgError, "Zero or negative precision for exp");
    }

    /* TODO: the following switch statement is almost same as one in the
     *       BigDecimalCmp function. */
    switch (TYPE(x)) {
      case T_DATA:
        if (!is_kind_of_BigDecimal(x)) break;
        vx = DATA_PTR(x);
        negative = BIGDECIMAL_NEGATIVE_P(vx);
        infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
        nan = VpIsNaN(vx);
        break;

      case T_FIXNUM:
        /* fall through */
      case T_BIGNUM:
        vx = GetVpValue(x, 0);
        break;

      case T_FLOAT:
        flo = RFLOAT_VALUE(x);
        negative = flo < 0;
        infinite = isinf(flo);
        nan = isnan(flo);
        if (!infinite && !nan) {
            vx = GetVpValueWithPrec(x, DBL_DIG+1, 0);
        }
        break;

      case T_RATIONAL:
        vx = GetVpValueWithPrec(x, prec, 0);
        break;

      default:
        break;
    }
    if (infinite) {
        if (negative) {
            return ToValue(GetVpValueWithPrec(INT2FIX(0), prec, 1));
        }
        else {
            Real* vy;
            vy = VpCreateRbObject(prec, "#0");
            VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
            RB_GC_GUARD(vy->obj);
            return ToValue(vy);
        }
    }
    else if (nan) {
        Real* vy;
        vy = VpCreateRbObject(prec, "#0");
        VpSetNaN(vy);
        RB_GC_GUARD(vy->obj);
        return ToValue(vy);
    }
    else if (vx == NULL) {
        cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
    }
    x = vx->obj;

    n = prec + rmpd_double_figures();
    negative = BIGDECIMAL_NEGATIVE_P(vx);
    if (negative) {
        VpSetSign(vx, 1);
    }

    one = ToValue(VpCreateRbObject(1, "1"));
    y   = one;
    d   = y;
    i   = 1;

    while (!VpIsZero((Real*)DATA_PTR(d))) {
        SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
        SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
        ssize_t m = n - vabs(ey - ed);

        rb_thread_check_ints();

        if (m <= 0) {
            break;
        }
        else if ((size_t)m < rmpd_double_figures()) {
            m = rmpd_double_figures();
        }

        d = BigDecimal_mult(d, x);                             /* d <- d * x */
        d = BigDecimal_div2(d, SSIZET2NUM(i), SSIZET2NUM(m));  /* d <- d / i */
        y = BigDecimal_add(y, d);                              /* y <- y + d  */
        ++i;                                                   /* i  <- i + 1 */
    }

    if (negative) {
        return BigDecimal_div2(one, y, vprec);
    }
    else {
        vprec = SSIZET2NUM(prec - VpExponent10(DATA_PTR(y)));
        return BigDecimal_round(1, &vprec, y);
    }

    RB_GC_GUARD(one);
    RB_GC_GUARD(x);
    RB_GC_GUARD(y);
    RB_GC_GUARD(d);
}

日志(十进制,数字)→BigDecimal显示源

计算decimal精度的指定位数的自然对数numeric

如果decimal是零或负数,则引发Math :: DomainError。

如果decimal是正无穷,则返回Infinity。

如果decimal是NaN,则返回NaN。

代码语言:javascript
复制
static VALUE
BigMath_s_log(VALUE klass, VALUE x, VALUE vprec)
{
    ssize_t prec, n, i;
    SIGNED_VALUE expo;
    Real* vx = NULL;
    VALUE vn, one, two, w, x2, y, d;
    int zero = 0;
    int negative = 0;
    int infinite = 0;
    int nan = 0;
    double flo;
    long fix;

    if (!is_integer(vprec)) {
        rb_raise(rb_eArgError, "precision must be an Integer");
    }

    prec = NUM2SSIZET(vprec);
    if (prec <= 0) {
        rb_raise(rb_eArgError, "Zero or negative precision for exp");
    }

    /* TODO: the following switch statement is almost same as one in the
     *       BigDecimalCmp function. */
    switch (TYPE(x)) {
      case T_DATA:
          if (!is_kind_of_BigDecimal(x)) break;
          vx = DATA_PTR(x);
          zero = VpIsZero(vx);
          negative = BIGDECIMAL_NEGATIVE_P(vx);
          infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
          nan = VpIsNaN(vx);
          break;

      case T_FIXNUM:
        fix = FIX2LONG(x);
        zero = fix == 0;
        negative = fix < 0;
        goto get_vp_value;

      case T_BIGNUM:
        i = FIX2INT(rb_big_cmp(x, INT2FIX(0)));
        zero = i == 0;
        negative = i < 0;
get_vp_value:
        if (zero || negative) break;
        vx = GetVpValue(x, 0);
        break;

      case T_FLOAT:
        flo = RFLOAT_VALUE(x);
        zero = flo == 0;
        negative = flo < 0;
        infinite = isinf(flo);
        nan = isnan(flo);
        if (!zero && !negative && !infinite && !nan) {
            vx = GetVpValueWithPrec(x, DBL_DIG+1, 1);
        }
        break;

      case T_RATIONAL:
        zero = RRATIONAL_ZERO_P(x);
        negative = RRATIONAL_NEGATIVE_P(x);
        if (zero || negative) break;
        vx = GetVpValueWithPrec(x, prec, 1);
        break;

      case T_COMPLEX:
        rb_raise(rb_eMathDomainError,
                 "Complex argument for BigMath.log");

      default:
        break;
    }
    if (infinite && !negative) {
        Real* vy;
        vy = VpCreateRbObject(prec, "#0");
        RB_GC_GUARD(vy->obj);
        VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
        return ToValue(vy);
    }
    else if (nan) {
        Real* vy;
        vy = VpCreateRbObject(prec, "#0");
        RB_GC_GUARD(vy->obj);
        VpSetNaN(vy);
        return ToValue(vy);
    }
    else if (zero || negative) {
        rb_raise(rb_eMathDomainError,
                 "Zero or negative argument for log");
    }
    else if (vx == NULL) {
        cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
    }
    x = ToValue(vx);

    RB_GC_GUARD(one) = ToValue(VpCreateRbObject(1, "1"));
    RB_GC_GUARD(two) = ToValue(VpCreateRbObject(1, "2"));

    n = prec + rmpd_double_figures();
    RB_GC_GUARD(vn) = SSIZET2NUM(n);
    expo = VpExponent10(vx);
    if (expo < 0 || expo >= 3) {
        char buf[DECIMAL_SIZE_OF_BITS(SIZEOF_VALUE * CHAR_BIT) + 4];
        snprintf(buf, sizeof(buf), "1E%"PRIdVALUE, -expo);
        x = BigDecimal_mult2(x, ToValue(VpCreateRbObject(1, buf)), vn);
    }
    else {
        expo = 0;
    }
    w = BigDecimal_sub(x, one);
    x = BigDecimal_div2(w, BigDecimal_add(x, one), vn);
    RB_GC_GUARD(x2) = BigDecimal_mult2(x, x, vn);
    RB_GC_GUARD(y)  = x;
    RB_GC_GUARD(d)  = y;
    i = 1;
    while (!VpIsZero((Real*)DATA_PTR(d))) {
        SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
        SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
        ssize_t m = n - vabs(ey - ed);
        if (m <= 0) {
            break;
        }
        else if ((size_t)m < rmpd_double_figures()) {
            m = rmpd_double_figures();
        }

        x = BigDecimal_mult2(x2, x, vn);
        i += 2;
        d = BigDecimal_div2(x, SSIZET2NUM(i), SSIZET2NUM(m));
        y = BigDecimal_add(y, d);
    }

    y = BigDecimal_mult(y, two);
    if (expo != 0) {
        VALUE log10, vexpo, dy;
        log10 = BigMath_s_log(klass, INT2FIX(10), vprec);
        vexpo = ToValue(GetVpValue(SSIZET2NUM(expo), 1));
        dy = BigDecimal_mult(log10, vexpo);
        y = BigDecimal_add(y, dy);
    }

    return y;
}

公共实例方法

E(数字)→BigDecimal显示源

计算e(自然对数的底数)为指定的精度位数,numeric

代码语言:javascript
复制
BigMath.E(10).to_s
#=> "0.271828182845904523536028752390026306410273e1"
代码语言:javascript
复制
# File ext/bigdecimal/lib/bigdecimal/math.rb, line 227
def E(prec)
  raise ArgumentError, "Zero or negative precision for E" if prec <= 0
  BigMath.exp(1, prec)
end

PI(数字)→BigDecimal显示源

计算pi的值到指定的精度位数,numeric

代码语言:javascript
复制
BigMath.PI(10).to_s
#=> "0.3141592653589793238462643388813853786957412e1"
代码语言:javascript
复制
# File ext/bigdecimal/lib/bigdecimal/math.rb, line 182
def PI(prec)
  raise ArgumentError, "Zero or negative precision for PI" if prec <= 0
  n      = prec + BigDecimal.double_fig
  zero   = BigDecimal("0")
  one    = BigDecimal("1")
  two    = BigDecimal("2")

  m25    = BigDecimal("-0.04")
  m57121 = BigDecimal("-57121")

  pi     = zero

  d = one
  k = one
  t = BigDecimal("-80")
  while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
    m = BigDecimal.double_fig if m < BigDecimal.double_fig
    t   = t*m25
    d   = t.div(k,m)
    k   = k+two
    pi  = pi + d
  end

  d = one
  k = one
  t = BigDecimal("956")
  while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
    m = BigDecimal.double_fig if m < BigDecimal.double_fig
    t   = t.div(m57121,n)
    d   = t.div(k,m)
    pi  = pi + d
    k   = k+two
  end
  pi
end

atan(十进制,数字)→BigDecimal显示源

计算decimal精度的指定位数的反正切值numeric

如果decimal是NaN,则返回NaN。

代码语言:javascript
复制
BigMath.atan(BigDecimal.new('-1'), 16).to_s
#=> "-0.785398163397448309615660845819878471907514682065e0"
代码语言:javascript
复制
# File ext/bigdecimal/lib/bigdecimal/math.rb, line 145
def atan(x, prec)
  raise ArgumentError, "Zero or negative precision for atan" if prec <= 0
  return BigDecimal("NaN") if x.nan?
  pi = PI(prec)
  x = -x if neg = x < 0
  return pi.div(neg ? -2 : 2, prec) if x.infinite?
  return pi / (neg ? -4 : 4) if x.round(prec) == 1
  x = BigDecimal("1").div(x, prec) if inv = x > 1
  x = (-1 + sqrt(1 + x**2, prec))/x if dbl = x > 0.5
  n    = prec + BigDecimal.double_fig
  y = x
  d = y
  t = x
  r = BigDecimal("3")
  x2 = x.mult(x,n)
  while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
    m = BigDecimal.double_fig if m < BigDecimal.double_fig
    t = -t.mult(x2,n)
    d = t.div(r,m)
    y += d
    r += 2
  end
  y *= 2 if dbl
  y = pi / 2 - y if inv
  y = -y if neg
  y
end

cos(十进制,数字)→BigDecimal显示源

计算decimal精度的指定位数的余弦值,numeric

如果decimal是Infinity或NaN,则返回NaN。

代码语言:javascript
复制
BigMath.cos(BigMath.PI(4), 16).to_s
#=> "-0.999999999999999999999999999999856613163740061349e0"
代码语言:javascript
复制
# File ext/bigdecimal/lib/bigdecimal/math.rb, line 101
def cos(x, prec)
  raise ArgumentError, "Zero or negative precision for cos" if prec <= 0
  return BigDecimal("NaN") if x.infinite? || x.nan?
  n    = prec + BigDecimal.double_fig
  one  = BigDecimal("1")
  two  = BigDecimal("2")
  x = -x if x < 0
  if x > (twopi = two * BigMath.PI(prec))
    if x > 30
      x = twopi
    else
      x -= twopi while x > twopi
    end
  end
  x1 = one
  x2 = x.mult(x,n)
  sign = 1
  y = one
  d = y
  i = BigDecimal("0")
  z = one
  while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
    m = BigDecimal.double_fig if m < BigDecimal.double_fig
    sign = -sign
    x1  = x2.mult(x1,n)
    i  += two
    z  *= (i-one) * i
    d   = sign * x1.div(z,m)
    y  += d
  end
  y
end

sin(十进制,数字)→BigDecimal显示源

计算decimal精度的指定位数的正弦值,numeric

如果decimal是Infinity或NaN,则返回NaN。

代码语言:javascript
复制
BigMath.sin(BigMath.PI(5)/4, 5).to_s
#=> "0.70710678118654752440082036563292800375e0"
代码语言:javascript
复制
# File ext/bigdecimal/lib/bigdecimal/math.rb, line 57
def sin(x, prec)
  raise ArgumentError, "Zero or negative precision for sin" if prec <= 0
  return BigDecimal("NaN") if x.infinite? || x.nan?
  n    = prec + BigDecimal.double_fig
  one  = BigDecimal("1")
  two  = BigDecimal("2")
  x = -x if neg = x < 0
  if x > (twopi = two * BigMath.PI(prec))
    if x > 30
      x = twopi
    else
      x -= twopi while x > twopi
    end
  end
  x1   = x
  x2   = x.mult(x,n)
  sign = 1
  y    = x
  d    = y
  i    = one
  z    = one
  while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
    m = BigDecimal.double_fig if m < BigDecimal.double_fig
    sign = -sign
    x1  = x2.mult(x1,n)
    i  += two
    z  *= (i-one) * i
    d   = sign * x1.div(z,m)
    y  += d
  end
  neg ? -y : y
end

sqrt(十进制,数字)→BigDecimal显示源

计算decimal精度的指定位数的平方根,numeric

代码语言:javascript
复制
BigMath.sqrt(BigDecimal.new('2'), 16).to_s
#=> "0.1414213562373095048801688724e1"
代码语言:javascript
复制
# File ext/bigdecimal/lib/bigdecimal/math.rb, line 42
def sqrt(x, prec)
  x.sqrt(prec)
end

扫码关注腾讯云开发者

领取腾讯云代金券