In Files

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

Quicksearch

BigMath

Provides mathematical functions.

Example:

```require "bigdecimal/math"

include BigMath

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

Public Class Methods

exp(decimal, numeric) → BigDecimal click to toggle source

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

If `decimal` is infinity, returns Infinity.

If `decimal` 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, 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 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) {
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 = VpGetSign(vx) < 0;
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);
}
```
log(decimal, numeric) → BigDecimal click to toggle source

Computes the natural logarithm of `decimal` to the specified number of digits of precision, `numeric`.

If `decimal` is zero or negative, raises Math::DomainError.

If `decimal` is positive infinity, returns Infinity.

If `decimal` 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 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);
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[16];
snprintf(buf, 16, "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;
}
```

Public Instance Methods

E(numeric) → BigDecimal click to toggle source

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

```BigMath::E(10).to_s
#=> "0.271828182845904523536028752390026306410273E1"
```
```
# File 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(numeric) → BigDecimal click to toggle source

Computes the value of pi to the specified number of digits of precision, `numeric`.

```BigMath::PI(10).to_s
#=> "0.3141592653589793238462643388813853786957412E1"
```
```
# File bigdecimal/lib/bigdecimal/math.rb, line 182
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
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(decimal, numeric) → BigDecimal click to toggle source

Computes the arctangent of `decimal` to the specified number of digits of precision, `numeric`.

If `decimal` is NaN, returns NaN.

```BigMath::atan(BigDecimal.new('-1'), 16).to_s
#=> "-0.785398163397448309615660845819878471907514682065E0"
```
```
# File 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(decimal, numeric) → BigDecimal click to toggle source

Computes the cosine of `decimal` to the specified number of digits of precision, `numeric`.

If `decimal` is Infinity or NaN, returns NaN.

```BigMath::cos(BigMath::PI(4), 16).to_s
#=> "-0.999999999999999999999999999999856613163740061349E0"
```
```
# File 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(decimal, numeric) → BigDecimal click to toggle source

Computes the sine of `decimal` to the specified number of digits of precision, `numeric`.

If `decimal` is Infinity or NaN, returns NaN.

```BigMath::sin(BigMath::PI(5)/4, 5).to_s
#=> "0.70710678118654752440082036563292800375E0"
```
```
# File 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(decimal, numeric) → BigDecimal click to toggle source

Computes the square root of `decimal` to the specified number of digits of precision, `numeric`.

```BigMath::sqrt(BigDecimal.new('2'), 16).to_s
#=> "0.14142135623730950488016887242096975E1"
```
```
# File bigdecimal/lib/bigdecimal/math.rb, line 42
def sqrt(x, prec)
x.sqrt(prec)
end
```

Commenting is here to help enhance the documentation. For example, code samples, or clarification of the documentation.

If you have questions about Ruby or the documentation, please post to one of the Ruby mailing lists. You will get better, faster, help that way.

If you wish to post a correction of the docs, please do so, but also file bug report so that it can be corrected for the next release. Thank you.

If you want to help improve the Ruby documentation, please visit Documenting-ruby.org.

blog comments powered by Disqus