radix 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ ##