Module: BigDecimal::Internal

Defined in:
lib/bigdecimal.rb

Overview

:nodoc:

Constant Summary collapse

EXTRA_PREC =

Default extra precision for intermediate calculations This value is currently the same as BigDecimal.double_fig, but defined separately for future changes.

16

Class Method Summary collapse

Class Method Details

.coerce_to_bigdecimal(x, prec, method_name) ⇒ Object

Coerce x to BigDecimal with the specified precision. TODO: some methods (example: BigMath.exp) require more precision than specified to coerce.

Raises:

  • (ArgumentError)


21
22
23
24
25
26
27
28
29
30
31
# File 'lib/bigdecimal.rb', line 21

def self.coerce_to_bigdecimal(x, prec, method_name) # :nodoc:
  case x
  when BigDecimal
    return x
  when Integer, Float
    return BigDecimal(x, 0)
  when Rational
    return BigDecimal(x, [prec, 2 * BigDecimal.double_fig].max)
  end
  raise ArgumentError, "#{x.inspect} can't be coerced into BigDecimal"
end

.coerce_validate_prec(prec, method_name, accept_zero: false) ⇒ Object

:nodoc:



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/bigdecimal.rb', line 33

def self.coerce_validate_prec(prec, method_name, accept_zero: false) # :nodoc:
  unless Integer === prec
    original = prec
    # Emulate Integer.try_convert for ruby < 3.1
    if prec.respond_to?(:to_int)
      prec = prec.to_int
    else
      raise TypeError, "no implicit conversion of #{original.class} into Integer"
    end
    raise TypeError, "can't convert #{original.class} to Integer" unless Integer === prec
  end

  if accept_zero
    raise ArgumentError, "Negative precision for #{method_name}" if prec < 0
  else
    raise ArgumentError, "Zero or negative precision for #{method_name}" if prec <= 0
  end
  prec
end

.float_log(x) ⇒ Object

Calculates Math.log(x.to_f) considering large or small exponent



87
88
89
# File 'lib/bigdecimal.rb', line 87

def self.float_log(x) # :nodoc:
  Math.log(x._decimal_shift(-x.exponent).to_f) + x.exponent * Math.log(10)
end

.infinity_computation_resultObject

:nodoc:



53
54
55
56
57
58
# File 'lib/bigdecimal.rb', line 53

def self.infinity_computation_result # :nodoc:
  if BigDecimal.mode(BigDecimal::EXCEPTION_ALL).anybits?(BigDecimal::EXCEPTION_INFINITY)
    raise FloatDomainError, "Computation results in 'Infinity'"
  end
  BigDecimal::INFINITY
end

.nan_computation_resultObject

:nodoc:



67
68
69
70
71
72
# File 'lib/bigdecimal.rb', line 67

def self.nan_computation_result # :nodoc:
  if BigDecimal.mode(BigDecimal::EXCEPTION_ALL).anybits?(BigDecimal::EXCEPTION_NaN)
    raise FloatDomainError, "Computation results to 'NaN'"
  end
  BigDecimal::NAN
end

.newton_loop(prec, initial_precision: BigDecimal.double_fig / 2, safe_margin: 2) ⇒ Object

Iteration for Newton’s method with increasing precision



75
76
77
78
79
80
81
82
83
84
# File 'lib/bigdecimal.rb', line 75

def self.newton_loop(prec, initial_precision: BigDecimal.double_fig / 2, safe_margin: 2) # :nodoc:
  precs = []
  while prec > initial_precision
    precs << prec
    prec = (precs.last + 1) / 2 + safe_margin
  end
  precs.reverse_each do |p|
    yield p
  end
end

.taylor_sum_binary_splitting(x, ds, prec) ⇒ Object

Calculating Taylor series sum using binary splitting method Calculates f(x) = (x/d0)*(1+(x/d1)*(1+(x/d2)*(1+(x/d3)*(1+…)))) x.n_significant_digits or ds.size must be small to be performant.



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/bigdecimal.rb', line 94

def self.taylor_sum_binary_splitting(x, ds, prec) # :nodoc:
  fs = ds.map {|d| [0, BigDecimal(d)] }
  # fs = [[a0, a1], [b0, b1], [c0, c1], ...]
  # f(x) = a0/a1+(x/a1)*(1+b0/b1+(x/b1)*(1+c0/c1+(x/c1)*(1+d0/d1+(x/d1)*(1+...))))
  while fs.size > 1
    # Merge two adjacent fractions
    # from: (1 + a0/a1 + x/a1 * (1 + b0/b1 + x/b1 * rest))
    # to:   (1 + (a0*b1+x*(b0+b1))/(a1*b1) + (x*x)/(a1*b1) * rest)
    xn = xn ? xn.mult(xn, prec) : x
    fs = fs.each_slice(2).map do |(a, b)|
      b ||= [0, BigDecimal(1)._decimal_shift([xn.exponent, 0].max + 2)]
      [
        (a[0] * b[1]).add(xn * (b[0] + b[1]), prec),
        a[1].mult(b[1], prec)
      ]
    end
  end
  BigDecimal(fs[0][0]).div(fs[0][1], prec)
end

.underflow_computation_resultObject

:nodoc:



60
61
62
63
64
65
# File 'lib/bigdecimal.rb', line 60

def self.underflow_computation_result # :nodoc:
  if BigDecimal.mode(BigDecimal::EXCEPTION_ALL).anybits?(BigDecimal::EXCEPTION_UNDERFLOW)
    raise FloatDomainError, 'Exponent underflow'
  end
  BigDecimal(0)
end