radix 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  name : radix
2
- version : 1.1.0
3
- date : 2010-09-03
2
+ version : 2.0.0
3
+ date : 2010-10-31
4
4
 
5
5
  requires:
6
6
  - syckle (build)
@@ -3,7 +3,7 @@ title : Radix
3
3
  suite : rubyworks
4
4
  summary: Convert to and from any base.
5
5
  contact: trans <transfire@gmail.com>
6
- license: LGPL
6
+ license: Apache 2.0
7
7
  authors: Thomas Sawyer
8
8
  created: 2009-07-01
9
9
 
@@ -11,10 +11,10 @@ description:
11
11
  Convert to and from any base.
12
12
 
13
13
  resources:
14
- hompage : http://rubyworks.github.com/radix
15
- development: http://github.com/rubyworks/radix
16
- mailinglist: http://groups.google.com/group/rubyworks-mailinglist
17
- repository : git://github.com/rubyworks/radix.git
14
+ home: http://rubyworks.github.com/radix
15
+ code: http://github.com/rubyworks/radix
16
+ mail: http://groups.google.com/group/rubyworks-mailinglist
17
+ repo: git://github.com/rubyworks/radix.git
18
18
 
19
19
  copyright:
20
20
  Copyright (c) 2009 Thomas Sawyer
