nio 0.2.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.
- data/History.txt +5 -0
- data/License.txt +20 -0
- data/Manifest.txt +34 -0
- data/README.txt +560 -0
- data/Rakefile +4 -0
- data/SOURCE.txt +31 -0
- data/config/hoe.rb +73 -0
- data/config/requirements.rb +17 -0
- data/lib/nio/flttol.rb +654 -0
- data/lib/nio/fmt.rb +1872 -0
- data/lib/nio/repdec.rb +496 -0
- data/lib/nio/rtnlzr.rb +406 -0
- data/lib/nio/sugar.rb +99 -0
- data/lib/nio/tools.rb +44 -0
- data/lib/nio/version.rb +9 -0
- data/lib/nio.rb +8 -0
- data/log/debug.log +0 -0
- data/script/destroy +14 -0
- data/script/destroy.cmd +1 -0
- data/script/generate +14 -0
- data/script/generate.cmd +1 -0
- data/script/txt2html +74 -0
- data/script/txt2html.cmd +1 -0
- data/setup.rb +1585 -0
- data/tasks/deployment.rake +27 -0
- data/tasks/environment.rake +7 -0
- data/tasks/nuweb.rake +69 -0
- data/tasks/website.rake +17 -0
- data/test/data.yaml +101 -0
- data/test/test_fmt.rb +373 -0
- data/test/test_helper.rb +32 -0
- data/test/test_repdec.rb +88 -0
- data/test/test_rtnlzr.rb +125 -0
- data/test/test_tools.rb +40 -0
- metadata +88 -0
data/lib/nio/repdec.rb
ADDED
@@ -0,0 +1,496 @@
|
|
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 = 2048
|
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
|
+
def setQ(x,y, opt=DEF_OPT)
|
383
|
+
@radix = opt.digits.radix if opt.digits_defined?
|
384
|
+
xy_sign = x==0 ? 0 : x<0 ? -1 : +1;
|
385
|
+
xy_sign = -xy_sign if y<0;
|
386
|
+
@sign = xy_sign
|
387
|
+
x = x.abs;
|
388
|
+
y = y.abs;
|
389
|
+
|
390
|
+
@d = [];
|
391
|
+
@rep_i = nil;
|
392
|
+
|
393
|
+
if y==0 then
|
394
|
+
if x==0 then
|
395
|
+
@ip = :indeterminate
|
396
|
+
else
|
397
|
+
@ip = xy_sign==-1 ? :neginfinity : :posinfinity
|
398
|
+
end
|
399
|
+
return self
|
400
|
+
end
|
401
|
+
|
402
|
+
k = [];
|
403
|
+
@ip = x.div(y) #x/y;
|
404
|
+
x -= @ip*y;
|
405
|
+
i = 0;
|
406
|
+
ended = false;
|
407
|
+
|
408
|
+
max_d = opt.max_d
|
409
|
+
while x>0 && @rep_i==nil && (max_d<=0 || i<max_d)
|
410
|
+
@rep_i = k.index(x)
|
411
|
+
if @rep_i.nil? then
|
412
|
+
k.push x;
|
413
|
+
x *= @radix
|
414
|
+
@d.push x.div(y) # x/y;
|
415
|
+
x-= @d[i]*y;
|
416
|
+
i += 1;
|
417
|
+
end
|
418
|
+
end
|
419
|
+
self
|
420
|
+
end
|
421
|
+
|
422
|
+
def getQ(opt=DEF_OPT)
|
423
|
+
raise RepDecError,"Base mismatch: #{opt.digits.radix} when #{@radix} was expected." if opt.digits_defined? && @radix!=opt.digits.radix
|
424
|
+
|
425
|
+
if !ip.is_a?(Integer) then
|
426
|
+
y = 0;
|
427
|
+
x=0 if ip==:indeterminate;
|
428
|
+
x=1 if ip==:posinfinity
|
429
|
+
x=-1 if ip==:neginfinity
|
430
|
+
return x,y;
|
431
|
+
end if
|
432
|
+
|
433
|
+
|
434
|
+
n = @d.length
|
435
|
+
a = @ip
|
436
|
+
b = a
|
437
|
+
for i in 0...n
|
438
|
+
a*=@radix
|
439
|
+
a+=@d[i];
|
440
|
+
if @rep_i!=nil && i<@rep_i
|
441
|
+
b *= @radix
|
442
|
+
b += @d[i];
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
x = a
|
447
|
+
x -= b if @rep_i!=nil
|
448
|
+
|
449
|
+
y = @radix**n
|
450
|
+
y -= @radix**@rep_i if @rep_i!=nil
|
451
|
+
|
452
|
+
d = Nio.gcd(x,y)
|
453
|
+
x /= d
|
454
|
+
y /= d
|
455
|
+
|
456
|
+
x = -x if @sign<0
|
457
|
+
|
458
|
+
return x,y;
|
459
|
+
end
|
460
|
+
|
461
|
+
#protected
|
462
|
+
|
463
|
+
attr_reader :d, :ip, :rep_i, :sign;
|
464
|
+
attr_writer :d, :ip, :rep_i, :sign;
|
465
|
+
|
466
|
+
end
|
467
|
+
|
468
|
+
|
469
|
+
def RepDec.group_digits(digits, opt)
|
470
|
+
if opt.grp_sep!=nil && opt.grp_sep!='' && opt.grp.length>0
|
471
|
+
grouped = ''
|
472
|
+
i = 0
|
473
|
+
while digits.length>0
|
474
|
+
l = opt.grp[i]
|
475
|
+
l = digits.length if l>digits.length
|
476
|
+
grouped = opt.grp_sep + grouped if grouped.length>0
|
477
|
+
grouped = digits[-l,l] + grouped
|
478
|
+
digits = digits[0,digits.length-l]
|
479
|
+
i += 1 if i<opt.grp.length-1
|
480
|
+
end
|
481
|
+
grouped
|
482
|
+
else
|
483
|
+
digits
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
module_function
|
488
|
+
|
489
|
+
def gcd(a,b)
|
490
|
+
while b!=0 do
|
491
|
+
a,b = b, a.modulo(b)
|
492
|
+
end
|
493
|
+
return a.abs;
|
494
|
+
end
|
495
|
+
|
496
|
+
end
|