class Numerals::FltConversion

Public Class Methods

new(context_or_type, 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. :context can be used to use the numeric context as input rounding. input_rounding is also used to round input …

Calls superclass method Numerals::ContextConversion::new
# File lib/numerals/conversions/flt.rb, line 16
def initialize(context_or_type, options={})
  super
end

Public Instance Methods

exact?(value, options={}) click to toggle source
# File lib/numerals/conversions/flt.rb, line 38
def exact?(value, options={})
  options[:exact]
end
number_of_digits(value, options={}) click to toggle source
# File lib/numerals/conversions/flt.rb, line 29
def number_of_digits(value, options={})
  base = options[:base] || 10
  if base == @context.radix
    value.number_of_digits
  else
    x.class.context[precision: value.number_of_digits].necessary_digits(base)
  end
end
number_to_numeral(number, mode, rounding) click to toggle source

mode is either :exact or :approximate

# File lib/numerals/conversions/flt.rb, line 43
def number_to_numeral(number, mode, rounding)
  if number.special? # @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/flt.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/flt.rb, line 20
def order_of_magnitude(value, options={})
  base = options[:base] || 10 # value.num_class.radix
  if value.class.radix == base
    value.adjusted_exponent + 1
  else
    value.abs.log(base).floor + 1
  end
end
read(numeral, exact_input, approximate_simplified) click to toggle source
# File lib/numerals/conversions/flt.rb, line 96
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)
    numeral = numeral.exact if exact_input
    fixed_numeral_to_num numeral
  end
end
write(number, exact_input, output_rounding) click to toggle source
# File lib/numerals/conversions/flt.rb, line 65
def write(number, exact_input, output_rounding)
  output_base = output_rounding.base
  input_base = @context.radix

  if number.special? # @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)
      general_num_to_numeral number, output_rounding, false
    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)
      Numeral.from_coefficient_scale(
        number.sign*number.coefficient, number.integral_exponent,
        approximate: true, base: output_base
      )
    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/flt.rb, line 133
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/flt.rb, line 124
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/flt.rb, line 197
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/flt.rb, line 174
def fixed_numeral_to_num(numeral)
  # consider:
  # return exact_numeral_to_num(numeral) if numeral.exact?
  if numeral.base == @context.radix
    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
    if numeral.repeating? # numeral.exact?
      exact_numeral_to_num(numeral)
    else
      general_numeral_to_num numeral, :fixed
    end
  end
end
free_numeral_to_num(numeral) click to toggle source
# File lib/numerals/conversions/flt.rb, line 201
def free_numeral_to_num(numeral)
  if numeral.base == @context.radix
    same_base_numeral_to_num numeral
  else
    general_numeral_to_num numeral, :free
  end
end
general_num_to_numeral(x, rounding, all_digits) click to toggle source
# File lib/numerals/conversions/flt.rb, line 138
def general_num_to_numeral(x, rounding, all_digits)
  sign, coefficient, exponent = x.split # @context.split(x)
  precision = x.number_of_digits
  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

  formatter = Flt::Support::Formatter.new(
    @context.radix, @context.etiny, output_base, raise_on_repeat: false
  )
  formatter.format(
    x, coefficient, exponent, rounding_mode, precision, all_digits
  )

  dec_pos, digits = formatter.digits
  rep_pos = formatter.repeat

  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/flt.rb, line 213
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
  reader.read(@context, rounding_mode, sign, coefficient, scale, numeral.base).tap do
    # @exact = reader.exact?
  end
end
same_base_numeral_to_num(numeral) click to toggle source
# File lib/numerals/conversions/flt.rb, line 192
def same_base_numeral_to_num(numeral)
  sign, coefficient, scale = numeral.split
  @context.Num sign, coefficient, scale
end
short_numeral_to_num(numeral) click to toggle source
# File lib/numerals/conversions/flt.rb, line 209
def short_numeral_to_num(numeral)
  general_numeral_to_num numeral, :short
end
special_num_to_numeral(x) click to toggle source
# File lib/numerals/conversions/flt.rb, line 116
def special_num_to_numeral(x)
  if x.nan?
    Numeral.nan
  elsif x.infinite?
    Numeral.infinity @context.sign(x)
  end
end
special_numeral_to_num(numeral) click to toggle source
# File lib/numerals/conversions/flt.rb, line 165
def special_numeral_to_num(numeral)
  case numeral.special
  when :nan
    @context.nan
  when :inf
    @context.infinity numeral.sign
  end
end