radix 1.1.0 → 2.0.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,263 @@
1
+ require 'radix/numeric'
2
+
3
+ module Radix
4
+
5
+ # Radix::Float is simple a Ruby Float class that can handle bases.
6
+ #
7
+ # TODO: Make fully immutable. After that we can catch @digits and
8
+ # the library should be a good bit faster.
9
+ class Float < Numeric
10
+
11
+ # Internal floating point value.
12
+ attr :value
13
+
14
+ # Base of the number.
15
+ attr :base
16
+
17
+ # Base encoding table.
18
+ attr :code
19
+
20
+ private
21
+
22
+ #
23
+ def initialize(value, base=10)
24
+ @value = parse_value(value, base)
25
+ @base, @code = parse_base(base)
26
+ end
27
+
28
+ #
29
+ def parse_value(value, base)
30
+ case value
31
+ when Float, Integer # Radix
32
+ parse_numeric(value.to_f, base)
33
+ when ::Array
34
+ parse_array(value, base)
35
+ when ::String
36
+ parse_string(value, base)
37
+ when ::Numeric
38
+ parse_numeric(value.to_f, base)
39
+ end
40
+ end
41
+
42
+ public
43
+
44
+ #
45
+ def to_i
46
+ to_f.to_i
47
+ end
48
+
49
+ #
50
+ alias_method :to_int, :to_i
51
+
52
+ #
53
+ def to_f
54
+ value.to_f
55
+ end
56
+
57
+ #
58
+ def to_a(base=nil)
59
+ if base
60
+ convert(base).digits_encoded
61
+ else
62
+ digits_encoded
63
+ end
64
+ end
65
+
66
+ #
67
+ def to_s(base=nil, divider=nil)
68
+ divider = divider.to_s if divider
69
+ if base
70
+ convert(base).to_s(nil, divider)
71
+ else
72
+ if code
73
+ digits_encoded.join(divider)
74
+ else
75
+ if @base > 10
76
+ digits.join(divider || DIVIDER)
77
+ else
78
+ digits.join(divider)
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ #
85
+ def inspect
86
+ "#{digits.join(' ')} (#{base})"
87
+ end
88
+
89
+ #
90
+ def digits
91
+ i, f = base_conversion(value, base)
92
+ if negative?
93
+ ['-'] + i + [DOT] + f
94
+ else
95
+ i + [DOT] + f
96
+ end
97
+ end
98
+
99
+ #
100
+ def digits_encoded
101
+ base_encode(digits)
102
+ end
103
+
104
+ # Returns true if the number negative?
105
+ def negative?
106
+ value < 0
107
+ end
108
+
109
+ #
110
+ def convert(new_base)
111
+ self.class.new(value, new_base)
112
+ end
113
+
114
+ # Power
115
+ def **(other)
116
+ operation(:**, other)
117
+ end
118
+
119
+ # Modulo
120
+ def %(other)
121
+ operation(:%, other)
122
+ end
123
+
124
+ #
125
+ alias_method :modulo, :%
126
+
127
+ #
128
+ def abs
129
+ self.class.new(value.abs, base)
130
+ end
131
+
132
+ #
133
+ def ceil
134
+ self.class.new(value.ceil, base)
135
+ end
136
+
137
+ #
138
+ def floor
139
+ self.class.new(value.floor, base)
140
+ end
141
+
142
+ #
143
+ def round
144
+ return self.class.new((value + 0.5).floor, base) if self > 0.0
145
+ return self.class.new((value - 0.5).ceil, base) if self < 0.0
146
+ return self.class.new(0, base)
147
+ end
148
+
149
+ # Strict equality requires same class as well as value.
150
+ def eql?(num)
151
+ self.class.equal?(num.class) && self == num
152
+ end
153
+
154
+ # Simple equality requires equal values only.
155
+ def ==(other)
156
+ case other
157
+ when Float, Integer # Radix
158
+ value == other.value
159
+ else
160
+ value == other
161
+ end
162
+ end
163
+
164
+ #
165
+ def <=>(other)
166
+ to_f <=> other.to_f
167
+ end
168
+
169
+ #
170
+ #def infinite?
171
+ # digits[0,2] == [0, DOT]
172
+ #end
173
+
174
+ #
175
+ #def finite?
176
+ # !infinite
177
+ #end
178
+
179
+ #
180
+ #def nan?
181
+ # digits[-2,2] == [DOT, 0]
182
+ #end
183
+
184
+ #
185
+ def coerce(o)
186
+ [Radix::Float.new(o), self]
187
+ end
188
+
189
+ private
190
+
191
+ # Perform arthmetic operation.
192
+ def operation(op, other)
193
+ a = self.to_f
194
+ b = other.to_f
195
+ x = a.__send__(op, b)
196
+ Radix::Float.new(x, base)
197
+ end
198
+
199
+ #
200
+ def base_conversion(value, base, prec=10)
201
+ #if value < 0
202
+ # @negative, value = true, value.abs
203
+ #end
204
+ value = value.to_f.abs
205
+
206
+ i, f = split_float(value)
207
+
208
+ a = []
209
+ while i > 0
210
+ i, r = i.divmod(base)
211
+ a << r
212
+ end
213
+
214
+ #c = [] # f-cache
215
+ p = prec
216
+ b = []
217
+ while !f.zero?
218
+ k = (f * base)
219
+ r, f = split_float(k)
220
+ #c.include?(f) ? break : c << f
221
+ break if p == 0; p -= 1
222
+ b << r
223
+ end
224
+
225
+ b << 0 if b.empty?
226
+
227
+ [a.reverse, b]
228
+ end
229
+
230
+ #
231
+ def decimal(digits, base)
232
+ i, f = split_digits(digits)
233
+ e = i.size - 1
234
+ v = 0
235
+ (i + f).each do |n|
236
+ v += n * base**e
237
+ e -= 1
238
+ end
239
+ v
240
+ end
241
+
242
+ #
243
+ def split_digits(value)
244
+ if d = value.index(DOT) || value.index('.')
245
+ i, f = value[0...d], value[d+1..-1]
246
+ else
247
+ i, f = value, [0]
248
+ end
249
+ i.map!{ |x| x.to_i }
250
+ f.map!{ |x| x.to_i }
251
+ return i, f
252
+ end
253
+
254
+ #
255
+ def split_float(float)
256
+ i, f = float.to_s.split('.')
257
+ return i.to_i, ('0.'+f).to_f
258
+ end
259
+
260
+ end
261
+
262
+ end
263
+
@@ -0,0 +1,263 @@
1
+ require 'radix/numeric'
2
+
3
+ module Radix
4
+
5
+ #
6
+ class Integer < Numeric
7
+
8
+ # Stores the numerc value as normal number.
9
+ attr :value
10
+
11
+ # Base of the number.
12
+ attr :base
13
+
14
+ # Base encoding table.
15
+ attr :code
16
+
17
+ private
18
+
19
+ #
20
+ def initialize(value, base=10)
21
+ @value = parse_value(value, base)
22
+ @base, @code = parse_base(base)
23
+ end
24
+
25
+ #
26
+ def parse_value(value, base)
27
+ case value
28
+ when Integer, Float # Radix
29
+ parse_numeric(value.to_i, base)
30
+ when ::Array
31
+ parse_array(value, base)
32
+ when ::String
33
+ parse_string(value, base)
34
+ when ::Numeric
35
+ parse_numeric(value, base)
36
+ end
37
+ end
38
+
39
+ # Take an Array in the form of [..., d2, d1, d0] and convert it to
40
+ # base ten, and store in @value.
41
+ #
42
+ # If a float style array is passed in for +value+, e.g. [9, '.', 5],
43
+ # the fractional part will simply be truncated.
44
+ def parse_array(value, base)
45
+ if i = value.index(DOT)
46
+ value = [0...i]
47
+ end
48
+ super(value, base)
49
+ end
50
+
51
+ ## digits << #Radix.convert(d, base, 10).to_i
52
+
53
+ public
54
+
55
+ #
56
+ def to_i
57
+ value.to_i #(sign + convert(10).digits.join('')).to_i
58
+ end
59
+
60
+ #
61
+ alias_method :to_int, :to_i
62
+
63
+ #
64
+ def to_f
65
+ value.to_f #(sign + convert(10).digits.join('')).to_f
66
+ end
67
+
68
+ #
69
+ def to_a(base=nil)
70
+ if base
71
+ convert(base).digits_encoded
72
+ else
73
+ digits_encoded
74
+ end
75
+ end
76
+
77
+ #
78
+ def to_s(base=nil, divider=nil)
79
+ divider = divider.to_s if divider
80
+ if base
81
+ convert(base).to_s(nil, divider)
82
+ else
83
+ if code
84
+ digits_encoded.join(divider)
85
+ else
86
+ if @base > 10
87
+ digits.join(divider || DIVIDER)
88
+ else
89
+ digits.join(divider)
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ #
96
+ def inspect
97
+ "#{digits.join(' ')} (#{base})"
98
+ end
99
+
100
+ #
101
+ def digits
102
+ i = base_conversion(value, base)
103
+ i.unshift('-') if negative?
104
+ i
105
+ end
106
+
107
+ #
108
+ def digits_encoded
109
+ base_encode(digits)
110
+ end
111
+
112
+ # Returns true if the number is negative.
113
+ def negative?
114
+ value < 0
115
+ end
116
+
117
+ #
118
+ def convert(base)
119
+ self.class.new(value, base)
120
+ #new_digits = Radix::Base.convert_base(digits, base, new_base)
121
+ #self.class.new(new_digits, new_base)
122
+ end
123
+
124
+ # Addition
125
+ def +(other)
126
+ operation(:+, other)
127
+ end
128
+
129
+ # Subtraction
130
+ def -(other)
131
+ operation(:-, other)
132
+ end
133
+
134
+ # Multiplication
135
+ def *(other)
136
+ operation(:*, other)
137
+ end
138
+
139
+ # Division
140
+ def /(other)
141
+ operation(:/, other)
142
+ end
143
+
144
+ # Power
145
+ def **(other)
146
+ operation(:**, other)
147
+ end
148
+
149
+ # Modulo
150
+ def %(other)
151
+ operation(:%, other)
152
+ end
153
+
154
+ # Asymmetric binary shift operator.
155
+ def <<(o)
156
+ Radix::Integer.new(to_int << o.to_int, base)
157
+ end
158
+
159
+ # AND bit operator
160
+ def &(o)
161
+ Radix::Integer.new(to_int & o.to_int, base)
162
+ end
163
+
164
+ #
165
+ def abs
166
+ self.class.new(value.abs, base)
167
+ end
168
+
169
+ # Strict equality requires same class as well as value.
170
+ def eql?(num)
171
+ self.class.equal?(num.class) && self == num
172
+ end
173
+
174
+ # Simple equality requires equal values only.
175
+ # TODO: Handle Float and Radix::Float.
176
+ def ==(other)
177
+ case other
178
+ when Float, Integer # Radix
179
+ value == other.value
180
+ else
181
+ value == other
182
+ end
183
+ end
184
+
185
+ #
186
+ def <=>(other)
187
+ value <=> other.to_f # to_num
188
+ end
189
+
190
+ #
191
+ def coerce(value)
192
+ [Radix::Integer.new(value), self]
193
+ end
194
+
195
+ private
196
+
197
+ # Perform arthmetic operation.
198
+ def operation(op, other)
199
+ a = self.to_i
200
+ b = other.to_i
201
+ x = a.__send__(op, b)
202
+ self.class.new(x, base)
203
+ end
204
+
205
+ #
206
+ def base_conversion(value, base)
207
+ #if value < 0
208
+ # @negative, value = true, value.abs
209
+ #end
210
+ i = value.abs
211
+
212
+ a = []
213
+ while i > 0
214
+ i, r = i.divmod(base)
215
+ a << r
216
+ end
217
+
218
+ a.reverse
219
+ end
220
+
221
+ end
222
+
223
+ end
224
+
225
+ ### Want to see the hard way to do addition?
226
+ ##
227
+ ## def +(other)
228
+ ## other = convert_other(other)
229
+ ##
230
+ ## result = []
231
+ ## index = -1
232
+ ## carry = 0
233
+ ##
234
+ ## x1 = self.digits[index]
235
+ ## x2 = other.digits[index]
236
+ ## while x1 or x2
237
+ ## r = (x1||0) + (x2||0) + carry
238
+ ## if r >= base
239
+ ## result.unshift(r - base)
240
+ ## carry = 1
241
+ ## else
242
+ ## result.unshift(r)
243
+ ## carry = 0
244
+ ## end
245
+ ## index -= 1
246
+ ## x1 = self.digits[index]
247
+ ## x2 = other.digits[index]
248
+ ## end
249
+ ## result << carry if carry != 0
250
+ ## Radix::Integer.new(result, base)
251
+ ## end
252
+ ##
253
+ ## def convert_other(other)
254
+ ## case other
255
+ ## when Radix::Integer
256
+ ## other.convert(base)
257
+ ## when Integer
258
+ ## Radix::Integer.new(other, base)
259
+ ## when String, Array
260
+ ## Radix::Integer.new(other, base)
261
+ ## end
262
+ ## end
263
+ ##