@@ -0,0 +1,144 @@
1
+ require 'radix/base'
2
+
3
+ module Radix
4
+
5
+ # Redix separator used in string and array representations.
6
+ DOT = '.'
7
+
8
+ #
9
+ DIV = '/'
10
+
11
+ #
12
+ DIVIDER = " "
13
+
14
+ # Radix Numeric base class is subclassed by Radix::Integer and Radix::Float,
15
+ # and is a subclass of Ruby's built-in Numeric class.
16
+ class Numeric < ::Numeric
17
+
18
+ # TODO: Make immutable, but best way to do it?
19
+
20
+ #class << self
21
+ # alias_method :_new, :new
22
+ # private :_new
23
+ #end
24
+ #
25
+ #def self.new(value, base=10)
26
+ # @cache ||= {}
27
+ # @cache[[value, base]] ||= _new(value, base)
28
+ #end
29
+
30
+ # Addition
31
+ def +(other)
32
+ operation(:+, other)
33
+ end
34
+
35
+ # Subtraction
36
+ def -(other)
37
+ operation(:-, other)
38
+ end
39
+
40
+ # Multiplication
41
+ def *(other)
42
+ operation(:*, other)
43
+ end
44
+
45
+ # Division
46
+ def /(other)
47
+ operation(:/, other)
48
+ end
49
+
50
+ private
51
+
52
+ #
53
+ def parse_base(base)
54
+ case base
55
+ when Array
56
+ code = base
57
+ base = base.size
58
+ else
59
+ code = nil
60
+ base = base
61
+ end
62
+ return base, code
63
+ end
64
+
65
+ #
66
+ def parse_numeric(value, base)
67
+ value
68
+ end
69
+
70
+ # If a float style string is passed in for +value+, e.g. "9.5", the
71
+ # decimal will simply be truncated. So "9.x" would become "9".
72
+ def parse_string(value, base)
73
+ digits = value.split(//)
74
+ parse_array(digits, base)
75
+ end
76
+
77
+ # Take an Array in the form of [d1, d2, ..., DOT, d-1, d-2, ...]
78
+ # and convert it to base ten, and store in @value.
79
+ def parse_array(value, base)
80
+ value = value.dup
81
+
82
+ if value.first == '-'
83
+ neg = true
84
+ value.shift
85
+ else
86
+ neg = false
87
+ end
88
+
89
+ value = base_decode(value)
90
+
91
+ ## raise an error if any digit is not less than base
92
+ raise ArgumentError if value.any?{ |e| ::Numeric === e && base < e }
93
+
94
+ v = decimal(value, base)
95
+
96
+ neg ? -v : v
97
+ end
98
+
99
+ # Convert array of values of a different base to decimal.
100
+ # This handles integer values. The method for Radix::Float
101
+ # is slighly different.
102
+ def decimal(digits, base)
103
+ e = digits.size - 1
104
+ v = 0
105
+ digits.each do |n|
106
+ v += n.to_i * base**e
107
+ e -= 1
108
+ end
109
+ v
110
+ end
111
+
112
+ # Map array of values to base encoding. If no encoding is defined
113
+ # this simply returns the +digits+ unchanged.
114
+ def base_encode(digits)
115
+ return digits unless @code
116
+ digits.map do |i|
117
+ case i
118
+ when '-', DOT, DIV
119
+ i
120
+ else
121
+ code[i]
122
+ end
123
+ end
124
+ end
125
+
126
+ # Decode an encoded array.
127
+ def base_decode(digits)
128
+ #return digits unless code
129
+ code = self.code || BASE::B62
130
+ digits.map do |c|
131
+ case c
132
+ when '-', DOT, DIV
133
+ c
134
+ when ::Numeric
135
+ c
136
+ else
137
+ code.index(c) # TODO: Could speed up with an reverse index.
138
+ end
139
+ end
140
+ end
141
+
142
+ end
143
+
144
+ end
@@ -1,30 +0,0 @@
1
- require 'radix/number'
2
-
3
- class ::Numeric
4
-
5
- #
6
- def b(base)
7
- Radix::Number.new(self, base)
8
- end
9
-
10
- end
11
-
12
-
13
- class ::String
14
-
15
- #
16
- def b(base)
17
- Radix::Number.new(self, base)
18
- end
19
-
20
- end
21
-
22
-
23
- class ::Array
24
-
25
- #
26
- def b(base)
27
- Radix::Number.new(self, base)
28
- end
29
-
30
- end
@@ -0,0 +1,203 @@
1
+ require 'rational'
2
+ require 'radix/numeric'
3
+
4
+ module Radix
5
+
6
+ #
7
+ class Rational < Numeric
8
+
9
+ # Alternative to #new.
10
+ def self.[](n,d=nil,b=10)
11
+ new(n,d,b)
12
+ end
13
+
14
+ # Stores the Rational value.
15
+ attr :value
16
+
17
+ # Base of the number.
18
+ attr :base
19
+
20
+ # Base encoding table.
21
+ attr :code
22
+
23
+ private
24
+
25
+ # Create a new Radix::Rational instance.
26
+ #
27
+ # Rational.new(<Integer>, <Integer>, <Integer>)
28
+ # Rational.new(<Rational>, <Integer>)
29
+ #
30
+ def initialize(numerator, denominator=nil, base=10)
31
+ case numerator
32
+ when ::Rational, Rational
33
+ ratn = numerator
34
+ base = denominator
35
+ @value = ::Rational.new!(ratn.numerator, ratn.denominator)
36
+ else
37
+ n = parse_value(numerator, base)
38
+ d = parse_value(denominator, base)
39
+ @value = ::Rational.new!(n, d)
40
+ end
41
+ @base, @code = parse_base(base)
42
+ end
43
+
44
+ #
45
+ def parse_value(value, base)
46
+ case value
47
+ when Float, Integer # Radix
48
+ parse_numeric(value.to_i, base)
49
+ when ::Array
50
+ parse_array(value, base)
51
+ when ::String
52
+ parse_string(value, base)
53
+ when ::Numeric
54
+ parse_numeric(value.to_i, base)
55
+ end
56
+ end
57
+
58
+ public
59
+
60
+ #
61
+ def numerator
62
+ @value.numerator
63
+ end
64
+
65
+ #
66
+ def denominator
67
+ @value.denominator
68
+ end
69
+
70
+ #
71
+ def negative?
72
+ value < 0
73
+ end
74
+
75
+ #
76
+ def convert(base)
77
+ self.class.new(numerator, denominator, base)
78
+ end
79
+
80
+ #
81
+ def to_r
82
+ value
83
+ end
84
+
85
+ #
86
+ def to_f
87
+ numerator.to_f / denominator.to_f
88
+ end
89
+
90
+ #
91
+ def to_i
92
+ to_f.to_i
93
+ end
94
+
95
+ #
96
+ def to_a(base=nil)
97
+ if base
98
+ convert(base).digits_encoded
99
+ else
100
+ digits_encoded
101
+ end
102
+ end
103
+
104
+ #
105
+ def to_s(base=nil, divider=nil)
106
+ divider = divider.to_s if divider
107
+ if base
108
+ convert(base).to_s(nil, divider)
109
+ else
110
+ if code
111
+ digits_encoded.join(divider)
112
+ else
113
+ if @base > 10
114
+ digits.join(divider || DIVIDER)
115
+ else
116
+ digits.join(divider)
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ #
123
+ def ==(other)
124
+ a, b = self.to_f, other.to_f
125
+ a == b
126
+ end
127
+
128
+ #
129
+ def reduce
130
+ self.class.new(Rational(numerator, denominator), base)
131
+ end
132
+
133
+ #
134
+ def digits
135
+ n = base_conversion(numerator, base)
136
+ d = base_conversion(denominator, base)
137
+ i = n + ['/'] + d
138
+ i.unshift('-') if negative?
139
+ i
140
+ end
141
+
142
+ #
143
+ def digits_encoded
144
+ base_encode(digits)
145
+ end
146
+
147
+ #
148
+ def inspect
149
+ "#{digits.join(' ')} (#{base})"
150
+ end
151
+
152
+ #
153
+ def coerce(value)
154
+ [Radix::Rational.new(value), self]
155
+ end
156
+
157
+ private
158
+
159
+ #
160
+ def operation(op, other)
161
+ x = value.__send__(op, other.to_r)
162
+ self.class.new(x, base)
163
+ end
164
+
165
+ #
166
+ def base_conversion(value, base)
167
+ #if value < 0
168
+ # @negative, value = true, value.abs
169
+ #end
170
+ i = value.abs
171
+
172
+ a = []
173
+ while i > 0
174
+ i, r = i.divmod(base)
175
+ a << r
176
+ end
177
+
178
+ a.reverse
179
+ end
180
+
181
+ end
182
+
183
+ end
184
+
185
+ class ::Array
186
+ # Convenience method for creating a Radix::Rational.
187
+ # TODO: Keep #br? Or find another way?
188
+ def br(base=nil)
189
+ args = dup
190
+ args << base if base
191
+ Radix::Rational.new(*args)
192
+ end
193
+ end
194
+
195
+ class ::Float
196
+ #
197
+ def to_r
198
+ n, f = to_s.split('.')
199
+ d = (10 * f.size).to_i
200
+ n = (n.to_i * d) + f.to_i
201
+ Rational(n, d)
202
+ end
203
+ end
@@ -1,6 +1,6 @@
1
1
  name : radix
2
- version : 1.1.0
3
- date : 2010-09-03
2
+ version : 2.0.0
3
+ date : 2010-10-31
4
4
 
5
5
  requires:
6
6
  - syckle (build)
@@ -3,7 +3,7 @@ title : Radix
3
3
  suite : rubyworks
4
4
  summary: Convert to and from any base.
5
5
  contact: trans <transfire@gmail.com>
6
- license: LGPL
6
+ license: Apache 2.0
7
7
  authors: Thomas Sawyer
8
8
  created: 2009-07-01
9
9
 
@@ -11,10 +11,10 @@ description:
11
11
  Convert to and from any base.
12
12
 
13
13
  resources:
14
- hompage : http://rubyworks.github.com/radix
15
- development: http://github.com/rubyworks/radix
16
- mailinglist: http://groups.google.com/group/rubyworks-mailinglist
17
- repository : git://github.com/rubyworks/radix.git
14
+ home: http://rubyworks.github.com/radix
15
+ code: http://github.com/rubyworks/radix
16
+ mail: http://groups.google.com/group/rubyworks-mailinglist
17
+ repo: git://github.com/rubyworks/radix.git
18
18
 
19
19
  copyright:
20
20
  Copyright (c) 2009 Thomas Sawyer
@@ -0,0 +1,256 @@
1
+ = Radix Integer
2
+
3
+ Radix provides an Integer class for working with integers in various bases.
4
+
5
+ require 'radix'
6
+
7
+ == Initialization
8
+
9
+ Radix::Integer's initializer can accept either an Integer, String or
10
+ Array as a value and an integer base.
11
+
12
+ Give an integer value, it will automatically be converted to the base
13
+ specified.
14
+
15
+ check do |integer, base, digits|
16
+ r = Radix::Integer.new(integer, base)
17
+ r.digits.assert == digits
18
+ end
19
+
20
+ ok 8, 2, [1,0,0,0]
21
+ ok 4, 2, [1,0,0]
22
+ ok 8, 10, [8]
23
+ ok 10, 10, [1, 0]
24
+ ok 8, 16, [8]
25
+ ok 16, 16, [1, 0]
26
+
27
+ Where as a String value is taken to already be in the base given.
28
+
29
+ ok "1000", 2, [1,0,0,0]
30
+ ok "100", 2, [1,0,0]
31
+
32
+ ok "8", 10, [8]
33
+ ok "10", 10, [1, 0]
34
+ ok "8", 16, [8]
35
+ ok "10", 16, [1, 0]
36
+
37
+ And an Array is also taken to be in the base given.
38
+
39
+ ok %w[1 0 0 0], 2, [1,0,0,0]
40
+ ok %w[ 1 0 0], 2, [1,0,0]
41
+
42
+ ok %w[ 8], 10, [8]
43
+ ok %w[1 0], 10, [1, 0]
44
+ ok %w[ 8], 16, [8]
45
+ ok %w[1 0], 16, [1, 0]
46
+
47
+ Integers can also be negative, rather than positive. In each case
48
+ just prepend the value with a minus sign.
49
+
50
+ check do |integer, base, digits|
51
+ r = Radix::Integer.new(integer, base)
52
+ r.digits.assert == digits
53
+ r.assert.negative?
54
+ end
55
+
56
+ ok -8, 2, ['-',1,0,0,0]
57
+ ok "-1000", 2, ['-',1,0,0,0]
58
+ ok %w[- 1 0 0 0], 2, ['-',1,0,0,0]
59
+
60
+ If a value has a digit outside of the range of the base an ArgumentError
61
+ will be raised.
62
+
63
+ expect ArgumentError do
64
+ Radix::Integer.new('9', 2)
65
+ end
66
+
67
+ Radix provides a convenience extension method to Integer, String and Array
68
+ called #b, to more easily initialize a Radix numeric object. The method simply
69
+ passes the receiver on to `Radix::Integer#new`.
70
+
71
+ check do |integer, base, digits|
72
+ r = integer.b(base)
73
+ r.assert.is_a?(Radix::Integer)
74
+ r.digits.assert == digits
75
+ end
76
+
77
+ ok 8, 2, [1,0,0,0]
78
+ ok 4, 2, [1,0,0]
79
+
80
+ ok "1000", 2, [1,0,0,0]
81
+ ok "100", 2, [1,0,0]
82
+
83
+ ok %w"1 0 0 0", 2, [1,0,0,0]
84
+ ok %w"1 0 0", 2, [1,0,0]
85
+
86
+ == Conversion
87
+
88
+ Radix integers can ve converted to other bases with the #convert method.
89
+
90
+ b = "1000".b(2)
91
+ d = b.convert(10)
92
+ d.digits.assert == [8]
93
+
94
+ We can convert a Radix::Integer to a regular base-10 Integer with the #to_i
95
+ method.
96
+
97
+ b = "1000".b(2)
98
+ d = b.to_i
99
+ d.assert == 8
100
+
101
+ == Equality
102
+
103
+ Radix extend the Integer, String and Array classes with the #b method
104
+ which simplifies the creation of Radix::Integer instances. The following
105
+ return the equivalent instance of Radix::Integer.
106
+
107
+ a = 8.b(2)
108
+ b = "1000".b(2)
109
+ c = [1, 0, 0, 0].b(2)
110
+
111
+ a.assert == b
112
+ b.assert == c
113
+ c.assert == a
114
+
115
+ a.assert == 8
116
+ b.assert == 8
117
+ c.assert == 8
118
+
119
+ More stringent equality can be had from #eql?, in which the other integer
120
+ must be a Radix::Integer too.
121
+
122
+ a.assert.eql?(b)
123
+ a.refute.eql?(8)
124
+
125
+ === Operations
126
+
127
+ Radix::Integer supports all the usual mathematical operators.
128
+
129
+ === Addition
130
+
131
+ check do |a, b, x|
132
+ (a + b).assert == x
133
+ end
134
+
135
+ ok "1000".b(2), "0010".b(2), "1010".b(2)
136
+ ok "1000".b(2), "2".b(8), "1010".b(2)
137
+ ok "1000".b(2), "2".b(8), "10".b(10)
138
+
139
+ A more complex example.
140
+
141
+ x = "AZ42".b(62) + "54".b(10)
142
+ x.assert == "2518124".b(10)
143
+ x.assert == 2518124
144
+
145
+ Adding negative integers will, of course, be akin to subtraction.
146
+
147
+ ok "1000".b(2), "-0010".b(2), "110".b(2)
148
+ ok "1000".b(2), "-2".b(8), "110".b(2)
149
+ ok "1000".b(2), "-2".b(8), "6".b(10)
150
+
151
+ ok "-1000".b(2), "0010".b(2), "-110".b(2)
152
+ ok "-1000".b(2), "2".b(8), "-110".b(2)
153
+ ok "-1000".b(2), "2".b(8), "-6".b(10)
154
+
155
+ ok "-1000".b(2), "-0010".b(2), "-1010".b(2)
156
+ ok "-1000".b(2), "-2".b(8), "-1010".b(2)
157
+ ok "-1000".b(2), "-2".b(8), "-10".b(10)
158
+
159
+ === Subtraction
160
+
161
+ check do |a, b, x|
162
+ (a - b).assert == x
163
+ end
164
+
165
+ ok "1000".b(2), "10".b(2), "0110".b(2)
166
+ ok "1000".b(2), "2".b(8), "0110".b(2)
167
+ ok "1000".b(2), "2".b(8), "6".b(8)
168
+ ok "1000".b(2), "2".b(8), "6".b(10)
169
+
170
+ A more complex example.
171
+
172
+ x = "AZ42".b(62) - "54".b(10)
173
+ x.assert == "2518016".b(10)
174
+ x.assert == 2518016
175
+
176
+ === Multiplication
177
+
178
+ check do |a, b, x|
179
+ (a * b).assert == x
180
+ end
181
+
182
+ ok "1000".b(2), "10".b(2), "10000".b(2)
183
+ ok "1000".b(2), "2".b(8), "10000".b(2)
184
+ ok "1000".b(2), "2".b(8), "20".b(8)
185
+ ok "1000".b(2), "2".b(8), "16".b(10)
186
+
187
+ A more complex example.
188
+
189
+ x = "Z42".b(62) * "4".b(10)
190
+ x.assert == "539160".b(10)
191
+ x.assert == 539160
192
+
193
+ === Division
194
+
195
+ check do |a, b, x|
196
+ (a / b).assert == x
197
+ end
198
+
199
+ ok "1000".b(2), "10".b(2), "100".b(2)
200
+ ok "1000".b(2), "2".b(8), "100".b(2)
201
+ ok "1000".b(2), "2".b(8), "4".b(8)
202
+ ok "1000".b(2), "2".b(8), "4".b(10)
203
+
204
+ A more complex example.
205
+
206
+ x = "AZ42".b(62) / "54".b(10)
207
+ x.assert == "46630".b(10)
208
+ x.assert == 46630
209
+
210
+ === Power
211
+
212
+ check do |a, b, x|
213
+ (a ** b).assert == x
214
+ end
215
+
216
+ ok "1000".b(2), "10".b(2), 64
217
+
218
+ === Modulo
219
+
220
+ check do |a, b, x|
221
+ (a % b).assert == x
222
+ end
223
+
224
+ ok "1000".b(2), "10".b(2), 0
225
+ ok "1000".b(2), "11".b(2), 2
226
+
227
+ === Bitwise Shift
228
+
229
+ check do |a, b, x|
230
+ (a << b).assert == x
231
+ end
232
+
233
+ ok "10".b(2), "10".b(2), "1000".b(2)
234
+ ok "10".b(2), 2, "1000".b(2)
235
+ ok "10".b(2), 2, 8
236
+
237
+ === Bitwise AND
238
+
239
+ check do |a, b, x|
240
+ (a & b).assert == x
241
+ end
242
+
243
+ ok "1010".b(2), "10".b(2), "10".b(2)
244
+ ok "1010".b(2), "2".b(8), "10".b(2)
245
+
246
+ == Coerce
247
+
248
+ When a Radix::Integer is the operand in an operation against a regular
249
+ Ruby Integer, the calculation should still work via #coerce.
250
+
251
+ check do |a, b, x|
252
+ (a + b).assert == x
253
+ end
254
+
255
+ ok 10, "10".b(2), "12".b(10)
256
+