nio 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,507 +1,507 @@
1
- # repdec.rb -- Repeating Decimals (Repeating Numerals, actually)
2
-
3
- # Copyright (C) 2003-2005, Javier Goizueta <javier@goizueta.info>
4
- #
5
- # This program is free software; you can redistribute it and/or
6
- # modify it under the terms of the GNU General Public License
7
- # as published by the Free Software Foundation; either version 2
8
- # of the License, or (at your option) any later version.
9
-
10
- require 'nio/tools'
11
- module Nio
12
-
13
- class RepDecError <StandardError
14
- end
15
-
16
- class DigitsDef
17
- include StateEquivalent
18
- def initialize(ds='0123456789', cs=true)
19
- @digits = ds
20
- @casesens = cs
21
- @dncase = (ds.downcase==ds)
22
- @radix = @digits.size
23
- end
24
- def is_digit?(ch_code)
25
- ch_code = set_case(ch_code) unless @casesens
26
- @digits.include?(ch_code)
27
- end
28
- def digit_value(ch_code)
29
- ch_code = set_case(ch_code) unless @casesens
30
- @digits.index(ch_code)
31
- end
32
- def digit_char(v)
33
- @digits[v]
34
- end
35
- def digit_char_safe(v)
36
- v>=0 && v<@radix ? @digits[v] : nil
37
- end
38
- def radix
39
- @radix
40
- end
41
- def DigitsDef.base(b,dncase=false,casesens=false)
42
- dgs = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[0,b]
43
- dgs.downcase! if dncase
44
- DigitsDef.new(dgs,casesens)
45
- end
46
- private
47
- def set_case(ch_code)
48
- ch_code = ch_code.chr if ch_code.kind_of?(Numeric)
49
- @dncase ? ch_code.downcase[0] : ch_code.upcase[0]
50
- end
51
- end
52
-
53
-
54
- # RepDec handles repeating decimals (repeating numerals actually)
55
- class RepDec
56
- include StateEquivalent
57
-
58
- class Opt # :nodoc:
59
- include StateEquivalent
60
- def initialize() #default options
61
-
62
- @begin_rep = '<'
63
- @end_rep = '>'
64
-
65
- @auto_rep = '...'
66
-
67
- @dec_sep = '.'
68
- @grp_sep = ','
69
- @grp = [] # [3] for thousands separators
70
-
71
- @inf_txt = 'Infinity'
72
- @nan_txt = 'NaN'
73
-
74
- @digits = DigitsDef.new
75
- @digits_defined = false
76
-
77
- @max_d = 5000
78
-
79
- end
80
- attr_accessor :begin_rep, :end_rep, :auto_rep, :dec_sep, :grp_sep, :grp, :max_d
81
- attr_accessor :nan_txt, :inf_txt
82
-
83
- def set_delim(begin_d,end_d='')
84
- @begin_rep = begin_d
85
- @end_rep = end_d
86
- return self
87
- end
88
- def set_suffix(a)
89
- @auto_rep = a
90
- return self
91
- end
92
- def set_sep(d)
93
- @dec_sep = a
94
- return self
95
- end
96
- def set_grouping(sep,g=[])
97
- @grp_sep = a
98
- @grp = g
99
- return self
100
- end
101
- def set_special(nan_txt, inf_txt)
102
- @nan_txt = nan_txt
103
- @inf_txt = inf_txt
104
- return self
105
- end
106
-
107
- def set_digits(ds, dncase=false, casesens=false)
108
- if ds
109
- @digits_defined = true
110
- if ds.kind_of?(DigitsDef)
111
- @digits = ds
112
- elsif ds.kind_of?(Numeric)
113
- @digits = DigitsDef.base(ds, dncase, casesens)
114
- else
115
- @digits = DigitsDef.new(ds,casesens)
116
- end
117
- else
118
- @digits = DigitsDef.new
119
- @digits_defined = false
120
- end
121
- self
122
- end
123
-
124
- attr_accessor :digits
125
- def digits_defined?
126
- @digits_defined
127
- end
128
-
129
- end
130
-
131
- DEF_OPT=Opt.new
132
-
133
-
134
- def initialize(b=10)
135
- setZ(b)
136
- end
137
-
138
- def setZ(b=10)
139
- @ip = 0;
140
- @d = [];
141
- @rep_i = nil;
142
- @sign = 0;
143
- @radix = b;
144
- self
145
- end
146
-
147
- def setS(str, opt=DEF_OPT)
148
- setZ(opt.digits_defined? ? opt.digits.radix : @radix);
149
- sgn,i_str,f_str,ri,detect_rep = RepDec.parse(str,opt)
150
- if i_str.kind_of?(Symbol)
151
- @ip = i_str
152
- else
153
- @ip = i_str.to_i(@radix); # this assumes conventional digits
154
- end
155
- @sign = sgn
156
- @rep_i = ri if ri
157
- f_str.each_byte{|b| @d.push opt.digits.digit_value(b)} unless f_str.nil?
158
-
159
- if detect_rep then
160
-
161
- for l in 1..(@d.length/2)
162
- l = @d.length/2 + 1 - l;
163
- if @d[-l..-1]==@d[-2*l...-l]
164
-
165
- for m in 1..l
166
- if l.modulo(m)==0 then
167
- reduce_l = true;
168
- for i in 2..l/m
169
- if @d[-m..-1]!=@d[-i*m...-i*m+m] then
170
- reduce_l = false;
171
- break;
172
- end
173
- end
174
- if reduce_l then
175
- l = m
176
- break
177
- end
178
- end
179
- end
180
-
181
-
182
- @rep_i = @d.length - 2*l;
183
- l.times { @d.pop }
184
-
185
-
186
- while @d.length >= 2*l && @d[-l..-1]==@d[-2*l...-l]
187
-
188
- @rep_i = @d.length - 2*l;
189
- l.times { @d.pop }
190
-
191
- end
192
-
193
- break
194
- end
195
- end
196
-
197
- end
198
-
199
-
200
- if @rep_i!=nil then
201
- if @d.length==@rep_i+1 && @d[@rep_i]==0 then
202
- @rep_i = nil;
203
- @d.pop;
204
- end
205
- end
206
- @d.pop while @d[@d.length-1]==0
207
-
208
- self
209
- end
210
-
211
- def RepDec.parse(str, opt=DEF_OPT)
212
- sgn,i_str,f_str,ri,detect_rep = nil,nil,nil,nil,nil
213
-
214
- i = 0;
215
- l = str.length;
216
-
217
- detect_rep = false;
218
-
219
-
220
- i += 1 while i<str.length && str[i,1] =~/\s/
221
-
222
-
223
- neg = false;
224
-
225
- neg = true if str[i,1]=='-'
226
- i += 1 if str[i,1]=='-' || str[i,1]=='+'
227
-
228
-
229
- i += 1 while i<str.length && str[i,1] =~/\s/
230
-
231
-
232
- str.upcase!
233
- if str[i,opt.nan_txt.size]==opt.nan_txt.upcase
234
- i_str = :indeterminate;
235
- elsif str[i,opt.inf_txt.size]==opt.inf_txt.upcase
236
- i_str = neg ? :neginfinity : :posinfinity;
237
- end
238
-
239
- unless i_str
240
- i_str = "0";
241
- while i<l && str[i,1]!=opt.dec_sep
242
- break if str[i,opt.auto_rep.length]==opt.auto_rep && opt.auto_rep!=''
243
- i_str += str[i,1] if str[i,1]!=opt.grp_sep
244
- i += 1;
245
- end
246
- sgn = neg ? -1 : +1
247
- i += 1; # skip the decimal separator
248
- end
249
-
250
- unless i_str.kind_of?(Symbol)
251
- j = 0;
252
- f_str = ''
253
- while i<l
254
- ch = str[i,1];
255
- if ch==opt.begin_rep then
256
- ri = j;
257
- elsif ch==opt.end_rep then
258
- i = l;
259
- elsif ch==opt.auto_rep[0,1] then
260
- detect_rep = true;
261
- i = l;
262
- else
263
- f_str << ch
264
- j += 1;
265
- end
266
- i += 1;
267
- end
268
- end
269
- return [sgn,i_str,f_str,ri,detect_rep]
270
- end
271
-
272
- def getS(nrep=0, opt=DEF_OPT)
273
- raise RepDecError,"Base mismatch: #{opt.digits.radix} when #{@radix} was expected." if opt.digits_defined? && @radix!=opt.digits.radix
274
-
275
- if !ip.is_a?(Integer) then
276
- str=opt.nan_txt if ip==:indeterminate;
277
- str=opt.inf_txt if ip==:posinfinity
278
- str='-'+opt.inf_txt if ip==:neginfinity
279
- return str;
280
- end
281
-
282
- s = "";
283
- s += '-' if @sign<0
284
- s += RepDec.group_digits(@ip.to_s(@radix),opt);
285
- s += opt.dec_sep if @d.length>0;
286
- for i in 0...@d.length
287
- break if nrep>0 && @rep_i==i;
288
- s += opt.begin_rep if i==@rep_i;
289
- s << opt.digits.digit_char(@d[i])
290
- end;
291
- if nrep>0 then
292
- if @rep_i!=nil then
293
- nrep += 1;
294
- nrep.times do
295
- for i in @rep_i...@d.length
296
- s << opt.digits.digit_char(@d[i])
297
- end
298
- end
299
-
300
- check = RepDec.new;
301
- check.setS s+opt.auto_rep, opt;
302
- #print " s=",s,"\n"
303
- #print " self=",self.to_s,"\n"
304
- while check!=self
305
- for i in @rep_i...@d.length
306
- s << opt.digits.digit_char(@d[i])
307
- end
308
- check.setS s+opt.auto_rep, opt;
309
- end
310
-
311
- s += opt.auto_rep;
312
- end
313
- else
314
- s += opt.end_rep if @rep_i!=nil;
315
- end
316
- return s;
317
- end
318
-
319
- def to_s()
320
- getS
321
- end
322
-
323
- def normalize!(remove_trailing_zeros=true)
324
- if ip.is_a?(Integer)
325
- if @rep_i!=nil && @rep_i==@d.length-1 && @d[@rep_i]==(@radix-1) then
326
- @d.pop;
327
- @rep_i = nil;
328
-
329
- i = @d.length-1;
330
- carry = 1;
331
- while carry>0 && i>=0
332
- @d[i] += carry;
333
- carry = 0;
334
- if @d[i]>(@radix) then
335
- carry = 1;
336
- @d[i]=0;
337
- @d.pop if i==@d.length;
338
- end
339
- i -= 1;
340
- end
341
- @ip += carry;
342
-
343
- end
344
-
345
- if @rep_i!=nil && @rep_i>=@d.length
346
- @rep_i = nil
347
- end
348
-
349
- if @rep_i!=nil && @rep_i>=0
350
- unless @d[@rep_i..-1].find {|x| x!=0}
351
- @d = @d[0...@rep_i]
352
- @rep_i = nil
353
- end
354
- end
355
- if @rep_i==nil && remove_trailing_zeros
356
- while @d[@d.length-1]==0
357
- @d.pop
358
- end
359
- end
360
-
361
- end
362
- end
363
-
364
- def copy()
365
- c = clone
366
- c.d = d.clone
367
- return c;
368
- end
369
-
370
- def ==(c)
371
- a = copy;
372
- b = c.copy;
373
- a.normalize!
374
- b.normalize!
375
- return a.ip==b.ip && a.d==b.d && a.rep_i==b.rep_i
376
- end
377
-
378
- #def !=(c)
379
- # return !(self==c);
380
- #end
381
-
382
- # Change the maximum number of digits that RepDec objects
383
- # can handle.
384
- def RepDec.maximum_number_of_digits=(n)
385
- @max_d = [n,2048].max
386
- end
387
- # Return the maximum number of digits that RepDec objects
388
- # can handle.
389
- def RepDec.maximum_number_of_digits
390
- @max_d
391
- end
392
-
393
- def setQ(x,y, opt=DEF_OPT)
394
- @radix = opt.digits.radix if opt.digits_defined?
395
- xy_sign = x==0 ? 0 : x<0 ? -1 : +1;
396
- xy_sign = -xy_sign if y<0;
397
- @sign = xy_sign
398
- x = x.abs;
399
- y = y.abs;
400
-
401
- @d = [];
402
- @rep_i = nil;
403
-
404
- if y==0 then
405
- if x==0 then
406
- @ip = :indeterminate
407
- else
408
- @ip = xy_sign==-1 ? :neginfinity : :posinfinity
409
- end
410
- return self
411
- end
412
-
413
- k = {};
414
- @ip = x.div(y) #x/y;
415
- x -= @ip*y;
416
- i = 0;
417
- ended = false;
418
-
419
- max_d = opt.max_d
420
- while x>0 && @rep_i==nil && (max_d<=0 || i<max_d)
421
- @rep_i = k[x]
422
- if @rep_i.nil? then
423
- k[x] = i;
424
- x *= @radix
425
- d,x = x.divmod(y)
426
- @d.push d
427
- i += 1;
428
- end
429
- end
430
- self
431
- end
432
-
433
- def getQ(opt=DEF_OPT)
434
- raise RepDecError,"Base mismatch: #{opt.digits.radix} when #{@radix} was expected." if opt.digits_defined? && @radix!=opt.digits.radix
435
-
436
- if !ip.is_a?(Integer) then
437
- y = 0;
438
- x=0 if ip==:indeterminate;
439
- x=1 if ip==:posinfinity
440
- x=-1 if ip==:neginfinity
441
- return x,y;
442
- end if
443
-
444
-
445
- n = @d.length
446
- a = @ip
447
- b = a
448
- for i in 0...n
449
- a*=@radix
450
- a+=@d[i];
451
- if @rep_i!=nil && i<@rep_i
452
- b *= @radix
453
- b += @d[i];
454
- end
455
- end
456
-
457
- x = a
458
- x -= b if @rep_i!=nil
459
-
460
- y = @radix**n
461
- y -= @radix**@rep_i if @rep_i!=nil
462
-
463
- d = Nio.gcd(x,y)
464
- x /= d
465
- y /= d
466
-
467
- x = -x if @sign<0
468
-
469
- return x,y;
470
- end
471
-
472
- #protected
473
-
474
- attr_reader :d, :ip, :rep_i, :sign;
475
- attr_writer :d, :ip, :rep_i, :sign;
476
-
477
- end
478
-
479
-
480
- def RepDec.group_digits(digits, opt)
481
- if opt.grp_sep!=nil && opt.grp_sep!='' && opt.grp.length>0
482
- grouped = ''
483
- i = 0
484
- while digits.length>0
485
- l = opt.grp[i]
486
- l = digits.length if l>digits.length
487
- grouped = opt.grp_sep + grouped if grouped.length>0
488
- grouped = digits[-l,l] + grouped
489
- digits = digits[0,digits.length-l]
490
- i += 1 if i<opt.grp.length-1
491
- end
492
- grouped
493
- else
494
- digits
495
- end
496
- end
497
-
498
- module_function
499
-
500
- def gcd(a,b)
501
- while b!=0 do
502
- a,b = b, a.modulo(b)
503
- end
504
- return a.abs;
505
- end
506
-
507
- end
1
+ # repdec.rb -- Repeating Decimals (Repeating Numerals, actually)
2
+
3
+ # Copyright (C) 2003-2005, Javier Goizueta <javier@goizueta.info>
4
+ #
5
+ # This program is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU General Public License
7
+ # as published by the Free Software Foundation; either version 2
8
+ # of the License, or (at your option) any later version.
9
+
10
+ require 'nio/tools'
11
+ module Nio
12
+
13
+ class RepDecError <StandardError
14
+ end
15
+
16
+ class DigitsDef
17
+ include StateEquivalent
18
+ def initialize(ds='0123456789', cs=true)
19
+ @digits = ds
20
+ @casesens = cs
21
+ @dncase = (ds.downcase==ds)
22
+ @radix = @digits.size
23
+ end
24
+ def is_digit?(ch_code)
25
+ ch_code = set_case(ch_code) unless @casesens
26
+ @digits.include?(ch_code)
27
+ end
28
+ def digit_value(ch_code)
29
+ ch_code = set_case(ch_code) unless @casesens
30
+ @digits.index(ch_code.chr)
31
+ end
32
+ def digit_char(v)
33
+ @digits[v]
34
+ end
35
+ def digit_char_safe(v)
36
+ v>=0 && v<@radix ? @digits[v] : nil
37
+ end
38
+ def radix
39
+ @radix
40
+ end
41
+ def DigitsDef.base(b,dncase=false,casesens=false)
42
+ dgs = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[0,b]
43
+ dgs.downcase! if dncase
44
+ DigitsDef.new(dgs,casesens)
45
+ end
46
+ private
47
+ def set_case(ch_code)
48
+ ch_code = ch_code.chr if ch_code.kind_of?(Numeric)
49
+ @dncase ? ch_code.downcase[0] : ch_code.upcase[0]
50
+ end
51
+ end
52
+
53
+
54
+ # RepDec handles repeating decimals (repeating numerals actually)
55
+ class RepDec
56
+ include StateEquivalent
57
+
58
+ class Opt # :nodoc:
59
+ include StateEquivalent
60
+ def initialize() #default options
61
+
62
+ @begin_rep = '<'
63
+ @end_rep = '>'
64
+
65
+ @auto_rep = '...'
66
+
67
+ @dec_sep = '.'
68
+ @grp_sep = ','
69
+ @grp = [] # [3] for thousands separators
70
+
71
+ @inf_txt = 'Infinity'
72
+ @nan_txt = 'NaN'
73
+
74
+ @digits = DigitsDef.new
75
+ @digits_defined = false
76
+
77
+ @max_d = 5000
78
+
79
+ end
80
+ attr_accessor :begin_rep, :end_rep, :auto_rep, :dec_sep, :grp_sep, :grp, :max_d
81
+ attr_accessor :nan_txt, :inf_txt
82
+
83
+ def set_delim(begin_d,end_d='')
84
+ @begin_rep = begin_d
85
+ @end_rep = end_d
86
+ return self
87
+ end
88
+ def set_suffix(a)
89
+ @auto_rep = a
90
+ return self
91
+ end
92
+ def set_sep(d)
93
+ @dec_sep = a
94
+ return self
95
+ end
96
+ def set_grouping(sep,g=[])
97
+ @grp_sep = a
98
+ @grp = g
99
+ return self
100
+ end
101
+ def set_special(nan_txt, inf_txt)
102
+ @nan_txt = nan_txt
103
+ @inf_txt = inf_txt
104
+ return self
105
+ end
106
+
107
+ def set_digits(ds, dncase=false, casesens=false)
108
+ if ds
109
+ @digits_defined = true
110
+ if ds.kind_of?(DigitsDef)
111
+ @digits = ds
112
+ elsif ds.kind_of?(Numeric)
113
+ @digits = DigitsDef.base(ds, dncase, casesens)
114
+ else
115
+ @digits = DigitsDef.new(ds,casesens)
116
+ end
117
+ else
118
+ @digits = DigitsDef.new
119
+ @digits_defined = false
120
+ end
121
+ self
122
+ end
123
+
124
+ attr_accessor :digits
125
+ def digits_defined?
126
+ @digits_defined
127
+ end
128
+
129
+ end
130
+
131
+ DEF_OPT=Opt.new
132
+
133
+
134
+ def initialize(b=10)
135
+ setZ(b)
136
+ end
137
+
138
+ def setZ(b=10)
139
+ @ip = 0;
140
+ @d = [];
141
+ @rep_i = nil;
142
+ @sign = 0;
143
+ @radix = b;
144
+ self
145
+ end
146
+
147
+ def setS(str, opt=DEF_OPT)
148
+ setZ(opt.digits_defined? ? opt.digits.radix : @radix);
149
+ sgn,i_str,f_str,ri,detect_rep = RepDec.parse(str,opt)
150
+ if i_str.kind_of?(Symbol)
151
+ @ip = i_str
152
+ else
153
+ @ip = i_str.to_i(@radix); # this assumes conventional digits
154
+ end
155
+ @sign = sgn
156
+ @rep_i = ri if ri
157
+ f_str.each_byte{|b| @d.push opt.digits.digit_value(b)} unless f_str.nil?
158
+
159
+ if detect_rep then
160
+
161
+ for l in 1..(@d.length/2)
162
+ l = @d.length/2 + 1 - l;
163
+ if @d[-l..-1]==@d[-2*l...-l]
164
+
165
+ for m in 1..l
166
+ if l.modulo(m)==0 then
167
+ reduce_l = true;
168
+ for i in 2..l/m
169
+ if @d[-m..-1]!=@d[-i*m...-i*m+m] then
170
+ reduce_l = false;
171
+ break;
172
+ end
173
+ end
174
+ if reduce_l then
175
+ l = m
176
+ break
177
+ end
178
+ end
179
+ end
180
+
181
+
182
+ @rep_i = @d.length - 2*l;
183
+ l.times { @d.pop }
184
+
185
+
186
+ while @d.length >= 2*l && @d[-l..-1]==@d[-2*l...-l]
187
+
188
+ @rep_i = @d.length - 2*l;
189
+ l.times { @d.pop }
190
+
191
+ end
192
+
193
+ break
194
+ end
195
+ end
196
+
197
+ end
198
+
199
+
200
+ if @rep_i!=nil then
201
+ if @d.length==@rep_i+1 && @d[@rep_i]==0 then
202
+ @rep_i = nil;
203
+ @d.pop;
204
+ end
205
+ end
206
+ @d.pop while @d[@d.length-1]==0
207
+
208
+ self
209
+ end
210
+
211
+ def RepDec.parse(str, opt=DEF_OPT)
212
+ sgn,i_str,f_str,ri,detect_rep = nil,nil,nil,nil,nil
213
+
214
+ i = 0;
215
+ l = str.length;
216
+
217
+ detect_rep = false;
218
+
219
+
220
+ i += 1 while i<str.length && str[i,1] =~/\s/
221
+
222
+
223
+ neg = false;
224
+
225
+ neg = true if str[i,1]=='-'
226
+ i += 1 if str[i,1]=='-' || str[i,1]=='+'
227
+
228
+
229
+ i += 1 while i<str.length && str[i,1] =~/\s/
230
+
231
+
232
+ str.upcase!
233
+ if str[i,opt.nan_txt.size]==opt.nan_txt.upcase
234
+ i_str = :indeterminate;
235
+ elsif str[i,opt.inf_txt.size]==opt.inf_txt.upcase
236
+ i_str = neg ? :neginfinity : :posinfinity;
237
+ end
238
+
239
+ unless i_str
240
+ i_str = "0";
241
+ while i<l && str[i,1]!=opt.dec_sep
242
+ break if str[i,opt.auto_rep.length]==opt.auto_rep && opt.auto_rep!=''
243
+ i_str += str[i,1] if str[i,1]!=opt.grp_sep
244
+ i += 1;
245
+ end
246
+ sgn = neg ? -1 : +1
247
+ i += 1; # skip the decimal separator
248
+ end
249
+
250
+ unless i_str.kind_of?(Symbol)
251
+ j = 0;
252
+ f_str = ''
253
+ while i<l
254
+ ch = str[i,1];
255
+ if ch==opt.begin_rep then
256
+ ri = j;
257
+ elsif ch==opt.end_rep then
258
+ i = l;
259
+ elsif ch==opt.auto_rep[0,1] then
260
+ detect_rep = true;
261
+ i = l;
262
+ else
263
+ f_str << ch
264
+ j += 1;
265
+ end
266
+ i += 1;
267
+ end
268
+ end
269
+ return [sgn,i_str,f_str,ri,detect_rep]
270
+ end
271
+
272
+ def getS(nrep=0, opt=DEF_OPT)
273
+ raise RepDecError,"Base mismatch: #{opt.digits.radix} when #{@radix} was expected." if opt.digits_defined? && @radix!=opt.digits.radix
274
+
275
+ if !ip.is_a?(Integer) then
276
+ str=opt.nan_txt if ip==:indeterminate;
277
+ str=opt.inf_txt if ip==:posinfinity
278
+ str='-'+opt.inf_txt if ip==:neginfinity
279
+ return str;
280
+ end
281
+
282
+ s = "";
283
+ s += '-' if @sign<0
284
+ s += RepDec.group_digits(@ip.to_s(@radix),opt);
285
+ s += opt.dec_sep if @d.length>0;
286
+ for i in 0...@d.length
287
+ break if nrep>0 && @rep_i==i;
288
+ s += opt.begin_rep if i==@rep_i;
289
+ s << opt.digits.digit_char(@d[i])
290
+ end;
291
+ if nrep>0 then
292
+ if @rep_i!=nil then
293
+ nrep += 1;
294
+ nrep.times do
295
+ for i in @rep_i...@d.length
296
+ s << opt.digits.digit_char(@d[i])
297
+ end
298
+ end
299
+
300
+ check = RepDec.new;
301
+ check.setS s+opt.auto_rep, opt;
302
+ #print " s=",s,"\n"
303
+ #print " self=",self.to_s,"\n"
304
+ while check!=self
305
+ for i in @rep_i...@d.length
306
+ s << opt.digits.digit_char(@d[i])
307
+ end
308
+ check.setS s+opt.auto_rep, opt;
309
+ end
310
+
311
+ s += opt.auto_rep;
312
+ end
313
+ else
314
+ s += opt.end_rep if @rep_i!=nil;
315
+ end
316
+ return s;
317
+ end
318
+
319
+ def to_s()
320
+ getS
321
+ end
322
+
323
+ def normalize!(remove_trailing_zeros=true)
324
+ if ip.is_a?(Integer)
325
+ if @rep_i!=nil && @rep_i==@d.length-1 && @d[@rep_i]==(@radix-1) then
326
+ @d.pop;
327
+ @rep_i = nil;
328
+
329
+ i = @d.length-1;
330
+ carry = 1;
331
+ while carry>0 && i>=0
332
+ @d[i] += carry;
333
+ carry = 0;
334
+ if @d[i]>(@radix) then
335
+ carry = 1;
336
+ @d[i]=0;
337
+ @d.pop if i==@d.length;
338
+ end
339
+ i -= 1;
340
+ end
341
+ @ip += carry;
342
+
343
+ end
344
+
345
+ if @rep_i!=nil && @rep_i>=@d.length
346
+ @rep_i = nil
347
+ end
348
+
349
+ if @rep_i!=nil && @rep_i>=0
350
+ unless @d[@rep_i..-1].find {|x| x!=0}
351
+ @d = @d[0...@rep_i]
352
+ @rep_i = nil
353
+ end
354
+ end
355
+ if @rep_i==nil && remove_trailing_zeros
356
+ while @d[@d.length-1]==0
357
+ @d.pop
358
+ end
359
+ end
360
+
361
+ end
362
+ end
363
+
364
+ def copy()
365
+ c = clone
366
+ c.d = d.clone
367
+ return c;
368
+ end
369
+
370
+ def ==(c)
371
+ a = copy;
372
+ b = c.copy;
373
+ a.normalize!
374
+ b.normalize!
375
+ return a.ip==b.ip && a.d==b.d && a.rep_i==b.rep_i
376
+ end
377
+
378
+ #def !=(c)
379
+ # return !(self==c);
380
+ #end
381
+
382
+ # Change the maximum number of digits that RepDec objects
383
+ # can handle.
384
+ def RepDec.maximum_number_of_digits=(n)
385
+ @max_d = [n,2048].max
386
+ end
387
+ # Return the maximum number of digits that RepDec objects
388
+ # can handle.
389
+ def RepDec.maximum_number_of_digits
390
+ @max_d
391
+ end
392
+
393
+ def setQ(x,y, opt=DEF_OPT)
394
+ @radix = opt.digits.radix if opt.digits_defined?
395
+ xy_sign = x==0 ? 0 : x<0 ? -1 : +1;
396
+ xy_sign = -xy_sign if y<0;
397
+ @sign = xy_sign
398
+ x = x.abs;
399
+ y = y.abs;
400
+
401
+ @d = [];
402
+ @rep_i = nil;
403
+
404
+ if y==0 then
405
+ if x==0 then
406
+ @ip = :indeterminate
407
+ else
408
+ @ip = xy_sign==-1 ? :neginfinity : :posinfinity
409
+ end
410
+ return self
411
+ end
412
+
413
+ k = {};
414
+ @ip = x.div(y) #x/y;
415
+ x -= @ip*y;
416
+ i = 0;
417
+ ended = false;
418
+
419
+ max_d = opt.max_d
420
+ while x>0 && @rep_i==nil && (max_d<=0 || i<max_d)
421
+ @rep_i = k[x]
422
+ if @rep_i.nil? then
423
+ k[x] = i;
424
+ x *= @radix
425
+ d,x = x.divmod(y)
426
+ @d.push d
427
+ i += 1;
428
+ end
429
+ end
430
+ self
431
+ end
432
+
433
+ def getQ(opt=DEF_OPT)
434
+ raise RepDecError,"Base mismatch: #{opt.digits.radix} when #{@radix} was expected." if opt.digits_defined? && @radix!=opt.digits.radix
435
+
436
+ if !ip.is_a?(Integer) then
437
+ y = 0;
438
+ x=0 if ip==:indeterminate;
439
+ x=1 if ip==:posinfinity
440
+ x=-1 if ip==:neginfinity
441
+ return x,y;
442
+ end if
443
+
444
+
445
+ n = @d.length
446
+ a = @ip
447
+ b = a
448
+ for i in 0...n
449
+ a*=@radix
450
+ a+=@d[i];
451
+ if @rep_i!=nil && i<@rep_i
452
+ b *= @radix
453
+ b += @d[i];
454
+ end
455
+ end
456
+
457
+ x = a
458
+ x -= b if @rep_i!=nil
459
+
460
+ y = @radix**n
461
+ y -= @radix**@rep_i if @rep_i!=nil
462
+
463
+ d = Nio.gcd(x,y)
464
+ x /= d
465
+ y /= d
466
+
467
+ x = -x if @sign<0
468
+
469
+ return x,y;
470
+ end
471
+
472
+ #protected
473
+
474
+ attr_reader :d, :ip, :rep_i, :sign;
475
+ attr_writer :d, :ip, :rep_i, :sign;
476
+
477
+ end
478
+
479
+
480
+ def RepDec.group_digits(digits, opt)
481
+ if opt.grp_sep!=nil && opt.grp_sep!='' && opt.grp.length>0
482
+ grouped = ''
483
+ i = 0
484
+ while digits.length>0
485
+ l = opt.grp[i]
486
+ l = digits.length if l>digits.length
487
+ grouped = opt.grp_sep + grouped if grouped.length>0
488
+ grouped = digits[-l,l] + grouped
489
+ digits = digits[0,digits.length-l]
490
+ i += 1 if i<opt.grp.length-1
491
+ end
492
+ grouped
493
+ else
494
+ digits
495
+ end
496
+ end
497
+
498
+ module_function
499
+
500
+ def gcd(a,b)
501
+ while b!=0 do
502
+ a,b = b, a.modulo(b)
503
+ end
504
+ return a.abs;
505
+ end
506
+
507
+ end