Extended maintenance of Ruby 1.9.3 ended on February 23, 2015. Read more

In Files

• bigdecimal/bigdecimal.c
• bigdecimal/lib/bigdecimal/math.rb

Quicksearch

BigMath

mathematical functions

Provides mathematical functions.

Example:

```require "bigdecimal"
require "bigdecimal/math"

include BigMath

a = BigDecimal((PI(100)/2).to_s)
puts sin(a,100) # -> 0.10000000000000000000......E1
```

Public Class Methods

exp(x, prec) click to toggle source

Computes the value of e (the base of natural logarithms) raised to the power of x, to the specified number of digits of precision.

If x is infinite, returns Infinity.

If x is NaN, returns NaN.

```
static VALUE
BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
{
ssize_t prec, n, i;
Real* vx = NULL;
VALUE one, d, x1, y, z;
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 almostly the 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 = VpGetSign(vx) < 0;
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) {
}
else {
Real* vy;
vy = VpCreateRbObject(prec, "#0");
RB_GC_GUARD(vy->obj);
VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
}
}
else if (nan) {
Real* vy;
vy = VpCreateRbObject(prec, "#0");
RB_GC_GUARD(vy->obj);
VpSetNaN(vy);
}
else if (vx == NULL) {
cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
}
x = RB_GC_GUARD(vx->obj);

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

RB_GC_GUARD(one) = ToValue(VpCreateRbObject(1, "1"));
RB_GC_GUARD(x1) = one;
RB_GC_GUARD(y)  = one;
RB_GC_GUARD(d)  = y;
RB_GC_GUARD(z)  = one;
i  = 0;

while (!VpIsZero((Real*)DATA_PTR(d))) {
VALUE argv[2];
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();
}

x1 = BigDecimal_mult2(x1, x, SSIZET2NUM(n));
++i;
z = BigDecimal_mult(z, SSIZET2NUM(i));
argv[0] = z;
argv[1] = SSIZET2NUM(m);
d = BigDecimal_div2(2, argv, x1);
}

if (negative) {
VALUE argv[2];
argv[0] = y;
argv[1] = vprec;
return BigDecimal_div2(2, argv, one);
}
else {
vprec = SSIZET2NUM(prec - VpExponent10(DATA_PTR(y)));
return BigDecimal_round(1, &vprec, y);
}
}
```
log(x, prec) click to toggle source

Computes the natural logarithm of x to the specified number of digits of precision.

If x is zero or negative, raises Math::DomainError.

If x is positive infinite, returns Infinity.

If x is NaN, returns NaN.

```
static VALUE
BigMath_s_log(VALUE klass, VALUE x, VALUE vprec)
{
ssize_t prec, n, i;
SIGNED_VALUE expo;
Real* vx = NULL;
VALUE argv[2], 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 almostly the 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 = VpGetSign(vx) < 0;
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:
zero = RBIGNUM_ZERO_P(x);
negative = RBIGNUM_NEGATIVE_P(x);
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);
}
else if (nan) {
Real* vy;
vy = VpCreateRbObject(prec, "#0");
RB_GC_GUARD(vy->obj);
VpSetNaN(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[16];
snprintf(buf, 16, "1E%ld", -expo);
x = BigDecimal_mult2(x, ToValue(VpCreateRbObject(1, buf)), vn);
}
else {
expo = 0;
}
w = BigDecimal_sub(x, one);
argv[1] = vn;
x = BigDecimal_div2(2, argv, w);
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;
argv[0] = SSIZET2NUM(i);
argv[1] = SSIZET2NUM(m);
d = BigDecimal_div2(2, argv, x);
}

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);
}

return y;
}
```

Public Instance Methods

E(prec) click to toggle source

Computes e (the base of natural logarithms) to the specified number of digits of precision.

```
# File bigdecimal/lib/bigdecimal/math.rb, line 189
def E(prec)
raise ArgumentError, "Zero or negative precision for E" if prec <= 0
n    = prec + BigDecimal.double_fig
one  = BigDecimal("1")
y  = one
d  = y
z  = one
i  = 0
while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
m = BigDecimal.double_fig if m < BigDecimal.double_fig
i += 1
z *= i
d  = one.div(z,m)
y += d
end
y
end
```
PI(prec) click to toggle source

Computes the value of pi to the specified number of digits of precision.

```
# File bigdecimal/lib/bigdecimal/math.rb, line 149
def PI(prec)
raise ArgumentError, "Zero or negative argument 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
w = 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
w = 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(x, prec) click to toggle source

Computes the arctangent of x to the specified number of digits of precision.

If x is NaN, returns NaN.

```
# File bigdecimal/lib/bigdecimal/math.rb, line 120
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(x, prec) click to toggle source

Computes the cosine of x to the specified number of digits of precision.

If x is infinite or NaN, returns NaN.

```
# File bigdecimal/lib/bigdecimal/math.rb, line 84
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(x, prec) click to toggle source

Computes the sine of x to the specified number of digits of precision.

If x is infinite or NaN, returns NaN.

```
# File bigdecimal/lib/bigdecimal/math.rb, line 48
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(x,prec) click to toggle source

Computes the square root of x to the specified number of digits of precision.

BigDecimal.new('2').sqrt(16).to_s

`-> "0.14142135623730950488016887242096975E1"`
```
# File bigdecimal/lib/bigdecimal/math.rb, line 41
def sqrt(x,prec)
x.sqrt(prec)
end
```