nio 0.2.1 → 0.2.2

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.
@@ -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