Class: Horologium::Numeric::Exact
- Inherits:
-
Object
- Object
- Horologium::Numeric::Exact
- 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.
Instance Attribute Summary collapse
-
#value ⇒ Rational
readonly
private
Protected so == and eql? can read another Exact's Rational.
Instance Method Summary collapse
- #*(scalar) ⇒ Horologium::Numeric::Exact
- #+(other) ⇒ Horologium::Numeric::Exact
- #-(other) ⇒ Horologium::Numeric::Exact
- #/(scalar) ⇒ Horologium::Numeric::Exact
- #==(other) ⇒ Boolean
- #eql?(other) ⇒ Boolean
- #hash ⇒ Integer
-
#initialize(value) ⇒ Exact
constructor
A new instance of Exact.
-
#scalar_rational(scalar) ⇒ Rational
An exact value is not a scalar, and passing one where a number belongs is a mistake, so it is refused.
-
#to_f ⇒ Float
The value as a single Float.
- #to_r ⇒ Rational
Constructor Details
#initialize(value) ⇒ Exact
Returns a new instance of Exact.
26 27 28 29 |
# File 'lib/horologium/numeric/exact.rb', line 26 def initialize(value) @value = value.to_r freeze end |
Instance Attribute Details
#value ⇒ Rational (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.
Protected so == and eql? can read another Exact's Rational.
94 95 96 |
# File 'lib/horologium/numeric/exact.rb', line 94 def value @value end |
Instance Method Details
#*(scalar) ⇒ Horologium::Numeric::Exact
46 47 48 |
# File 'lib/horologium/numeric/exact.rb', line 46 def *(scalar) # rubocop:disable Naming/BinaryOperatorParameterName self.class.new(value * scalar_rational(scalar)) end |
#+(other) ⇒ Horologium::Numeric::Exact
33 34 35 |
# File 'lib/horologium/numeric/exact.rb', line 33 def +(other) self.class.new(value + other.value) end |
#-(other) ⇒ Horologium::Numeric::Exact
39 40 41 |
# File 'lib/horologium/numeric/exact.rb', line 39 def -(other) self.class.new(value - other.value) end |
#/(scalar) ⇒ Horologium::Numeric::Exact
53 54 55 |
# File 'lib/horologium/numeric/exact.rb', line 53 def /(scalar) # rubocop:disable Naming/BinaryOperatorParameterName self.class.new(value / scalar_rational(scalar)) end |
#==(other) ⇒ Boolean
59 60 61 |
# File 'lib/horologium/numeric/exact.rb', line 59 def ==(other) other.is_a?(self.class) && value == other.value end |
#eql?(other) ⇒ Boolean
65 66 67 |
# File 'lib/horologium/numeric/exact.rb', line 65 def eql?(other) other.is_a?(self.class) && value.eql?(other.value) end |
#hash ⇒ Integer
70 71 72 |
# File 'lib/horologium/numeric/exact.rb', line 70 def hash value.hash end |
#scalar_rational(scalar) ⇒ Rational
An exact value is not a scalar, and passing one where a number belongs is a mistake, so it is refused.
104 105 106 107 108 109 110 111 112 113 |
# File 'lib/horologium/numeric/exact.rb', line 104 def scalar_rational(scalar) case scalar when Integer, Float, Rational scalar.to_r else raise ArgumentError, "an Exact multiplies and divides by a plain number, " \ "got a #{scalar.class}" end end |
#to_f ⇒ Float
The value as a single Float. A Float cannot hold what a Rational holds, so the extra precision is dropped here. Do it at the end, once the arithmetic is done.
84 85 86 |
# File 'lib/horologium/numeric/exact.rb', line 84 def to_f value.to_f end |
#to_r ⇒ Rational
75 76 77 |
# File 'lib/horologium/numeric/exact.rb', line 75 def to_r value end |