Module: BigMath

Defined in:
lib/bigdecimal.rb,
lib/bigdecimal/math.rb,
lib/bigdecimal/math/erf.rb,
lib/bigdecimal/math/gamma.rb,
sig/big_math.rbs

Overview

Core BigMath methods for BigDecimal (log, exp) are defined here. Other methods (sin, cos, atan) are defined in 'bigdecimal/math.rb'.

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 collapse

Instance Method Summary collapse

Class Method Details

.acos(x, prec) ⇒ Object

call-seq:

acos(decimal, numeric) -> BigDecimal

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"

Raises:

  • (Math::DomainError)


270
271
272
273
274
275
276
277
278
279
280
281
282
# 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(x, prec) ⇒ Object

call-seq:

acosh(decimal, numeric) -> BigDecimal

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"

Raises:

  • (Math::DomainError)


453
454
455
456
457
458
459
460
461
# 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(x, prec) ⇒ Object

call-seq:

asin(decimal, numeric) -> BigDecimal

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"

Raises:

  • (Math::DomainError)


244
245
246
247
248
249
250
251
252
253
254
255
256
257
# 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(x, prec) ⇒ Object

call-seq:

asinh(decimal, numeric) -> BigDecimal

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"


431
432
433
434
435
436
437
438
439
440
# 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(x, prec) ⇒ Object

call-seq:

atan(decimal, numeric) -> BigDecimal

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"


295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# 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(y, x, prec) ⇒ Object

call-seq:

atan2(decimal, decimal, numeric) -> BigDecimal

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"


326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
# 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(x, prec) ⇒ Object

call-seq:

atanh(decimal, numeric) -> BigDecimal

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"

Raises:

  • (Math::DomainError)


474
475
476
477
478
479
480
481
482
483
484
# 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(x, prec) ⇒ Object

call-seq:

cbrt(decimal, numeric) -> BigDecimal

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

BigMath.cbrt(BigDecimal('2'), 32).to_s
#=> "0.12599210498948731647672106072782e1"


137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# 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(x, prec) ⇒ Object

call-seq:

cos(decimal, numeric) -> BigDecimal

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(16), 32).to_s
#=> "-0.99999999999999999999999999999997e0"


204
205
206
207
208
209
210
211
# 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(x, prec) ⇒ Object

call-seq:

cosh(decimal, numeric) -> BigDecimal

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"


386
387
388
389
390
391
392
393
394
395
# 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(prec) ⇒ Object

call-seq:

E(numeric) -> BigDecimal

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

BigMath.E(32).to_s
#=> "0.27182818284590452353602874713527e1"


712
713
714
715
# File 'lib/bigdecimal/math.rb', line 712

def E(prec)
  prec = BigDecimal::Internal.coerce_validate_prec(prec, :E)
  exp(1, prec)
end

.erf(x, prec) ⇒ Object

call-seq:

erf(decimal, numeric) -> BigDecimal

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"


598
599
600
601
# File 'lib/bigdecimal/math.rb', line 598

def erf(x, prec)
  require 'bigdecimal/math/erf'
  Erf.erf(x, prec)
end

.erfc(x, prec) ⇒ Object

call-seq:

erfc(decimal, numeric) -> BigDecimal

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"


614
615
616
617
# File 'lib/bigdecimal/math.rb', line 614

def erfc(x, prec)
  require 'bigdecimal/math/erf'
  Erf.erfc(x, prec)
end

.exp(x, prec) ⇒ Object

call-seq:

BigMath.exp(decimal, numeric)    -> BigDecimal

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.



356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
# 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(x, prec) ⇒ Object

call-seq:

BigMath.expm1(decimal, numeric)    -> BigDecimal

Computes exp(decimal) - 1 to the specified number of digits of precision, numeric.

BigMath.expm1(BigDecimal('0.1'), 32).to_s
#=> "0.10517091807564762481170782649025e0"


566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
# 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) ⇒ Object

call-seq:

frexp(x) -> [BigDecimal, Integer]

Decomposes x into a normalized fraction and an integral power of ten.

BigMath.frexp(BigDecimal(123.456))
#=> [0.123456e0, 3]


655
656
657
658
659
660
661
# 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(x, prec) ⇒ Object

call-seq:

BigMath.gamma(decimal, numeric)    -> BigDecimal

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"


628
629
630
631
# File 'lib/bigdecimal/math.rb', line 628

def gamma(x, prec)
  require 'bigdecimal/math/gamma'
  Gamma.gamma(x, prec)
end

.hypot(x, y, prec) ⇒ Object

call-seq:

hypot(x, y, numeric) -> BigDecimal

Returns sqrt(x2 + y2) to the specified number of digits of precision, numeric.

BigMath.hypot(BigDecimal('1'), BigDecimal('2'), 32).to_s
#=> "0.22360679774997896964091736687313e1"


163
164
165
166
167
168
169
170
171
# 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(x, exponent) ⇒ Object

call-seq:

ldexp(fraction, exponent) -> BigDecimal

Inverse of frexp. Returns the value of fraction * 10**exponent.

