class Numerals::BigDecimalConversion
Public Class Methods
new(options = {})
click to toggle source
Options:
-
:input_rounding (optional, a non-exact Rounding or rounding mode) which is used when input is approximate as the assumed rounding mode which would be used so that the result numeral rounds back to the input number
Calls superclass method
Numerals::ContextConversion::new
# File lib/numerals/conversions/bigdecimal.rb, line 14 def initialize(options = {}) super BigDecimal, options end
Public Instance Methods
exact?(value, options={})
click to toggle source
# File lib/numerals/conversions/bigdecimal.rb, line 39 def exact?(value, options={}) options[:exact] end
number_of_digits(value, options={})
click to toggle source
# File lib/numerals/conversions/bigdecimal.rb, line 27 def number_of_digits(value, options={}) base = options[:base] || 10 precision = x.precs.first decimal_digits = x.split[1].size n = decimal_digits # or use precision? if base == 10 n else Flt::DecNum.context[precision: n].necessary_digits(base) end end
number_to_numeral(number, mode, rounding)
click to toggle source
# File lib/numerals/conversions/bigdecimal.rb, line 43 def number_to_numeral(number, mode, rounding) if @context.special?(number) special_num_to_numeral number else if mode == :exact exact_num_to_numeral number, rounding else # mode == :approximate approximate_num_to_numeral(number, rounding) end end end
numeral_to_number(numeral, mode)
click to toggle source
# File lib/numerals/conversions/bigdecimal.rb, line 55 def numeral_to_number(numeral, mode) if numeral.special? special_numeral_to_num numeral elsif mode == :fixed fixed_numeral_to_num numeral else # mode == :free free_numeral_to_num numeral end end
order_of_magnitude(value, options={})
click to toggle source
# File lib/numerals/conversions/bigdecimal.rb, line 18 def order_of_magnitude(value, options={}) base = options[:base] || 10 if base == 10 value.exponent else (Math.log(value.abs)/Math.log(base)).floor + 1 end end
read(numeral, exact_input, approximate_simplified)
click to toggle source
# File lib/numerals/conversions/bigdecimal.rb, line 100 def read(numeral, exact_input, approximate_simplified) if numeral.special? special_numeral_to_num numeral elsif numeral.approximate? && !exact_input if approximate_simplified # akin to @context.Num(numeral_text, :short) short_numeral_to_num numeral else # akin to @context.Num(numeral_text, :free) free_numeral_to_num numeral end else # akin to @context.Num(numeral_text, :fixed) fixed_numeral_to_num numeral end end
write(number, exact_input, output_rounding)
click to toggle source
# File lib/numerals/conversions/bigdecimal.rb, line 65 def write(number, exact_input, output_rounding) output_base = output_rounding.base input_base = @context.radix if @context.special?(number) special_num_to_numeral number elsif exact_input if output_base == input_base && output_rounding.free? # akin to number.format(base: output_base, simplified: true) if true # ALT.1 just like approximate :short general_num_to_numeral number, output_rounding, false else # ALT.2 just like different bases exact_num_to_numeral number, output_rounding end else # akin to number.format(base: output_base, exact: true) exact_num_to_numeral number, output_rounding end else if output_base == input_base && output_rounding.preserving? # akin to number.format(base: output_base) sign, coefficient, exponent = @context.split(number) Numerals::Numeral.from_coefficient_scale sign*coefficient, exponent, approximate: true elsif output_rounding.simplifying? # akin to number.forma(base: output_base, simplify: true) general_num_to_numeral number, output_rounding, false else # akin to number.forma(base: output_base, all_digits: true) general_num_to_numeral number, output_rounding, true end end end
Private Instance Methods
approximate_num_to_numeral(number, rounding)
click to toggle source
# File lib/numerals/conversions/bigdecimal.rb, line 136 def approximate_num_to_numeral(number, rounding) all_digits = !rounding.free? general_num_to_numeral(number, rounding, all_digits) end
exact_num_to_numeral(number, rounding)
click to toggle source
# File lib/numerals/conversions/bigdecimal.rb, line 127 def exact_num_to_numeral(number, rounding) quotient = number.to_r numeral = Numerals::Numeral.from_quotient(quotient, base: rounding.base) unless rounding.free? numeral = rounding.round(numeral) end numeral end
exact_numeral_to_num(numeral)
click to toggle source
# File lib/numerals/conversions/bigdecimal.rb, line 202 def exact_numeral_to_num(numeral) @context.Num Rational(*numeral.to_quotient), :fixed end
fixed_numeral_to_num(numeral)
click to toggle source
# File lib/numerals/conversions/bigdecimal.rb, line 183 def fixed_numeral_to_num(numeral) # consider: # return exact_numeral_to_num(numeral) if numeral.exact? if numeral.base == 10 unless @context.exact? rounding = Rounding[@context.rounding, precision: @context.precision, base: @context.radix] numeral = rounding.round(numeral) end same_base_numeral_to_num numeral else general_numeral_to_num numeral, :fixed end end
free_numeral_to_num(numeral)
click to toggle source
# File lib/numerals/conversions/bigdecimal.rb, line 206 def free_numeral_to_num(numeral) general_numeral_to_num numeral, :free end
general_num_to_numeral(x, rounding, all_digits)
click to toggle source
# File lib/numerals/conversions/bigdecimal.rb, line 141 def general_num_to_numeral(x, rounding, all_digits) sign, coefficient, exponent = @context.split(x) # the actual number of digits is x.split[1].size # but BigDecimal doesn't keep trailing zeros # we'll use the internal precision which is an implementation detail precision = x.precs.first output_base = rounding.base # here rounding_mode is not the output rounding mode, but the rounding mode used for input rounding_mode = (@input_rounding || rounding).mode # The minimum exponent of BigDecimal numbers is not well defined; # depends of host architecture, version of BigDecimal, etc. # We'll use an arbitrary conservative value. min_exp = -100000000 formatter = Flt::Support::Formatter.new( @context.radix, min_exp, output_base, raise_on_repeat: false ) formatter.format( x, coefficient, exponent, rounding_mode, precision, all_digits ) dec_pos, digits = formatter.digits normalization = :approximate numeral = Numerals::Numeral[digits, sign: sign, point: dec_pos, rep_pos: formatter.repeat, base: output_base, normalize: normalization] numeral = rounding.round(numeral, round_up: formatter.round_up) numeral end
general_numeral_to_num(numeral, mode)
click to toggle source
# File lib/numerals/conversions/bigdecimal.rb, line 210 def general_numeral_to_num(numeral, mode) sign, coefficient, scale = numeral.split reader = Flt::Support::Reader.new(mode: mode) if @input_rounding rounding_mode = @input_rounding.mode else rounding_Mode = @context.rounding end dec_num_context = Flt::DecNum::Context( precision: @context.precision, rounding: @context.rounding ) dec_num = reader.read(dec_num_context, rounding_mode, sign, coefficient, scale, numeral.base) @context.Num dec_num end
same_base_numeral_to_num(numeral)
click to toggle source
# File lib/numerals/conversions/bigdecimal.rb, line 197 def same_base_numeral_to_num(numeral) sign, coefficient, scale = numeral.split @context.Num sign, coefficient, scale end
special_num_to_numeral(x)
click to toggle source
# File lib/numerals/conversions/bigdecimal.rb, line 119 def special_num_to_numeral(x) if x.nan? Numerals::Numeral.nan elsif x.infinite? Numerals::Numeral.infinity @context.sign(x) end end
special_numeral_to_num(numeral)
click to toggle source
# File lib/numerals/conversions/bigdecimal.rb, line 174 def special_numeral_to_num(numeral) case numeral.special when :nan @context.nan when :inf @context.infinity numeral.sign end end