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.
- checksums.yaml +15 -0
- data/.index +59 -0
- data/.yardopts +8 -0
- data/HISTORY.md +95 -0
- data/LICENSE.txt +23 -0
- data/README.md +100 -0
- data/demo/01_synopsis.md +46 -0
- data/demo/02_integer.md +256 -0
- data/demo/03_float.md +294 -0
- data/demo/04_rational.md +84 -0
- data/demo/05_base.md +78 -0
- data/demo/applique/ae.rb +3 -0
- data/demo/applique/check.rb +7 -0
- data/demo/applique/radix.rb +1 -0
- data/demo/issues/004_zero_empty_string.md +18 -0
- data/lib/radix.rb +31 -0
- data/lib/radix.yml +59 -0
- data/lib/radix/base.rb +244 -0
- data/lib/radix/float.rb +456 -0
- data/lib/radix/integer.rb +466 -0
- data/lib/radix/numeric.rb +217 -0
- data/lib/radix/rational.rb +311 -0
- metadata +115 -0
@@ -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
|
+
|