Module: Horologium::Numeric::Precision Private

Defined in:
lib/horologium/numeric/precision.rb,
sig/horologium/numeric/precision.rbs

Overview

This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.

The precision a value computes with: :standard, the fast two-part float (TwoPartFloat), or :exact, the lossless Rational (Exact). This module holds the rules that decide the precision of a result and coerce a value from one precision into another.

The rule for a result is that exactness is contagious: an operation between two :standard values stays :standard, but mixing :standard with :exact promotes to :exact rather than dropping to :standard. Promotion loses nothing, because a two-part float pair is already an exact Rational. What :exact guarantees is Horologium's own arithmetic. It cannot bring back precision an input already lost when it was built.

Constant Summary collapse

NAMES =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

The recognised precisions.

Returns:

  • (Array[Symbol])
%i[standard exact].freeze

Class Method Summary collapse

Class Method Details

.coerce(value, to:) ⇒ Exact .coerce(value, to:) ⇒ TwoPartFloat .coerce(value, to:) ⇒ TwoPartFloat, Exact

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Coerces a numeric value into a precision, losslessly. Promoting a :standard value to :exact keeps its exact value; a value already in the target precision is returned unchanged. There is no lossy path: the contagion rule never moves an :exact value down to :standard, and asking for that raises an error.

Overloads:

Parameters:

  • value (TwoPartFloat, Exact)

    the value to coerce

  • to (Symbol)

    the target precision

Returns:

Raises:

  • (UnknownPrecisionError)

    when to is not recognised

  • (ArgumentError)

    when asked to coerce :exact down to :standard, which would lose precision



62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/horologium/numeric/precision.rb', line 62

def coerce(value, to:)
  case to
  when :exact
    value.is_a?(Exact) ? value : Exact.new(value)
  when :standard
    unless value.is_a?(TwoPartFloat)
      raise ArgumentError,
        "cannot coerce #{value.class} down to :standard without loss"
    end
    value
  else
    raise UnknownPrecisionError.new(to, NAMES)
  end
end

.resolve(left, right) ⇒ Symbol

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The precision a result takes from its two operands. Same precision passes through; a mix of :standard and :exact promotes to :exact.

Parameters:

  • left (Symbol)

    one operand's precision

  • right (Symbol)

    the other operand's precision

Returns:

  • (Symbol)

    the result's precision

Raises:



42
43
44
45
46
47
48
# File 'lib/horologium/numeric/precision.rb', line 42

def resolve(left, right)
  validate!(left)
  validate!(right)
  return :exact if left == :exact || right == :exact

  :standard
end

.validate!(precision) ⇒ Symbol

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Checks that a precision is recognised and returns it.

Parameters:

  • precision (Symbol)

    the precision to check

Returns:

  • (Symbol)

    the same precision

Raises:



28
29
30
31
32
# File 'lib/horologium/numeric/precision.rb', line 28

def validate!(precision)
  return precision if NAMES.include?(precision)

  raise UnknownPrecisionError.new(precision, NAMES)
end

.value_type(precision) ⇒ Class

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The numeric type a value takes at a precision: Exact for :exact and TwoPartFloat for :standard.

Parameters:

  • precision (Symbol)

    the precision

Returns:

  • (Class)

    the type its values take

Raises:



83
84
85
# File 'lib/horologium/numeric/precision.rb', line 83

def value_type(precision)
  (validate!(precision) == :exact) ? Exact : TwoPartFloat
end