radix-firstbanco 2.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.
@@ -0,0 +1,217 @@
1
+ require 'radix/base'
2
+
3
+ module Radix
4
+
5
+ # Radix separator used in string and array representations.
6
+ DOT = '.'
7
+
8
+ # Division character for rational numbers
9
+ DIV = '/'
10
+
11
+ # Default seperator character.
12
+ DIVIDER = " "
13
+
14
+ ##
15
+ # Radix::Numeric class inherits from Ruby's Numeric class. It is then
16
+ # subclassed by Radix::Integer and Radix::Float.
17
+ #
18
+ # @todo Make immutable, but best way to do it?
19
+ # @example First suggestion
20
+ # class << self
21
+ # alias_method :_new, :new
22
+ # private :_new
23
+ # end
24
+ # @example Second suggestion
25
+ # def self.new(value, base=10)
26
+ # @cache ||= {}
27
+ # @cache[[value, base]] ||= _new(value, base)
28
+ # end
29
+ class Numeric < ::Numeric
30
+
31
+ ##
32
+ # Addition, binary operation.
33
+ #
34
+ # @param [Radix::Numeric] other
35
+ #
36
+ # @return [Radix::Numeric] Result of arithmetic operation.
37
+ def +(other)
38
+ operation(:+, other)
39
+ end
40
+
41
+ ##
42
+ # Subtraction, binary operation.
43
+ #
44
+ # @param [Radix::Numeric] other
45
+ #
46
+ # @return [Radix::Numeric] Result of arithmetic operation.
47
+ def -(other)
48
+ operation(:-, other)
49
+ end
50
+
51
+ ##
52
+ # Multiplication, binary operation.
53
+ #
54
+ # @param [Radix::Numeric] other
55
+ #
56
+ # @return [Radix::Numeric] Result of arithmetic operation.
57
+ def *(other)
58
+ operation(:*, other)
59
+ end
60
+
61
+ ##
62
+ # Division, binary operation.
63
+ #
64
+ # @param [Radix::Numeric] other
65
+ #
66
+ # @return [Radix::Numeric] Result of arithmetic operation.
67
+ def /(other)
68
+ operation(:/, other)
69
+ end
70
+
71
+ private
72
+
73
+ ##
74
+ # Parses the value of the base and character set to use.
75
+ #
76
+ # @param [Fixnum, Array<String>] base
77
+ # The value of the base, or a set of characters to use as
78
+ # representation of the base.
79
+ #
80
+ # @note If an array of String characters is passed, its length is the
81
+ # value of the base level.
82
+ #
83
+ # @return [Array<(Fixnum, [Array<String>, nil])>] Two part array:
84
+ # 0 - Fixnum value of the base.
85
+ # 1 - Nil, or Array of characters representing the base values.
86
+ def parse_base(base)
87
+ case base
88
+ when Array
89
+ code = base
90
+ base = base.size
91
+ else
92
+ code = nil
93
+ base = base
94
+ end
95
+ return base, code
96
+ end
97
+
98
+ ##
99
+ # Simply returns the passed value. Used for simplifying creation of
100
+ # Radix::Numeric instances.
101
+ #
102
+ # @param [Radix::Float, Radix::Integer] value Given value.
103
+ # @param [Fixnum, Array<String>] base Desired base.
104
+ #
105
+ # @return [Radix::Float, Radix::Integer] The passed value.
106
+ def parse_numeric(value, base)
107
+ value
108
+ end
109
+
110
+ ##
111
+ # If a float style string is passed in for +value+, e.g. "9.5", the
112
+ # decimal will simply be truncated. So "9.x" would become "9".
113
+ #
114
+ # @param [String] value
115
+ # Given value.
116
+ #
117
+ # @param [Fixnum, Array<String>] base
118
+ # Desired base.
119
+ #
120
+ # @return [Radix::Float, Radix::Integer] The passed value.
121
+ def parse_string(value, base)
122
+ digits = value.split(//)
123
+ parse_array(digits, base)
124
+ end
125
+
126
+ ##
127
+ # Take an Array in the form of [d1, d2, ..., DOT, d-1, d-2, ...]
128
+ # and convert it to base ten, and store in @value.
129
+ #
130
+ # @param [Array<String, Numeric>] value Given value.
131
+ # @param [Fixnum, Array<String>] base Desired base.
132
+ #
133
+ # @return [Fixnum] Decimal version of passed array in base context.
134
+ def parse_array(value, base)
135
+ value = value.dup
136
+
137
+ if value.first == '-'
138
+ neg = true
139
+ value.shift
140
+ else
141
+ neg = false
142
+ end
143
+
144
+ value = base_decode(value)
145
+
146
+ ## raise an error if any digit is not less than base
147
+ raise ArgumentError if value.any?{ |e| ::Numeric === e && base < e }
148
+
149
+ v = decimal(value, base)
150
+
151
+ neg ? -v : v # Returns negated v if value array.first == "-"
152
+ end
153
+
154
+ ##
155
+ # Convert array of values of a different base to decimal. This handles
156
+ # integer values. The method for Radix::Float is slighly different.
157
+ #
158
+ # @param [Array<Numeric, String>] digits
159
+ # Representation of base values.
160
+ #
161
+ # @param [Fixnum, Array<String>] base
162
+ # The base to convert from.
163
+ #
164
+ # @return [Integer] The digits of base converted to decimal.
165
+ def decimal(digits, base)
166
+ e = digits.size - 1
167
+ v = 0
168
+ digits.each do |n|
169
+ v += n.to_i * base**e
170
+ e -= 1
171
+ end
172
+ v
173
+ end
174
+
175
+ ##
176
+ # Map array of values to base encoding. If no encoding is defined
177
+ # this simply returns the +digits+ unchanged.
178
+ #
179
+ # @param [Array<String, Numeric>] digits
180
+ #
181
+ # @return [Array<String, Fixnum>] Encoded digits, or digits if @code is nil
182
+ def base_encode(digits)
183
+ return digits unless @code
184
+ digits.map do |i|
185
+ case i
186
+ when '-', DOT, DIV
187
+ i
188
+ else
189
+ code[i]
190
+ end
191
+ end
192
+ end
193
+
194
+ ##
195
+ # Decode an encoded array. Defaults to BASE::B62 if self.code is not set.
196
+ #
197
+ # @param [Array<String, Numeric>] digits The encoded characters.
198
+ #
199
+ # @return [Array<String, Numeric>] Decoded array.
200
+ def base_decode(digits)
201
+ #return digits unless code
202
+ code = self.code || BASE::B62
203
+ digits.map do |c|
204
+ case c
205
+ when '-', DOT, DIV
206
+ c
207
+ when ::Numeric
208
+ c
209
+ else
210
+ code.index(c) # TODO: Could speed up with an reverse index.
211
+ end
212
+ end
213
+ end
214
+
215
+ end
216
+
217
+ end
@@ -0,0 +1,311 @@
1
+ require 'rational'
2
+ require 'radix/numeric'
3
+
4
+ module Radix
5
+
6
+ ##
7
+ # Represents rational numbers.
8
+ #
9
+ # @!attribute [r] value
10
+ # @return [Rational] Ruby Rational representation of self in Base-10.
11
+ # @!attribute [r] base
12
+ # @return [Fixnum] The base level of Rational instance.
13
+ # @!attribute [r] code
14
+ # @return [Array<String>, nil] Substitution chars or nil if default.
15
+ class Rational < Numeric
16
+
17
+ ##
18
+ # Alternative to #new.
19
+ #
20
+ # @return [Radix::Rational]
21
+ def self.[](n,d=nil,b=10)
22
+ new(n,d,b)
23
+ end
24
+
25
+ ##
26
+ # Stores the Rational value in Base-10.
27
+ #
28
+ # @return [Rational]
29
+ attr :value
30
+
31
+ ##
32
+ # Base of the number.
33
+ #
34
+ # @return [Fixnum] The base level of Rational instance.
35
+ attr :base
36
+
37
+ ##
38
+ # Base encoding table.
39
+ #
40
+ # @return [Array<String>, nil] Substitution chars or nil if default.
41
+ attr :code
42
+
43
+ private
44
+
45
+ ##
46
+ # Create a new Radix::Rational instance.
47
+ # @example
48
+ # Rational.new(<Integer>, <Integer>, <Integer>)
49
+ # Rational.new(<Rational>, <Integer>)
50
+ # @param [Radix::Rational, ::Rational, Fixnum] numerator A rational number
51
+ # or a fixnum for the numerator of a new Rational.
52
+ # @param [Fixnum] denominator Denominator for new Rational.
53
+ # @param [Fixnum] base Base level for new Rational.
54
+ # @return [void]
55
+ def initialize(numerator, denominator=nil, base=10)
56
+ case numerator
57
+ when ::Rational, Rational
58
+ ratn = numerator
59
+ base = denominator
60
+ @value = Rational(ratn.numerator, ratn.denominator)
61
+ else
62
+ n = parse_value(numerator, base)
63
+ d = parse_value(denominator, base)
64
+ @value = Rational(n, d)
65
+ end
66
+ @base, @code = parse_base(base)
67
+ end
68
+
69
+ ##
70
+ # Parses String, Array, Radix::Float, Radix::Integer or Ruby numerics and
71
+ # returns the decimal value from base context for storage in @value.
72
+ #
73
+ # @param [Fixnum] base
74
+ def parse_value(value, base)
75
+ case value
76
+ when Float, Integer # Radix
77
+ parse_numeric(value.to_i, base)
78
+ when ::Array
79
+ parse_array(value, base)
80
+ when ::String
81
+ parse_string(value, base)
82
+ when ::Numeric
83
+ parse_numeric(value.to_i, base)
84
+ end
85
+ end
86
+
87
+ public
88
+
89
+ ##
90
+ # The numerator.
91
+ #
92
+ # @return [Fixnum] The numerator of Radix::Rational
93
+ def numerator
94
+ @value.numerator
95
+ end
96
+
97
+ ##
98
+ # The denominator.
99
+ #
100
+ # @return [Fixnum] The denominator of Radix::Rational
101
+ def denominator
102
+ @value.denominator
103
+ end
104
+
105
+ ##
106
+ # Is the value negative?
107
+ #
108
+ # @return [Boolean] Returns true if value < 0.
109
+ def negative?
110
+ value < 0
111
+ end
112
+
113
+ ##
114
+ # Convert rational to new base.
115
+ #
116
+ # @param [Fixnum] base Desired base.
117
+ # @return [Radix::Rational] Returns new Radix::Rational in passed base.
118
+ def convert(base)
119
+ self.class.new(numerator, denominator, base)
120
+ end
121
+
122
+ ##
123
+ # Convert to rational.
124
+ #
125
+ # @return [Rational] Returns the value.
126
+ def to_r
127
+ value
128
+ end
129
+
130
+ ##
131
+ # Convert to Float by dividing the numerator by the denominator.
132
+ #
133
+ # Returns the converted value. [Float]
134
+ def to_f
135
+ numerator.to_f / denominator.to_f
136
+ end
137
+
138
+ ##
139
+ # Convert to Integer by converting to Float first then
140
+ # appling #to_i to the float.
141
+ #
142
+ # Returns the converted value. [Integer]
143
+ def to_i
144
+ to_f.to_i
145
+ end
146
+
147
+ ##
148
+ # Translate value into an array of places. Uses current base unless
149
+ # specified.
150
+ #
151
+ # @param [Fixnum] base Desired base.
152
+ # @return [Array<Fixnum, String>] Array of place values.
153
+ def to_a(base=nil)
154
+ if base
155
+ convert(base).digits_encoded
156
+ else
157
+ digits_encoded
158
+ end
159
+ end
160
+
161
+ ##
162
+ # Convert the value into a string representation of the given base.
163
+ #
164
+ # @param [Fixnum] base The base to convert.
165
+ # @param [String] divider The string char(s) to divided with.
166
+ # @return [String] Translated value.
167
+ def to_s(base=nil, divider=nil)
168
+ divider = divider.to_s if divider
169
+ if base
170
+ convert(base).to_s(nil, divider)
171
+ else
172
+ if code
173
+ digits_encoded.join(divider)
174
+ else
175
+ if @base > 10
176
+ digits.join(divider || DIVIDER)
177
+ else
178
+ digits.join(divider)
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+ ##
185
+ # Simple equality requires equal values only.
186
+ #
187
+ # @todo This may need improvement to be more percise.
188
+ # @param [#to_f] other The value to compare to.
189
+ # @return [Boolean] True if equal values.
190
+ def ==(other)
191
+ a, b = self.to_f, other.to_f
192
+ a == b
193
+ end
194
+
195
+ ##
196
+ # Returns an irreducible version of self in current base.
197
+ #
198
+ # @todo Is this method neccesary since @value is a Ruby Rational and
199
+ # therefore already irreducible?
200
+ # @return [Radix::Rational]
201
+ def reduce
202
+ self.class.new(Rational(numerator, denominator), base)
203
+ end
204
+
205
+ ##
206
+ # Returns an array representation of the numerator and denominator with
207
+ # each column's value.
208
+ #
209
+ # @return [Array<String, Fixnum>] Values per column of @base as array.
210
+ # Prepended with "-" if negative.
211
+ def digits
212
+ n = base_conversion(numerator, base)
213
+ d = base_conversion(denominator, base)
214
+ i = n + ['/'] + d
215
+ i.unshift('-') if negative?
216
+ i
217
+ end
218
+
219
+ ##
220
+ # Returns digits, or coded version of digits if @code.
221
+ #
222
+ # @return [Array<String, Fixnum>] Values per column of @base as array.
223
+ # Prepended with "-" if negative. Or encoded version if @code is
224
+ # defined.
225
+ def digits_encoded
226
+ base_encode(digits)
227
+ end
228
+
229
+ ##
230
+ # Creates a string representation of self.
231
+ #
232
+ # @return [String] String rep of self.digits and @base.
233
+ def inspect
234
+ "#{digits.join(' ')} (#{base})"
235
+ end
236
+
237
+ ##
238
+ # Returns new Radix::Rational of passed value in base-10 and self as an
239
+ # Array.
240
+ #
241
+ # @return [Array<(Radix::Rational, Radix::Rational)>]
242
+ def coerce(value)
243
+ [Radix::Rational.new(value), self]
244
+ end
245
+
246
+ private
247
+
248
+ ##
249
+ # Perform passed arithmetic operation.
250
+ #
251
+ # @param [#to_r] other
252
+ # @return [Radix::Rational] Returns the result of the operation in @base.
253
+ def operation(op, other)
254
+ x = value.__send__(op, other.to_r)
255
+ self.class.new(x, base)
256
+ end
257
+
258
+ ##
259
+ # Perform base conversion.
260
+ #
261
+ # @return [Array<Fixnum, String>] Array of places.
262
+ def base_conversion(value, base)
263
+ #if value < 0
264
+ # @negative, value = true, value.abs
265
+ #end
266
+ i = value.abs
267
+
268
+ a = []
269
+ while i > 0
270
+ i, r = i.divmod(base)
271
+ a << r
272
+ end
273
+
274
+ a << 0 if a.empty?
275
+
276
+ a.reverse
277
+ end
278
+
279
+ end
280
+
281
+ end
282
+
283
+ class ::Array
284
+ ##
285
+ # Adds convenience method for creating a Radix::Rational.
286
+ #
287
+ # @todo Keep #br? Or find another way?
288
+ # @return [Radix::Rational]
289
+ def br(base=nil)
290
+ args = dup
291
+ args << base if base
292
+ Radix::Rational.new(*args)
293
+ end
294
+ end
295
+
296
+ if RUBY_VERSION < '1.9'
297
+ class ::Float
298
+
299
+ ##
300
+ # Adds a #to_r method to pre-1.9 ruby Rationals.
301
+ #
302
+ # @return [Rational]
303
+ def to_r
304
+ n, f = to_s.split('.')
305
+ d = (10 ** f.size).to_i
306
+ n = (n.to_i * d) + f.to_i
307
+ Rational(n, d)
308
+ end
309
+ end
310
+ end
311
+