is-fixed 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.yardopts +9 -0
- data/lib/is/fixed.rb +231 -0
- metadata +48 -0
data/.yardopts
ADDED
data/lib/is/fixed.rb
ADDED
@@ -0,0 +1,231 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class Fixed < Numeric
|
4
|
+
|
5
|
+
VERSION = '0.2.0'
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
# @return [Integer]
|
10
|
+
attr_accessor :precision
|
11
|
+
|
12
|
+
def precision= value
|
13
|
+
if @precision
|
14
|
+
raise 'Already defined.'
|
15
|
+
elsif self == Fixed
|
16
|
+
raise 'Fixed is an abstract class.'
|
17
|
+
else
|
18
|
+
@precision = value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param [Integer] precision
|
23
|
+
# @return [Class]
|
24
|
+
def subclass precision
|
25
|
+
@@classes ||= []
|
26
|
+
if ! @@classes[precision]
|
27
|
+
@@classes[precision] = Class.new(Fixed)
|
28
|
+
@@classes[precision].precision = precision
|
29
|
+
end
|
30
|
+
@@classes[precision]
|
31
|
+
end
|
32
|
+
|
33
|
+
# @param [Numeric] value
|
34
|
+
# @param [Integer] precision
|
35
|
+
# @return [Fixed]
|
36
|
+
def number value, precision
|
37
|
+
subclass(precision).new(value)
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param [Numeric] value
|
41
|
+
# @return [Fixed]
|
42
|
+
def [] value
|
43
|
+
self.new value
|
44
|
+
end
|
45
|
+
|
46
|
+
# @return [String]
|
47
|
+
def to_s
|
48
|
+
name || "Fixed(#{@precision})"
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [Integer]
|
54
|
+
attr_reader :precision
|
55
|
+
|
56
|
+
# @return [Integer]
|
57
|
+
attr_reader :number
|
58
|
+
|
59
|
+
def precision
|
60
|
+
self.class.precision
|
61
|
+
end
|
62
|
+
|
63
|
+
# @param [Numeric] number
|
64
|
+
# @param [Integer] shift
|
65
|
+
def initialize number = 0, shift = nil
|
66
|
+
if ! precision
|
67
|
+
raise 'Undefined precision.'
|
68
|
+
end
|
69
|
+
case number
|
70
|
+
when Fixed
|
71
|
+
np = number.precision + (shift || 0)
|
72
|
+
if np = precision
|
73
|
+
@number = number.number
|
74
|
+
elsif np < precision
|
75
|
+
@number = number.number * 10 ** (precision - np)
|
76
|
+
else
|
77
|
+
nn = number.number.divmod(10 ** (np - precision))
|
78
|
+
@number = nn[0] + (nn[1] < 5 && 0 || 1)
|
79
|
+
end
|
80
|
+
when Integer
|
81
|
+
np = (shift || 0)
|
82
|
+
if np == precision
|
83
|
+
@number = number
|
84
|
+
elsif np < precision
|
85
|
+
@number = number * 10 ** (precision - np)
|
86
|
+
else
|
87
|
+
nn = number.divmod(10 ** (np - precision))
|
88
|
+
@number = nn[0] + (nn[1] < 5 && 0 || 1)
|
89
|
+
end
|
90
|
+
else
|
91
|
+
np = (shift || 0)
|
92
|
+
@number = (Float(number) * Float(10) ** (precision - np)).round
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# @return [Fixed]
|
97
|
+
def +@
|
98
|
+
self
|
99
|
+
end
|
100
|
+
|
101
|
+
# @return [Fixed]
|
102
|
+
def -@
|
103
|
+
self.class.new -@number, precision
|
104
|
+
end
|
105
|
+
|
106
|
+
# @param [Numeric] other
|
107
|
+
# @return [Fixed]
|
108
|
+
def + other
|
109
|
+
other = self.class.new other
|
110
|
+
self.class.new @number + other.number, precision
|
111
|
+
end
|
112
|
+
|
113
|
+
# @param [Numeric] other
|
114
|
+
# @return [Fixed]
|
115
|
+
def - other
|
116
|
+
self + (-other)
|
117
|
+
end
|
118
|
+
|
119
|
+
# @param [Numeric] other
|
120
|
+
# @return [Fixed]
|
121
|
+
def * other
|
122
|
+
case other
|
123
|
+
when Fixed
|
124
|
+
self.class.new @number * other.number, precision + other.precision
|
125
|
+
when Integer
|
126
|
+
self.class.new @number * other, precision
|
127
|
+
else
|
128
|
+
self.class.new (Float(other) * @number).round, precision
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# @param [Numeric] other
|
133
|
+
# @return [Fixed]
|
134
|
+
def / other
|
135
|
+
# /
|
136
|
+
case other
|
137
|
+
when Fixed
|
138
|
+
n = @number * 10 ** other.precision
|
139
|
+
nn = n.divmod other.number
|
140
|
+
self.class.new nn[0] + (nn[1] < 5 && 0 || 1), precision
|
141
|
+
when Integer
|
142
|
+
nn = @number.divmod other
|
143
|
+
self.class.new nn[0] + (nn[1] < 5 && 0 || 1) / other.number, precision
|
144
|
+
else
|
145
|
+
self.class.new Float(@number) / Float(other), precision
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# @param [Numeric] other
|
150
|
+
# @return [Fixed]
|
151
|
+
def ** other
|
152
|
+
case other
|
153
|
+
when Integer
|
154
|
+
n = self.class.new 1
|
155
|
+
if other > 0
|
156
|
+
other.times { n = n * self }
|
157
|
+
elsif other < 0
|
158
|
+
other.times { n = n / self }
|
159
|
+
end
|
160
|
+
n
|
161
|
+
when Fixed
|
162
|
+
if other.integer?
|
163
|
+
self ** other.to_i
|
164
|
+
else
|
165
|
+
self ** other.to_f
|
166
|
+
end
|
167
|
+
else
|
168
|
+
self.class.new self.to_f ** Float(other)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def integer?
|
173
|
+
@number.divmod(10 ** precision)[1] == 0
|
174
|
+
end
|
175
|
+
|
176
|
+
# @return [Integer]
|
177
|
+
def to_i
|
178
|
+
@number.divmod(10 ** precision)[0]
|
179
|
+
end
|
180
|
+
|
181
|
+
# @return [Float]
|
182
|
+
def to_f
|
183
|
+
Float(@number) / Float(10 ** precision)
|
184
|
+
end
|
185
|
+
|
186
|
+
# @return [String]
|
187
|
+
def to_s
|
188
|
+
s = @number.to_s
|
189
|
+
l = s.length
|
190
|
+
if l <= precision
|
191
|
+
s = '0' * (precision - l + 1) + s
|
192
|
+
end
|
193
|
+
"#{s[0...-precision]}.#{s[-precision..-1]}"
|
194
|
+
end
|
195
|
+
|
196
|
+
def <=> other
|
197
|
+
if precision >= other.precision
|
198
|
+
@number <=> self.class.new(other).number
|
199
|
+
else
|
200
|
+
other.class.new(self).number <=> other.number
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def abs
|
205
|
+
self.class.new(@number.abs, precision)
|
206
|
+
end
|
207
|
+
|
208
|
+
def abs2
|
209
|
+
self * self
|
210
|
+
end
|
211
|
+
|
212
|
+
def coerce other
|
213
|
+
if Integer === other
|
214
|
+
[self.class.new(other), self]
|
215
|
+
else
|
216
|
+
super other
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
protected :precision, :number
|
221
|
+
|
222
|
+
end
|
223
|
+
|
224
|
+
# @param [Integer] precision
|
225
|
+
# @return [Class]
|
226
|
+
def Fixed precision
|
227
|
+
Fixed.subclass precision
|
228
|
+
end
|
229
|
+
|
230
|
+
Currency = Fixed(4)
|
231
|
+
|
metadata
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: is-fixed
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ivan Shikhalev
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-05-11 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Provides a fixed point numeric class.
|
15
|
+
email: shikhalev@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/is/fixed.rb
|
21
|
+
- .yardopts
|
22
|
+
homepage: https://github.com/shikhalev/gems/
|
23
|
+
licenses:
|
24
|
+
- GNU LGPL
|
25
|
+
post_install_message:
|
26
|
+
rdoc_options: []
|
27
|
+
require_paths:
|
28
|
+
- lib
|
29
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ! '>='
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 1.9.2
|
35
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
requirements: []
|
42
|
+
rubyforge_project:
|
43
|
+
rubygems_version: 1.8.25
|
44
|
+
signing_key:
|
45
|
+
specification_version: 3
|
46
|
+
summary: Provides a fixed point numeric class
|
47
|
+
test_files: []
|
48
|
+
has_rdoc:
|