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
-
.coerce_to_bigdecimal(x, prec, method_name) ⇒ Object
Coerce x to BigDecimal with the specified precision.
-
.coerce_validate_prec(prec, method_name, accept_zero: false) ⇒ Object
:nodoc:.
-
.float_log(x) ⇒ Object
Calculates Math.log(x.to_f) considering large or small exponent.
-
.infinity_computation_result ⇒ Object
:nodoc:.
-
.nan_computation_result ⇒ Object
:nodoc:.
-
.newton_loop(prec, initial_precision: BigDecimal.double_fig / 2, safe_margin: 2) ⇒ Object
Iteration for Newton’s method with increasing precision.
-
.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.
-
.underflow_computation_result ⇒ Object
:nodoc:.
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.
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_result ⇒ Object
: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_result ⇒ Object
: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_result ⇒ Object
: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 |