Module: Numerals::Conversions

Defined in:
lib/numerals/conversions.rb

Class Method Summary collapse

Class Method Details

.[](type, options = nil) ⇒ Object



6
7
8
9
10
# File 'lib/numerals/conversions.rb', line 6

def [](type, options = nil)
  if type.respond_to?(:numerals_conversion)
    type.numerals_conversion(options || {})
  end
end

.convert(number, options = {}) ⇒ Object

Convert an number to a different numeric type. Conversion is done by first converting the number to a Numeral, then converting the Numeral to de destination type.

Options:

  • :exact_input Consider the number an exact quantity. Otherwise, for approximate types, insignificant digits will not be converted.

  • :rounding Rounding to be applied during the conversion.

  • :type or :context can be used to define the destination type.

  • :output_mode can have the values :free, :short or :fixed and is used to define how the result is generated.



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/numerals/conversions.rb', line 128

def convert(number, options = {})
  if options[:exact]
    options = options.merge(exact_input: true, ouput_mode: :free)
  end

  exact_input = options[:exact_input] || false
  rounding = Rounding[options[:rounding] || Rounding[]]
  output_mode = options[:output_mode] || :free # :short :free :fixed
  type_options =  options[:type_options]
  selector = options[:context] || options[:type]
  output_conversions = self[selector, type_options]
  if output_conversions && output_conversions.respond_to?(:context)
    output_base = output_conversions.context.radix
    if rounding.base != output_base && rounding.free?
      rounding = rounding[base: output_base]
    end
  end

  if number.is_a?(Numeral)
    numeral = number
  else
    input_options = {
      exact: exact_input,
      rounding: rounding,
      type_options: type_options
    }
    numeral = write(number, input_options)
  end

  output_options = {
    type: options[:type], context: options[:context]
  }
  case output_mode
  when :short
    output_options.merge!(
      exact: false,
      simplify: true
    )
  when :free
    output_options.merge!(
      exact: false,
      simplify: false
    )
  when :fixed
    output_options.merge!(
      exact: true,
      simplify: false
    )
  end
  if !output_options[:exact] && numeral.exact?
    numeral.approximate!
  end
  read(numeral, output_options)
end

.exact?(number, options = {}) ⇒ Boolean

Returns:

  • (Boolean)


109
110
111
# File 'lib/numerals/conversions.rb', line 109

def exact?(number, options = {})
  self[number.class, options[:type_options]].exact?(number, options)
end

.number_of_digits(number, options = {}) ⇒ Object



16
17
18
# File 'lib/numerals/conversions.rb', line 16

def number_of_digits(number, options={})
  self[number.class, options[:type_options]].number_of_digits(number, options)
end

.order_of_magnitude(number, options = {}) ⇒ Object



12
13
14
# File 'lib/numerals/conversions.rb', line 12

def order_of_magnitude(number, options={})
  self[number.class, options[:type_options]].order_of_magnitude(number, options)
end

.read(numeral, options = {}) ⇒ Object

Convert Numeral to Number

read numeral, options={}

If the input numeral is approximate and the destination type allows for arbitrary precision, then the destination context precision will be ignored and the precision of the input will be preserved. The :simplify option affects this case by generating only the mininimun number of digits needed.

The :exact option will prevent this behaviour and always treat input as exact.

Valid output options:

  • :type class of the output number

  • :context context (in the case of Flt::Num, Float) for the output

  • :simplify (for approximate input numeral/arbitrary precision type only)

  • :exact treat input numeral as if exact



40
41
42
43
44
45
46
# File 'lib/numerals/conversions.rb', line 40

def read(numeral, options={})
  selector = options[:context] || options[:type]
  exact_input = options[:exact]
  approximate_simplified = options[:simplify]
  conversions = self[selector, options[:type_options]]
  conversions.read(numeral, exact_input, approximate_simplified)
end

.write(number, options = {}) ⇒ Object

Convert Number to Numeral

write number, options={}

Valid options:

  • :rounding (a Rounding) (which defines output base as well)

  • :exact (exact input indicator)

Approximate mode:

If the input is treated as an approximation (which is the case for types such as Flt::Num, Float,… unless the :exact option is true) then no ‘spurious’ digits will be shown (digits that can take any value and the numeral still would convert to the original number if rounded to the same precision)

In approximate mode, if rounding is simplifying? (:short), the shortest representation which rounds back to the origina number with the same precision is used. If rounding is :free and the output base is the same as the number internal radix, the exact precision (trailing zeros) of the number is represented.

Exact mode:

Is used for ‘exact’ types (such as Integer, Rational) or when the :exact option is defined to be true.

The number is treated as an exact value, and converted according to Rounding. (in this case the :free and :short precision roundings are equivalent)

Summary

In result there are 5 basically diferent conversion modes. Three of them apply only to approximate values, so they are not available for all input types:

  • ‘Short’ mode, which produces an exact Numeral. Used when input is not exact and rounding precision is :short.

  • ‘Free’ mode, which produces an approximate Numeral. Used when input is not exact and rounding precision is :short.

  • ‘Fixed’ mode, which produces an approximate Numeral. Used when input isnot exact and rounding precision is limited.

The other two modes are applied to exact input, so they’re available for all input types (since all can be taken as exact with the :exact option):

  • ‘All’ mode, which produces an exact Numeral. Used when input is exact and rounding precision is :free (or :short).

  • ‘Rounded’ mode, which produces an approximate Numeral. Used when input is exact and rounding precision is limited.



102
103
104
105
106
107
# File 'lib/numerals/conversions.rb', line 102

def write(number, options = {})
  output_rounding = Rounding[options[:rounding] || Rounding[]]
  conversion = self[number.class, options[:type_options]]
  exact_input = conversion.exact?(number, options)
  conversion.write(number, exact_input, output_rounding)
end