BigMath.ldexp(BigDecimal("0.123456e0"), 3)
#=> 0.123456e3


672
673
674
675
# 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(x, prec) ⇒ Object

call-seq:

BigMath.lgamma(decimal, numeric)    -> [BigDecimal, Integer]

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]


642
643
644
645
# File 'lib/bigdecimal/math.rb', line 642

def lgamma(x, prec)
  require 'bigdecimal/math/gamma'
  Gamma.lgamma(x, prec)
end

.log(x, prec) ⇒ Object

call-seq:

BigMath.log(decimal, numeric)    -> BigDecimal

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.

Raises:

  • (Math::DomainError)


303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# 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(x, prec) ⇒ Object

call-seq:

BigMath.log10(decimal, numeric)    -> BigDecimal

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"


529
530
531
532
533
534
535
536
537
538
539
540
# 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(x, prec) ⇒ Object

call-seq:

BigMath.log1p(decimal, numeric)    -> BigDecimal

Computes log(1 + decimal) to the specified number of digits of precision, numeric.

BigMath.log1p(BigDecimal('0.1'), 32).to_s
#=> "0.95310179804324860043952123280765e-1"

Raises:

  • (Math::DomainError)


550
551
552
553
554
555
556
# 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(x, prec) ⇒ Object

call-seq:

BigMath.log2(decimal, numeric)    -> BigDecimal

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"


501
502
503
504
505
506
507
508
509
510
511
512
# 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(prec) ⇒ Object

call-seq:

PI(numeric) -> BigDecimal

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

BigMath.PI(32).to_s
#=> "0.31415926535897932384626433832795e1"


686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
# 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(x, prec) ⇒ Object

call-seq:

sin(decimal, numeric) -> BigDecimal

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, 32).to_s
#=> "0.70710807985947359435812921837984e0"


184
185
186
187
188
189
190
191
# 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(x, prec) ⇒ Object

call-seq:

sinh(decimal, numeric) -> BigDecimal

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"


363
364
365
366
367
368
369
370
371
372
373
# 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(x, prec) ⇒ Object

call-seq:

sqrt(decimal, numeric) -> BigDecimal

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

BigMath.sqrt(BigDecimal('2'), 32).to_s
#=> "0.14142135623730950488016887242097e1"


64
65
66
67
68
# 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(x, prec) ⇒ Object

call-seq:

tan(decimal, numeric) -> BigDecimal

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"


227
228
229
230
231
# 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(x, prec) ⇒ Object

call-seq:

tanh(decimal, numeric) -> BigDecimal

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"


408
409
410
411
412
413
414
415
416
417
418
# 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

Instance Method Details

#self?.acosBigDecimal

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"

Parameters:

Returns:



54
# File 'sig/big_math.rbs', line 54

def self?.acos: (real | BigDecimal, int prec) -> BigDecimal

#self?.acoshBigDecimal

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"

Parameters:

Returns:



68
# File 'sig/big_math.rbs', line 68

def self?.acosh: (real | BigDecimal, int prec) -> BigDecimal

#self?.asinBigDecimal

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"

Parameters:

Returns:



82
# File 'sig/big_math.rbs', line 82

def self?.asin: (real | BigDecimal, int prec) -> BigDecimal

#self?.asinhBigDecimal

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"

Parameters:

Returns:



96
# File 'sig/big_math.rbs', line 96

def self?.asinh: (real | BigDecimal, int prec) -> BigDecimal

#self?.atanBigDecimal

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"

Parameters:

Returns:



110
# File 'sig/big_math.rbs', line 110

def self?.atan: (real | BigDecimal x, int prec) -> BigDecimal

#self?.atan2BigDecimal

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"

Parameters:

Returns:



122
# File 'sig/big_math.rbs', line 122

def self?.atan2: (real | BigDecimal, real | BigDecimal, int prec) -> BigDecimal

#self?.atanhBigDecimal

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"

Parameters:

Returns:



136
# File 'sig/big_math.rbs', line 136

def self?.atanh: (real | BigDecimal, int prec) -> BigDecimal

#self?.cbrtBigDecimal

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

BigMath.cbrt(BigDecimal('2'), 32).to_s
#=> "0.12599210498948731647672106072782e1"

Parameters:

Returns:



148
# File 'sig/big_math.rbs', line 148

def self?.cbrt: (real | BigDecimal, int prec) -> BigDecimal

#self?.cosBigDecimal

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(16), 32).to_s
#=> "-0.99999999999999999999999999999997e0"

Parameters:

Returns:



162
# File 'sig/big_math.rbs', line 162

def self?.cos: (real | BigDecimal x, int prec) -> BigDecimal

#self?.coshBigDecimal

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"

Parameters:

Returns:



176
# File 'sig/big_math.rbs', line 176

def self?.cosh: (real | BigDecimal, int prec) -> BigDecimal

#self?.EBigDecimal

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

BigMath.E(32).to_s
#=> "0.27182818284590452353602874713527e1"

Parameters:

  • prec (int)

Returns:



28
# File 'sig/big_math.rbs', line 28

def self?.E: (int prec) -> BigDecimal

