class Numerals::FloatConversion
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/float.rb, line 12 def initialize(options={}) super Float, options end
Public Instance Methods
exact?(value, options={})
click to toggle source
# File lib/numerals/conversions/float.rb, line 34 def exact?(value, options={}) options[:exact] end
number_of_digits(value, options={})
click to toggle source
# File lib/numerals/conversions/float.rb, line 25 def number_of_digits(value, options={}) base = options[:base] || 10 if base == @context.radix @context.precision else @context.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/float.rb, line 39 def number_to_numeral(number, mode, rounding) if @context.special?(number) special_float_to_numeral(number) else if mode == :exact exact_float_to_numeral number, rounding else # mode == :approximate approximate_float_to_numeral(number, rounding) end end end
numeral_to_number(numeral, mode)
click to toggle source
# File lib/numerals/conversions/float.rb, line 51 def numeral_to_number(numeral, mode) if numeral.special? special_numeral_to_float numeral elsif mode == :fixed fixed_numeral_to_float numeral else # mode == :free free_numeral_to_float numeral end end
order_of_magnitude(value, options={})
click to toggle source
# File lib/numerals/conversions/float.rb, line 16 def order_of_magnitude(value, options={}) base = options[:base] || 10 # @contex.radix if base == 10 Math.log10(value.abs).floor + 1 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/float.rb, line 93 def read(numeral, exact_input, approximate_simplified) if numeral.special? special_numeral_to_float numeral # elsif numeral.approximate? && !exact_input # if approximate_simplified # # akin to @context.Num(numeral_text, :short) # short_numeral_to_float numeral # else # # akin to @context.Num(numeral_text, :free) # free_numeral_to_float numeral # end else # akin to @context.Num(numeral_text, :fixed) fixed_numeral_to_float numeral end end
write(number, exact_input, output_rounding)
click to toggle source
# File lib/numerals/conversions/float.rb, line 61 def write(number, exact_input, output_rounding) output_base = output_rounding.base input_base = @context.radix if @context.special?(number) special_float_to_numeral number elsif exact_input if output_base == input_base && output_rounding.free? # akin to number.format(base: output_base, simplified: true) general_float_to_numeral number, output_rounding, false else # akin to number.format(base: output_base, exact: true) exact_float_to_numeral number, output_rounding end else if output_base == input_base && output_rounding.preserving? # akin to number.format(base: output_base) sign, coefficient, exp = @context.split(number) Numerals::Numeral.from_coefficient_scale( sign*coefficient, exp, approximate: true, base: output_base ) elsif output_rounding.simplifying? # akin to number.forma(base: output_base, simplify: true) general_float_to_numeral number, output_rounding, false else # akin to number.forma(base: output_base, all_digits: true) general_float_to_numeral number, output_rounding, true end end end
Private Instance Methods
approximate_float_to_numeral(number, rounding)
click to toggle source
# File lib/numerals/conversions/float.rb, line 129 def approximate_float_to_numeral(number, rounding) all_digits = !rounding.free? general_float_to_numeral(number, rounding, all_digits) end
conmensurable_base_numeral_to_float(numeral)
click to toggle source
# File lib/numerals/conversions/float.rb, line 234 def conmensurable_base_numeral_to_float(numeral) general_numeral_to_float numeral, :fixed end
exact_float_to_numeral(number, rounding)
click to toggle source
# File lib/numerals/conversions/float.rb, line 120 def exact_float_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_float(numeral)
click to toggle source
# File lib/numerals/conversions/float.rb, line 192 def exact_numeral_to_float(numeral) Rational(*numeral.to_quotient).to_f end
fixed_numeral_to_float(numeral)
click to toggle source
# File lib/numerals/conversions/float.rb, line 171 def fixed_numeral_to_float(numeral) return exact_numeral_to_float(numeral) if numeral.exact? if numeral.base == @context.radix same_base_numeral_to_float numeral else # representable_digits: number of numeral.base digits that can always be converted to Float and back # to a numeral preserving its value. representable_digits = @context.representable_digits(numeral.base) k = numeral.scale if !@input_rounding && numeral.digits.size <= representable_digits && k.abs <= representable_digits representable_numeral_to_float numeral elsif !@input_rounding && (k > 0 && numeral.point < 2*representable_digits) near_representable_numeral_to_float numeral elsif numeral.base.modulo(@context.radix) == 0 conmensurable_base_numeral_to_float numeral else general_numeral_to_float numeral, :fixed end end end
free_numeral_to_float(numeral)
click to toggle source
# File lib/numerals/conversions/float.rb, line 196 def free_numeral_to_float(numeral) # raise "Invalid Conversion" # Float does not support free (arbitrary precision) # fixed_numeral_to_float numeral # consider: # return general_numeral_to_float(numeral, :short) if numeral.exact? general_numeral_to_float numeral, :free end
general_float_to_numeral(x, rounding, all_digits)
click to toggle source
# File lib/numerals/conversions/float.rb, line 134 def general_float_to_numeral(x, rounding, all_digits) sign, coefficient, exponent = @context.split(x) precision = @context.precision 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: rep_pos, base: output_base, normalize: normalization] numeral = rounding.round(numeral, round_up: formatter.round_up) numeral end
general_numeral_to_float(numeral, mode)
click to toggle source
# File lib/numerals/conversions/float.rb, line 238 def general_numeral_to_float(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
near_representable_numeral_to_float(numeral)
click to toggle source
# File lib/numerals/conversions/float.rb, line 226 def near_representable_numeral_to_float(numeral) value, scale = numeral.to_value_scale j = scale - numeral.digits.size x = value.to_f * Float(numeral.base**(j)) x *= Float(numeral.base**(scale - j)) x end
representable_numeral_to_float(numeral)
click to toggle source
# File lib/numerals/conversions/float.rb, line 215 def representable_numeral_to_float(numeral) value, scale = numeral.to_value_scale x = value.to_f if scale < 0 x /= Float(numeral.base**-scale) else x *= Float(numeral.base**scale) end x end
same_base_numeral_to_float(numeral)
click to toggle source
# File lib/numerals/conversions/float.rb, line 210 def same_base_numeral_to_float(numeral) sign, coefficient, scale = numeral.split @context.Num(sign, coefficient, scale) end
short_numeral_to_float(numeral)
click to toggle source
# File lib/numerals/conversions/float.rb, line 204 def short_numeral_to_float(numeral) # raise "Invalid Conversion" # Float does not support short (arbitrary precision) # fixed_numeral_to_float numeral general_numeral_to_float numeral, :short end
special_float_to_numeral(x)
click to toggle source
# File lib/numerals/conversions/float.rb, line 112 def special_float_to_numeral(x) if x.nan? Numerals::Numeral.nan elsif x.infinite? Numerals::Numeral.infinity @context.sign(x) end end
special_numeral_to_float(numeral)
click to toggle source
# File lib/numerals/conversions/float.rb, line 162 def special_numeral_to_float(numeral) case numeral.special when :nan @context.nan when :inf @context.infinity numeral.sign end end