Class: Horologium::Numeric::Exact

Inherits:
Object
  • Object
show all
Defined in:
lib/horologium/numeric/exact.rb,
sig/horologium/numeric/exact.rbs

Overview

A number stored as an exact Rational, with no rounding. Where TwoPartFloat trades a little accuracy for the speed of Float arithmetic, Exact keeps the value exactly, as a ratio of two integers.

The value is frozen on creation.

Examples:

An exact third, which no Float can hold

Horologium::Numeric::Exact.new(Rational(1, 3)) ==
  Horologium::Numeric::Exact.new(Rational(1, 3))
# => true

See Also:

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(value) ⇒ Exact

Returns a new instance of Exact.

Parameters:

  • value (Integer, Float, Rational)

    the number to store, converted to an exact Rational with to_r. A Float is stored as its exact binary value, which is not always the decimal you typed, so pass a Rational when you mean an exact decimal. Exact records the value it is given faithfully; it does not recover precision already lost before construction.



26
27
28
29
# File 'lib/horologium/numeric/exact.rb', line 26

def initialize(value)
  @value = value.to_r
  freeze
end

Instance Attribute Details

#valueRational (readonly)

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 stored Rational. It is protected so == and eql? can read another Exact value's Rational without exposing it publicly.

Returns:

  • (Rational)


127
128
129
# File 'lib/horologium/numeric/exact.rb', line 127

def value
  @value
end

Instance Method Details

#*(scalar) ⇒ Horologium::Numeric::Exact

Multiplies by a plain number. The number becomes an exact Rational, so the product stays exact.

Examples:

Horologium::Numeric::Exact.new(Rational(1, 3)) * 6 ==
  Horologium::Numeric::Exact.new(2)
# => true

Parameters:

  • scalar (Numeric)

    the number to multiply by

Returns:



67
68
69
# File 'lib/horologium/numeric/exact.rb', line 67

def *(scalar) # rubocop:disable Naming/BinaryOperatorParameterName
  self.class.new(value * scalar.to_r)
end

#+(other) ⇒ Horologium::Numeric::Exact

Adds another exact value. Both are Rationals, so the sum is exact.

Examples:

Horologium::Numeric::Exact.new(Rational(1, 3)) +
  Horologium::Numeric::Exact.new(Rational(1, 6)) ==
  Horologium::Numeric::Exact.new(Rational(1, 2))
# => true

Parameters:

Returns:



40
41
42
# File 'lib/horologium/numeric/exact.rb', line 40

def +(other)
  self.class.new(value + other.value)
end

#-(other) ⇒ Horologium::Numeric::Exact

Subtracts another exact value. Both are Rationals, so the difference is exact.

Examples:

Horologium::Numeric::Exact.new(Rational(1, 2)) -
  Horologium::Numeric::Exact.new(Rational(1, 6)) ==
  Horologium::Numeric::Exact.new(Rational(1, 3))
# => true

Parameters:

Returns:



54
55
56
# File 'lib/horologium/numeric/exact.rb', line 54

def -(other)
  self.class.new(value - other.value)
end

#/(scalar) ⇒ Horologium::Numeric::Exact

Divides by a plain number. The number becomes an exact Rational, so the quotient stays exact.

Examples:

Horologium::Numeric::Exact.new(2) / 6 ==
  Horologium::Numeric::Exact.new(Rational(1, 3))
# => true

Parameters:

  • scalar (Numeric)

    the number to divide by

Returns:



80
81
82
# File 'lib/horologium/numeric/exact.rb', line 80

def /(scalar) # rubocop:disable Naming/BinaryOperatorParameterName
  self.class.new(value / scalar.to_r)
end

#==(other) ⇒ Boolean

Two values are equal when their Rationals are equal.

Examples:

Horologium::Numeric::Exact.new(1) == Horologium::Numeric::Exact.new(1)
# => true

Parameters:

  • other (Object)

    the object to compare

Returns:

  • (Boolean)

    true when other is an Exact with an equal value



91
92
93
# File 'lib/horologium/numeric/exact.rb', line 91

def ==(other)
  other.is_a?(self.class) && value == other.value
end

#eql?(other) ⇒ Boolean

The stricter equality used for Hash keys and Sets. It matches when the Rationals are eql?, which for Rational is the same test as ==.

Parameters:

  • other (Object)

    the object to compare

Returns:

  • (Boolean)

    true when other is an Exact with an eql? value



100
101
102
# File 'lib/horologium/numeric/exact.rb', line 100

def eql?(other)
  other.is_a?(self.class) && value.eql?(other.value)
end

#hashInteger

Returns a hash built from the Rational, so equal values share a hash and can be used as Hash keys.

Returns:

  • (Integer)

    a hash built from the Rational, so equal values share a hash and can be used as Hash keys



106
107
108
# File 'lib/horologium/numeric/exact.rb', line 106

def hash
  value.hash
end

#to_rRational

The stored value as a Rational.

Examples:

Horologium::Numeric::Exact.new(Rational(1, 3)).to_r == Rational(1, 3)
# => true

Returns:

  • (Rational)


116
117
118
# File 'lib/horologium/numeric/exact.rb', line 116

def to_r
  value
end