Class: Fixed

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/fixed.rb,
lib/fixed/version.rb

Constant Summary collapse

VERSION =
"1.1.0"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(fractions) ⇒ Fixed

Returns a new instance of Fixed.



34
35
36
37
38
# File 'lib/fixed.rb', line 34

def initialize(fractions)
  raise unless Integer === fractions
  @fractions = fractions
  freeze
end

Instance Attribute Details

#fractionsObject (readonly)

——- helpers ————————————————-



188
189
190
# File 'lib/fixed.rb', line 188

def fractions
  @fractions
end

Class Method Details

.from_fractions(fractions) ⇒ Object



48
49
50
# File 'lib/fixed.rb', line 48

def self.from_fractions(fractions)
  new fractions
end

.from_number(number) ⇒ Object



44
45
46
# File 'lib/fixed.rb', line 44

def self.from_number(number)
  new number_as_fractions(number)
end

.from_snapshot(arg, options) ⇒ Object



181
182
183
# File 'lib/fixed.rb', line 181

def self.from_snapshot(arg, options)
  String === arg ? self.parse(arg) : arg
end

.parse(str) ⇒ Object



40
41
42
# File 'lib/fixed.rb', line 40

def self.parse(str)
  new string_as_fractions(str)
end

.smallestObject



52
53
54
# File 'lib/fixed.rb', line 52

def self.smallest
  new 1
end

.zeroObject



56
57
58
# File 'lib/fixed.rb', line 56

def self.zero
  new 0
end

Instance Method Details

#*(number) ⇒ Object



70
71
72
73
74
75
# File 'lib/fixed.rb', line 70

def *(number)
  make(division_with_rounding(
    self.fractions * number.fractions,
    1000000000000000000,
  ))
end

#+(number) ⇒ Object

——- arithmetics ———————————————-



62
63
64
# File 'lib/fixed.rb', line 62

def +(number)
  make(self.fractions + number.fractions)
end

#-(number) ⇒ Object



66
67
68
# File 'lib/fixed.rb', line 66

def -(number)
  make(self.fractions - number.fractions)
end

#-@Object



84
85
86
# File 'lib/fixed.rb', line 84

def -@
  make(-self.fractions)
end

#/(number) ⇒ Object



77
78
79
80
81
82
# File 'lib/fixed.rb', line 77

def /(number)
  make(division_with_rounding(
    1000000000000000000 * self.fractions,
    number.fractions,
  ))
end

#<=>(number) ⇒ Object

——- comparing ———————————————–



119
120
121
122
# File 'lib/fixed.rb', line 119

def <=>(number)
  return nil unless Fixed === number
  self.fractions <=> number.fractions
end

#==(number) ⇒ Object



124
125
126
# File 'lib/fixed.rb', line 124

def ==(number)
  Fixed === number && self.fractions == number.fractions
end

#absObject



88
89
90
# File 'lib/fixed.rb', line 88

def abs
  make(self.fractions.abs)
end

#format(precision = 8) ⇒ Object



155
156
157
158
159
160
161
162
# File 'lib/fixed.rb', line 155

def format(precision = 8)
  raise "expected 1..18, got #{precision.inspect}" unless (0..18) === precision

  rounded_fractions = division_with_rounding(@fractions, 10 ** (18 - precision))
  str = rounded_fractions.abs.to_s.rjust(precision + 1, ?0)
  str.insert(-1 - precision, ?.) if precision > 0
  "#{?- if @fractions < 0}#{str}#{?* if @fractions != 0 && str =~ /^[-0\.]*$/}"
end

#inspectObject

——- printing ————————————————



143
144
145
146
147
148
149
# File 'lib/fixed.rb', line 143

def inspect
  if @fractions >= 0
    @fractions.to_s.rjust(19, ?0).insert(-19, ?.)
  else
    "-#{@fractions.abs.to_s.rjust(19, ?0).insert(-19, ?.)}"
  end
end

#negative?Boolean

Returns:

  • (Boolean)


128
129
130
# File 'lib/fixed.rb', line 128

def negative?
  @fractions < 0
end

#positive?Boolean

Returns:

  • (Boolean)


132
133
134
# File 'lib/fixed.rb', line 132

def positive?
  @fractions > 0
end

#pretty_format(precision = 8) ⇒ Object



164
165
166
167
168
169
170
171
172
# File 'lib/fixed.rb', line 164

def pretty_format(precision = 8)
  str = format(precision).dup
  stop = negative? ? 4 : 3

  n = str.index('.') || str.length
  str.insert(n -= 3, ',') while n > stop

  return str
end

#split(*numbers) ⇒ Object

Raises:

  • (ArgumentError)


92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/fixed.rb', line 92

def split(*numbers)
  ratios = numbers.map(&:to_fixed)
  raise ArgumentError if ratios.any?(&:negative?)
  raise ArgumentError if ratios.all?(&:zero?)

  # This method ensures that the calculated portions add up to the original
  # value and that no eps are lost due to rounding errors or other issues.

  remainder = ratios.reduce(:+)
  number = self

  ratios.map do |ratio|
    next Fixed.zero if remainder.zero?

    part = make(division_with_rounding(
      number.fractions * ratio.fractions,
      remainder.fractions,
    ))
    remainder -= ratio
    number -= part
    part
  end
end

#to_fixedObject



190
191
192
# File 'lib/fixed.rb', line 190

def to_fixed
  self
end

#to_json(state) ⇒ Object

——- serialization ——————————————-



177
178
179
# File 'lib/fixed.rb', line 177

def to_json(state)
  inspect.to_json(state)
end

#to_s(precision = 8) ⇒ Object



151
152
153
# File 'lib/fixed.rb', line 151

def to_s(precision = 8)
  format(precision)
end

#zero?Boolean

Returns:

  • (Boolean)


136
137
138
# File 'lib/fixed.rb', line 136

def zero?
  @fractions == 0
end