Module: BigMath
| Relationships & Source Files | |
| Namespace Children | |
|
Modules:
| |
| Defined in: | lib/bigdecimal.rb, lib/bigdecimal/math.rb, lib/bigdecimal/math/erf.rb, lib/bigdecimal/math/gamma.rb |
Overview
Provides mathematical functions.
Example:
require "bigdecimal/math"
include BigMath
a = BigDecimal((PI(49)/2).to_s)
puts sin(a,100) # => 0.9999999999...9999999986e0
Class Method Summary
-
.acos(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the arccosine of
decimalto the specified number of digits of precision,numeric. -
.acosh(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the inverse hyperbolic cosine of
decimalto the specified number of digits of precision,numeric. -
.asin(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the arcsine of
decimalto the specified number of digits of precision,numeric. -
.asinh(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the inverse hyperbolic sine of
decimalto the specified number of digits of precision,numeric. -
.atan(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the arctangent of
decimalto the specified number of digits of precision,numeric. -
.atan2(decimal, decimal, numeric) ⇒ BigDecimal
mod_func
Computes the arctangent of y and x to the specified number of digits of precision,
numeric. -
.atanh(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the inverse hyperbolic tangent of
decimalto the specified number of digits of precision,numeric. -
.cbrt(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the cube root of
decimalto the specified number of digits of precision,numeric. -
.cos(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the cosine of
decimalto the specified number of digits of precision,numeric. -
.cosh(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the hyperbolic cosine of
decimalto the specified number of digits of precision,numeric. -
E(numeric) ⇒ BigDecimal
mod_func
Computes e (the base of natural logarithms) to the specified number of digits of precision,
numeric. -
.erf(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the error function of
decimalto the specified number of digits of precision,numeric. -
.erfc(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the complementary error function of
decimalto the specified number of digits of precision,numeric. -
.exp(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the value of e (the base of natural logarithms) raised to the power of
decimal, to the specified number of digits of precision. -
.expm1(decimal, numeric) ⇒ BigDecimal
mod_func
Computes exp(decimal) - 1 to the specified number of digits of precision,
numeric. -
.frexp(x) ⇒ Array, Integer
mod_func
Decomposes
xinto a normalized fraction and an integral power of ten. -
.gamma(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the gamma function of
decimalto the specified number of digits of precision,numeric. -
.hypot(x, y, numeric) ⇒ BigDecimal
mod_func
Returns sqrt(x2 + y2) to the specified number of digits of precision,
numeric. -
.ldexp(fraction, exponent) ⇒ BigDecimal
mod_func
Inverse of .frexp.
-
.lgamma(decimal, numeric) ⇒ Array, Integer
mod_func
Computes the natural logarithm of the absolute value of the gamma function of
decimalto the specified number of digits of precision,numericand its sign. -
.log(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the natural logarithm of
decimalto the specified number of digits of precision,numeric. -
.log10(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the base 10 logarithm of
decimalto the specified number of digits of precision,numeric. -
.log1p(decimal, numeric) ⇒ BigDecimal
mod_func
Computes log(1 + decimal) to the specified number of digits of precision,
numeric. -
.log2(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the base 2 logarithm of
decimalto the specified number of digits of precision,numeric. -
PI(numeric) ⇒ BigDecimal
mod_func
Computes the value of pi to the specified number of digits of precision,
numeric. -
.sin(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the sine of
decimalto the specified number of digits of precision,numeric. -
.sinh(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the hyperbolic sine of
decimalto the specified number of digits of precision,numeric. -
.sqrt(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the square root of
decimalto the specified number of digits of precision,numeric. -
.tan(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the tangent of
decimalto the specified number of digits of precision,numeric. -
.tanh(decimal, numeric) ⇒ BigDecimal
mod_func
Computes the hyperbolic tangent of
decimalto the specified number of digits of precision,numeric. - ._exp_binary_splitting(x, prec) private mod_func Internal use only
- ._sin_around_zero(x, prec) private mod_func Internal use only
- ._sin_binary_splitting(x, prec) private mod_func Internal use only
-
._sin_periodic_reduction(x, prec, add_half_pi: false)
private
mod_func
Internal use only
Returns [sign, reduced_x] where reduced_x is in -pi/2..pi/2 and satisfies sin(x) = sign * sin(reduced_x) If add_half_pi is true, adds pi/2 to x before reduction.
Class Method Details
._exp_binary_splitting(x, prec) (private, mod_func)
# File 'lib/bigdecimal.rb', line 336
private_class_method def _exp_binary_splitting(x, prec) # :nodoc: return BigDecimal(1) if x.zero? # Find k that satisfies x**k / k! < 10**(-prec) log10 = Math.log(10) logx = BigDecimal::Internal.float_log(x.abs) step = (1..).bsearch { |k| Math.lgamma(k + 1)[0] - k * logx > prec * log10 } # exp(x)-1 = x*(1x/2*(1x/3*(1x/4*(1x/5*(1+...))))) 1 + BigDecimal::Internal.taylor_sum_binary_splitting(x, [*1..step], prec) end
._sin_around_zero(x, prec) (private, mod_func)
# File 'lib/bigdecimal/math.rb', line 110
private_class_method def _sin_around_zero(x, prec) # :nodoc: # Divide x into several parts # sin(x.xxxxxxxx...) = sin(x.xx + 0.00xx + 0.0000xxxx + ...) # Calculate sin of each part and restore sin(0.xxxxxxxx...) using addition theorem. sin = BigDecimal(0) cos = BigDecimal(1) n = 2 while x != 0 do partial_x = x.truncate(n) x -= partial_x s = _sin_binary_splitting(partial_x, prec) c = (1 - s * s).sqrt(prec) sin, cos = (sin * c).add(cos * s, prec), (cos * c).sub(sin * s, prec) n *= 2 end sin.clamp(BigDecimal(-1), BigDecimal(1)) end
._sin_binary_splitting(x, prec) (private, mod_func)
# File 'lib/bigdecimal/math.rb', line 97
private_class_method def _sin_binary_splitting(x, prec) # :nodoc: return x if x.zero? x2 = x.mult(x, prec) # Find k that satisfies x2**k / (2k+1)! < 10**(-prec) log10 = Math.log(10) logx = BigDecimal::Internal.float_log(x.abs) step = (1..).bsearch { |k| Math.lgamma(2 * k + 1)[0] - 2 * k * logx > prec * log10 } # Construct denominator sequence for binary splitting # sin(x) = x*(1-x2/(2*3)*(1-x2/(4*5)*(1-x2/(6*7)*(1-x2/(8*9)*(1-...))))) ds = (1..step).map {|i| -(2 * i) * (2 * i + 1) } x.mult(1 + BigDecimal::Internal.taylor_sum_binary_splitting(x2, ds, prec), prec) end
._sin_periodic_reduction(x, prec, add_half_pi: false) (private, mod_func)
Returns [sign, reduced_x] where reduced_x is in -pi/2..pi/2 and satisfies sin(x) = sign * sin(reduced_x) If add_half_pi is true, adds pi/2 to x before reduction. Precision of pi is adjusted to ensure reduced_x has the required precision.
# File 'lib/bigdecimal/math.rb', line 75
private_class_method def _sin_periodic_reduction(x, prec, add_half_pi: false) # :nodoc: return [1, x] if -Math::PI/2 <= x && x <= Math::PI/2 && !add_half_pi mod_prec = prec + BigDecimal::Internal::EXTRA_PREC pi_extra_prec = [x.exponent, 0].max + BigDecimal::Internal::EXTRA_PREC while true pi = PI(mod_prec + pi_extra_prec) half_pi = pi / 2 div, mod = (add_half_pi ? x + pi : x + half_pi).divmod(pi) mod -= half_pi if mod.zero? || mod_prec + mod.exponent <= 0 # mod is too small to estimate required pi precision mod_prec = mod_prec * 3 / 2 + BigDecimal::Internal::EXTRA_PREC elsif mod_prec + mod.exponent < prec # Estimate required precision of pi mod_prec = prec - mod.exponent + BigDecimal::Internal::EXTRA_PREC else return [div % 2 == 0 ? 1 : -1, mod.mult(1, prec)] end end end
.acos(decimal, numeric) ⇒ BigDecimal (mod_func)
Computes the arccosine of decimal to the specified number of digits of
precision, numeric.
If decimal is NaN, returns NaN.
BigMath.acos(BigDecimal('0.5'), 32).to_s
#=> "0.10471975511965977461542144610932e1"
# File 'lib/bigdecimal/math.rb', line 270
def acos(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :acos) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :acos) raise Math::DomainError, "Out of domain argument for acos" if x < -1 || x > 1 return BigDecimal::Internal.nan_computation_result if x.nan? prec2 = prec + BigDecimal::Internal::EXTRA_PREC return (PI(prec2) / 2).sub(asin(x, prec2), prec) if x < 0 return PI(prec2).div(2, prec) if x.zero? sin = (1 - x**2).sqrt(prec2) atan(sin.div(x, prec2), prec) end
.acosh(decimal, numeric) ⇒ BigDecimal (mod_func)
Computes the inverse hyperbolic cosine of decimal to the specified number of digits of
precision, numeric.
If decimal is NaN, returns NaN.
BigMath.acosh(BigDecimal('2'), 32).to_s
#=> "0.1316957896924816708625046347308e1"
# File 'lib/bigdecimal/math.rb', line 453
def acosh(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :acosh) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :acosh) raise Math::DomainError, "Out of domain argument for acosh" if x < 1 return BigDecimal::Internal.infinity_computation_result if x.infinite? return BigDecimal::Internal.nan_computation_result if x.nan? log(x + sqrt(x**2 - 1, prec + BigDecimal::Internal::EXTRA_PREC), prec) end
.asin(decimal, numeric) ⇒ BigDecimal (mod_func)
Computes the arcsine of decimal to the specified number of digits of
precision, numeric.
If decimal is NaN, returns NaN.
BigMath.asin(BigDecimal('0.5'), 32).to_s
#=> "0.52359877559829887307710723054658e0"
# File 'lib/bigdecimal/math.rb', line 244
def asin(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :asin) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :asin) raise Math::DomainError, "Out of domain argument for asin" if x < -1 || x > 1 return BigDecimal::Internal.nan_computation_result if x.nan? prec2 = prec + BigDecimal::Internal::EXTRA_PREC cos = (1 - x**2).sqrt(prec2) if cos.zero? PI(prec2).div(x > 0 ? 2 : -2, prec) else atan(x.div(cos, prec2), prec) end end
.asinh(decimal, numeric) ⇒ BigDecimal (mod_func)
Computes the inverse hyperbolic sine of decimal to the specified number of digits of
precision, numeric.
If decimal is NaN, returns NaN.
BigMath.asinh(BigDecimal('1'), 32).to_s
#=> "0.88137358701954302523260932497979e0"
# File 'lib/bigdecimal/math.rb', line 431
def asinh(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :asinh) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :asinh) return BigDecimal::Internal.nan_computation_result if x.nan? return BigDecimal::Internal.infinity_computation_result * x.infinite? if x.infinite? return -asinh(-x, prec) if x < 0 sqrt_prec = prec + [-x.exponent, 0].max + BigDecimal::Internal::EXTRA_PREC log(x + sqrt(x**2 + 1, sqrt_prec), prec) end
.atan(decimal, numeric) ⇒ BigDecimal (mod_func)
Computes the arctangent of decimal to the specified number of digits of
precision, numeric.
If decimal is NaN, returns NaN.
BigMath.atan(BigDecimal('-1'), 32).to_s
#=> "-0.78539816339744830961566084581988e0"
# File 'lib/bigdecimal/math.rb', line 295
def atan(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :atan) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :atan) return BigDecimal::Internal.nan_computation_result if x.nan? n = prec + BigDecimal::Internal::EXTRA_PREC return PI(n).div(2 * x.infinite?, prec) if x.infinite? x = -x if neg = x < 0 x = BigDecimal(1).div(x, n) if inv = x < -1 || x > 1 # Solve tan(y) - x = 0 with Newton's method # Repeat: y -= (tan(y) - x) * cos(y)**2 y = BigDecimal(Math.atan(x.to_f), 0) BigDecimal::Internal.newton_loop(n) do |p| s = sin(y, p) c = (1 - s * s).sqrt(p) y = y.sub(c * (s.sub(c * x.mult(1, p), p)), p) end y = PI(n) / 2 - y if inv y.mult(neg ? -1 : 1, prec) end
.atan2(decimal, decimal, numeric) ⇒ BigDecimal (mod_func)
Computes the arctangent of y and x to the specified number of digits of
precision, numeric.
BigMath.atan2(BigDecimal('-1'), BigDecimal('1'), 32).to_s
#=> "-0.78539816339744830961566084581988e0"
# File 'lib/bigdecimal/math.rb', line 326
def atan2(y, x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :atan2) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :atan2) y = BigDecimal::Internal.coerce_to_bigdecimal(y, prec, :atan2) return BigDecimal::Internal.nan_computation_result if x.nan? || y.nan? if x.infinite? || y.infinite? one = BigDecimal(1) zero = BigDecimal(0) x = x.infinite? ? (x > 0 ? one : -one) : zero y = y.infinite? ? (y > 0 ? one : -one) : y.sign * zero end return x.sign >= 0 ? BigDecimal(0) : y.sign * PI(prec) if y.zero? y = -y if neg = y < 0 xlarge = y.abs < x.abs prec2 = prec + BigDecimal::Internal::EXTRA_PREC if x > 0 v = xlarge ? atan(y.div(x, prec2), prec) : PI(prec2) / 2 - atan(x.div(y, prec2), prec2) else v = xlarge ? PI(prec2) - atan(-y.div(x, prec2), prec2) : PI(prec2) / 2 + atan(x.div(-y, prec2), prec2) end v.mult(neg ? -1 : 1, prec) end
.atanh(decimal, numeric) ⇒ BigDecimal (mod_func)
Computes the inverse hyperbolic tangent of decimal to the specified number of digits of
precision, numeric.
If decimal is NaN, returns NaN.
BigMath.atanh(BigDecimal('0.5'), 32).to_s
#=> "0.54930614433405484569762261846126e0"
# File 'lib/bigdecimal/math.rb', line 474
def atanh(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :atanh) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :atanh) raise Math::DomainError, "Out of domain argument for atanh" if x < -1 || x > 1 return BigDecimal::Internal.nan_computation_result if x.nan? return BigDecimal::Internal.infinity_computation_result if x == 1 return -BigDecimal::Internal.infinity_computation_result if x == -1 prec2 = prec + BigDecimal::Internal::EXTRA_PREC (log(x + 1, prec2) - log(1 - x, prec2)).div(2, prec) end
.cbrt(decimal, numeric) ⇒ BigDecimal (mod_func)
Computes the cube root of decimal to the specified number of digits of
precision, numeric.
BigMath.cbrt(BigDecimal('2'), 32).to_s
#=> "0.12599210498948731647672106072782e1"
# File 'lib/bigdecimal/math.rb', line 137
def cbrt(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :cbrt) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :cbrt) return BigDecimal::Internal.nan_computation_result if x.nan? return BigDecimal::Internal.infinity_computation_result * x.infinite? if x.infinite? return BigDecimal(0) if x.zero? x = -x if neg = x < 0 ex = x.exponent / 3 x = x._decimal_shift(-3 * ex) y = BigDecimal(Math.cbrt(x.to_f), 0) BigDecimal::Internal.newton_loop(prec + BigDecimal::Internal::EXTRA_PREC) do |p| y = (2 * y + x.div(y, p).div(y, p)).div(3, p) end y._decimal_shift(ex).mult(neg ? -1 : 1, prec) end
.cos(decimal, numeric) ⇒ BigDecimal (mod_func)
# File 'lib/bigdecimal/math.rb', line 204
def cos(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :cos) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :cos) return BigDecimal::Internal.nan_computation_result if x.infinite? || x.nan? n = prec + BigDecimal::Internal::EXTRA_PREC sign, x = _sin_periodic_reduction(x, n, add_half_pi: true) _sin_around_zero(x, n).mult(sign, prec) end
.cosh(decimal, numeric) ⇒ BigDecimal (mod_func)
Computes the hyperbolic cosine of decimal to the specified number of digits of
precision, numeric.
If decimal is NaN, returns NaN.
BigMath.cosh(BigDecimal('1'), 32).to_s
#=> "0.15430806348152437784779056207571e1"
# File 'lib/bigdecimal/math.rb', line 386
def cosh(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :cosh) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :cosh) return BigDecimal::Internal.nan_computation_result if x.nan? return BigDecimal::Internal.infinity_computation_result if x.infinite? prec2 = prec + BigDecimal::Internal::EXTRA_PREC e = exp(x, prec2) (e + BigDecimal(1).div(e, prec2)).div(2, prec) end
E(numeric) ⇒ BigDecimal (mod_func)
Computes e (the base of natural logarithms) to the specified number of
digits of precision, numeric.
BigMath.E(32).to_s
#=> "0.27182818284590452353602874713527e1"
# File 'lib/bigdecimal/math.rb', line 712
def E(prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :E) exp(1, prec) end
.erf(decimal, numeric) ⇒ BigDecimal (mod_func)
Computes the error function of decimal to the specified number of digits of
precision, numeric.
If decimal is NaN, returns NaN.
BigMath.erf(BigDecimal('1'), 32).to_s
#=> "0.84270079294971486934122063508261e0"
.erfc(decimal, numeric) ⇒ BigDecimal (mod_func)
Computes the complementary error function of decimal to the specified number of digits of
precision, numeric.
If decimal is NaN, returns NaN.
BigMath.erfc(BigDecimal('10'), 32).to_s
#=> "0.20884875837625447570007862949578e-44"
.exp(decimal, numeric) ⇒ BigDecimal (mod_func)
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.
# File 'lib/bigdecimal.rb', line 356
def exp(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :exp) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :exp) return BigDecimal::Internal.nan_computation_result if x.nan? if x.infinite? || x.exponent >= 21 # exp(10**20) and exp(-10**20) overflows/underflows 64-bit exponent if x.positive? return BigDecimal::Internal.infinity_computation_result elsif x.infinite? # exp(-Infinity) is +0 by definition, this is not an underflow. return BigDecimal(0) else return BigDecimal::Internal.underflow_computation_result end end return BigDecimal(1) if x.zero? # exp(x * 10**cnt) = exp(x)**(10**cnt) cnt = x < -1 || x > 1 ? x.exponent : 0 prec2 = prec + BigDecimal::Internal::EXTRA_PREC + cnt x = x._decimal_shift(-cnt) # Decimal form of bit-burst algorithm # Calculate exp(x.xxxxxxxxxxxxxxxx) as # exp(x.xx) * exp(0.00xx) * exp(0.0000xxxx) * exp(0.00000000xxxxxxxx) x = x.mult(1, prec2) n = 2 y = BigDecimal(1) BigDecimal.save_limit do BigDecimal.limit(0) while x != 0 do partial_x = x.truncate(n) x -= partial_x y = y.mult(_exp_binary_splitting(partial_x, prec2), prec2) n *= 2 end end # calculate exp(x * 10**cnt) from exp(x) # exp(x * 10**k) = exp(x * 10**(k - 1)) ** 10 cnt.times do y2 = y.mult(y, prec2) y5 = y2.mult(y2, prec2).mult(y, prec2) y = y5.mult(y5, prec2) end y.mult(1, prec) end
.expm1(decimal, numeric) ⇒ BigDecimal (mod_func)
Computes exp(decimal) - 1 to the specified number of digits of precision, numeric.
BigMath.expm1(BigDecimal('0.1'), 32).to_s
#=> "0.10517091807564762481170782649025e0"
# File 'lib/bigdecimal/math.rb', line 566
def expm1(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :expm1) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :expm1) return BigDecimal(-1) if x.infinite? == -1 exp_prec = prec if x < -1 # log10(exp(x)) = x * log10(e) lg_e = 0.4342944819032518 exp_prec = prec + (lg_e * x).ceil + BigDecimal::Internal::EXTRA_PREC elsif x < 1 exp_prec = prec - x.exponent + BigDecimal::Internal::EXTRA_PREC else exp_prec = prec end return BigDecimal(-1) if exp_prec <= 0 exp(x, exp_prec).sub(1, prec) end
.frexp(x) ⇒ Array, Integer (mod_func)
Decomposes x into a normalized fraction and an integral power of ten.
BigMath.frexp(BigDecimal(123.456))
#=> [0.123456e0, 3]
# File 'lib/bigdecimal/math.rb', line 655
def frexp(x) x = BigDecimal::Internal.coerce_to_bigdecimal(x, 0, :frexp) return [x, 0] unless x.finite? exponent = x.exponent [x._decimal_shift(-exponent), exponent] end
.gamma(decimal, numeric) ⇒ BigDecimal (mod_func)
Computes the gamma function of decimal to the specified number of
digits of precision, numeric.
BigMath.gamma(BigDecimal('0.5'), 32).to_s
#=> "0.17724538509055160272981674833411e1"
.hypot(x, y, numeric) ⇒ BigDecimal (mod_func)
Returns sqrt(x2 + y2) to the specified number of digits of
precision, numeric.
BigMath.hypot(BigDecimal('1'), BigDecimal('2'), 32).to_s
#=> "0.22360679774997896964091736687313e1"
# File 'lib/bigdecimal/math.rb', line 163
def hypot(x, y, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :hypot) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :hypot) y = BigDecimal::Internal.coerce_to_bigdecimal(y, prec, :hypot) return BigDecimal::Internal.nan_computation_result if x.nan? || y.nan? return BigDecimal::Internal.infinity_computation_result if x.infinite? || y.infinite? prec2 = prec + BigDecimal::Internal::EXTRA_PREC sqrt(x.mult(x, prec2) + y.mult(y, prec2), prec) end
.ldexp(fraction, exponent) ⇒ BigDecimal (mod_func)
Inverse of .frexp. Returns the value of fraction * 10**exponent.
BigMath.ldexp(BigDecimal("0.123456e0"), 3)
#=> 0.123456e3
# File 'lib/bigdecimal/math.rb', line 672
def ldexp(x, exponent) x = BigDecimal::Internal.coerce_to_bigdecimal(x, 0, :ldexp) x.finite? ? x._decimal_shift(exponent) : x end
.lgamma(decimal, numeric) ⇒ Array, Integer (mod_func)
Computes the natural logarithm of the absolute value of the gamma function
of decimal to the specified number of digits of precision, numeric and its sign.
BigMath.lgamma(BigDecimal('0.5'), 32)
#=> [0.57236494292470008707171367567653e0, 1]
.log(decimal, numeric) ⇒ BigDecimal (mod_func)
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.
# File 'lib/bigdecimal.rb', line 303
def log(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :log) raise Math::DomainError, 'Complex argument for BigMath.log' if Complex === x x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :log) return BigDecimal::Internal.nan_computation_result if x.nan? raise Math::DomainError, 'Negative argument for log' if x < 0 return -BigDecimal::Internal.infinity_computation_result if x.zero? return BigDecimal::Internal.infinity_computation_result if x.infinite? return BigDecimal(0) if x == 1 prec2 = prec + BigDecimal::Internal::EXTRA_PREC # Reduce x to near 1 if x > 1.01 || x < 0.99 # log(x) = log(x/exp(logx_approx)) + logx_approx logx_approx = BigDecimal(BigDecimal::Internal.float_log(x), 0) x = x.div(exp(logx_approx, prec2), prec2) else logx_approx = BigDecimal(0) end # Solve exp(y) - x = 0 with Newton's method # Repeat: y -= (exp(y) - x) / exp(y) y = BigDecimal(BigDecimal::Internal.float_log(x), 0) exp_additional_prec = [-(x - 1).exponent, 0].max BigDecimal::Internal.newton_loop(prec2) do |p| expy = exp(y, p + exp_additional_prec) y = y.sub(expy.sub(x, p).div(expy, p), p) end y.add(logx_approx, prec) end
.log10(decimal, numeric) ⇒ BigDecimal (mod_func)
Computes the base 10 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.
BigMath.log10(BigDecimal('3'), 32).to_s
#=> "0.47712125471966243729502790325512e0"
# File 'lib/bigdecimal/math.rb', line 529
def log10(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :log10) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :log10) return BigDecimal::Internal.nan_computation_result if x.nan? return BigDecimal::Internal.infinity_computation_result if x.infinite? == 1 prec2 = prec + BigDecimal::Internal::EXTRA_PREC * 3 / 2 v = log(x, prec2).div(log(BigDecimal(10), prec2), prec2) # Perform half-up rounding to calculate log10(10**n)==n correctly in every rounding mode v = v.round(prec + BigDecimal::Internal::EXTRA_PREC - (v.exponent < 0 ? v.exponent : 0), BigDecimal::ROUND_HALF_UP) v.mult(1, prec) end
.log1p(decimal, numeric) ⇒ BigDecimal (mod_func)
Computes log(1 + decimal) to the specified number of digits of precision, numeric.
BigMath.log1p(BigDecimal('0.1'), 32).to_s
#=> "0.95310179804324860043952123280765e-1"
# File 'lib/bigdecimal/math.rb', line 550
def log1p(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :log1p) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :log1p) raise Math::DomainError, 'Out of domain argument for log1p' if x < -1 return log(x + 1, prec) end
.log2(decimal, numeric) ⇒ BigDecimal (mod_func)
Computes the base 2 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.
BigMath.log2(BigDecimal('3'), 32).to_s
#=> "0.15849625007211561814537389439478e1"
# File 'lib/bigdecimal/math.rb', line 501
def log2(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :log2) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :log2) return BigDecimal::Internal.nan_computation_result if x.nan? return BigDecimal::Internal.infinity_computation_result if x.infinite? == 1 prec2 = prec + BigDecimal::Internal::EXTRA_PREC * 3 / 2 v = log(x, prec2).div(log(BigDecimal(2), prec2), prec2) # Perform half-up rounding to calculate log2(2**n)==n correctly in every rounding mode v = v.round(prec + BigDecimal::Internal::EXTRA_PREC - (v.exponent < 0 ? v.exponent : 0), BigDecimal::ROUND_HALF_UP) v.mult(1, prec) end
PI(numeric) ⇒ BigDecimal (mod_func)
Computes the value of pi to the specified number of digits of precision,
numeric.
BigMath.PI(32).to_s
#=> "0.31415926535897932384626433832795e1"
# File 'lib/bigdecimal/math.rb', line 686
def PI(prec) # Gauss–Legendre algorithm prec = BigDecimal::Internal.coerce_validate_prec(prec, :PI) n = prec + BigDecimal::Internal::EXTRA_PREC a = BigDecimal(1) b = BigDecimal(0.5, 0).sqrt(n) s = BigDecimal(0.25, 0) t = 1 while a != b && (a - b).exponent > 1 - n c = (a - b).div(2, n) a, b = (a + b).div(2, n), (a * b).sqrt(n) s = s.sub(c * c * t, n) t *= 2 end (a * b).div(s, prec) end
.sin(decimal, numeric) ⇒ BigDecimal (mod_func)
# File 'lib/bigdecimal/math.rb', line 184
def sin(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :sin) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :sin) return BigDecimal::Internal.nan_computation_result if x.infinite? || x.nan? n = prec + BigDecimal::Internal::EXTRA_PREC sign, x = _sin_periodic_reduction(x, n) _sin_around_zero(x, n).mult(sign, prec) end
.sinh(decimal, numeric) ⇒ BigDecimal (mod_func)
Computes the hyperbolic sine of decimal to the specified number of digits of
precision, numeric.
If decimal is NaN, returns NaN.
BigMath.sinh(BigDecimal('1'), 32).to_s
#=> "0.11752011936438014568823818505956e1"
# File 'lib/bigdecimal/math.rb', line 363
def sinh(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :sinh) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :sinh) return BigDecimal::Internal.nan_computation_result if x.nan? return BigDecimal::Internal.infinity_computation_result * x.infinite? if x.infinite? prec2 = prec + BigDecimal::Internal::EXTRA_PREC prec2 -= x.exponent if x.exponent < 0 e = exp(x, prec2) (e - BigDecimal(1).div(e, prec2)).div(2, prec) end
.sqrt(decimal, numeric) ⇒ BigDecimal (mod_func)
Computes the square root of decimal to the specified number of digits of
precision, numeric.
BigMath.sqrt(BigDecimal('2'), 32).to_s
#=> "0.14142135623730950488016887242097e1"
# File 'lib/bigdecimal/math.rb', line 64
def sqrt(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :sqrt) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :sqrt) x.sqrt(prec) end
.tan(decimal, numeric) ⇒ BigDecimal (mod_func)
Computes the tangent of decimal to the specified number of digits of
precision, numeric.
If decimal is Infinity or NaN, returns NaN.
BigMath.tan(BigDecimal("0.0"), 4).to_s
#=> "0.0"
BigMath.tan(BigMath.PI(24) / 4, 32).to_s
#=> "0.99999999999999999999999830836025e0"
# File 'lib/bigdecimal/math.rb', line 227
def tan(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :tan) prec2 = prec + BigDecimal::Internal::EXTRA_PREC sin(x, prec2).div(cos(x, prec2), prec) end
.tanh(decimal, numeric) ⇒ BigDecimal (mod_func)
Computes the hyperbolic tangent of decimal to the specified number of digits of
precision, numeric.
If decimal is NaN, returns NaN.
BigMath.tanh(BigDecimal('1'), 32).to_s
#=> "0.76159415595576488811945828260479e0"
# File 'lib/bigdecimal/math.rb', line 408
def tanh(x, prec) prec = BigDecimal::Internal.coerce_validate_prec(prec, :tanh) x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :tanh) return BigDecimal::Internal.nan_computation_result if x.nan? return BigDecimal(x.infinite?) if x.infinite? prec2 = prec + BigDecimal::Internal::EXTRA_PREC + [-x.exponent, 0].max e = exp(x, prec2) einv = BigDecimal(1).div(e, prec2) (e - einv).div(e + einv, prec) end