#self?.erfBigDecimal

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"

Parameters:

Returns:



190
# File 'sig/big_math.rbs', line 190

def self?.erf: (real | BigDecimal, int prec) -> BigDecimal

#self?.erfcBigDecimal

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"

Parameters:

Returns:



204
# File 'sig/big_math.rbs', line 204

def self?.erfc: (real | BigDecimal, int prec) -> BigDecimal

#self?.expBigDecimal

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.

Parameters:

Returns:



217
# File 'sig/big_math.rbs', line 217

def self?.exp: (real | BigDecimal, int prec) -> BigDecimal

#self?.expm1BigDecimal

Computes exp(decimal) - 1 to the specified number of digits of precision, numeric.

BigMath.expm1(BigDecimal('0.1'), 32).to_s
#=> "0.10517091807564762481170782649025e0"

Parameters:

Returns:



229
# File 'sig/big_math.rbs', line 229

def self?.expm1: (real | BigDecimal, int prec) -> BigDecimal

#self?.frexp[ BigDecimal, Integer ]

Decomposes x into a normalized fraction and an integral power of ten.

BigMath.frexp(BigDecimal(123.456))
#=> [0.123456e0, 3]

Parameters:

Returns:



240
# File 'sig/big_math.rbs', line 240

def self?.frexp: (real | BigDecimal x) -> [ BigDecimal, Integer ]

#self?.gammaBigDecimal

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"

Parameters:

Returns:



252
# File 'sig/big_math.rbs', line 252

def self?.gamma: (real | BigDecimal, int prec) -> BigDecimal

#self?.hypotBigDecimal

Returns sqrt(x2 + y2) to the specified number of digits of precision, numeric.

BigMath.hypot(BigDecimal('1'), BigDecimal('2'), 32).to_s
#=> "0.22360679774997896964091736687313e1"

Parameters:

Returns:



264
# File 'sig/big_math.rbs', line 264

def self?.hypot: (real | BigDecimal, real | BigDecimal, int prec) -> BigDecimal

#self?.ldexpBigDecimal

Inverse of frexp. Returns the value of fraction * 10**exponent.

BigMath.ldexp(BigDecimal("0.123456e0"), 3)
#=> 0.123456e3

Parameters:

Returns:



275
# File 'sig/big_math.rbs', line 275

def self?.ldexp: (real | BigDecimal fraction, Integer exponent) -> BigDecimal

#self?.lgamma[ BigDecimal, Integer ]

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]

Parameters:

Returns:



288
# File 'sig/big_math.rbs', line 288

def self?.lgamma: (real | BigDecimal, int prec) -> [ BigDecimal, Integer ]

#self?.logBigDecimal

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.

Parameters:

Returns:



303
# File 'sig/big_math.rbs', line 303

def self?.log: (real | BigDecimal, int prec) -> BigDecimal

#self?.log10BigDecimal

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"

Parameters:

Returns:



321
# File 'sig/big_math.rbs', line 321

def self?.log10: (real | BigDecimal, int prec) -> BigDecimal

#self?.log1pBigDecimal

Computes log(1 + decimal) to the specified number of digits of precision, numeric.

BigMath.log1p(BigDecimal('0.1'), 32).to_s
#=> "0.95310179804324860043952123280765e-1"

Parameters:

Returns:



333
# File 'sig/big_math.rbs', line 333

def self?.log1p: (real | BigDecimal, int prec) -> BigDecimal

#self?.log2BigDecimal

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"

Parameters:

Returns:



351
# File 'sig/big_math.rbs', line 351

def self?.log2: (real | BigDecimal, int prec) -> BigDecimal

#self?.PIBigDecimal

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

BigMath.PI(32).to_s
#=> "0.31415926535897932384626433832795e1"

Parameters:

  • prec (int)

Returns:



40
# File 'sig/big_math.rbs', line 40

def self?.PI: (int prec) -> BigDecimal

#self?.sinBigDecimal

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, 32).to_s
#=> "0.70710807985947359435812921837984e0"

Parameters:

Returns:



365
# File 'sig/big_math.rbs', line 365

def self?.sin: (real | BigDecimal x, int prec) -> BigDecimal

#self?.sinhBigDecimal

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"

Parameters:

Returns:



379
# File 'sig/big_math.rbs', line 379

def self?.sinh: (real | BigDecimal, int prec) -> BigDecimal

#self?.sqrtBigDecimal

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

BigMath.sqrt(BigDecimal('2'), 32).to_s
#=> "0.14142135623730950488016887242097e1"

Parameters:

Returns:



391
# File 'sig/big_math.rbs', line 391

def self?.sqrt: (real | BigDecimal x, int prec) -> BigDecimal

#self?.tanBigDecimal

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"

Parameters:

Returns:



408
# File 'sig/big_math.rbs', line 408

def self?.tan: (real | BigDecimal x, int prec) -> BigDecimal

#self?.tanhBigDecimal

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"

Parameters:

Returns:



422
# File 'sig/big_math.rbs', line 422

def self?.tanh: (real | BigDecimal, int prec) -> BigDecimal