nio 0.2.3 → 0.2.4
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 +8 -0
- data/Manifest.txt +1 -2
- data/README.txt +519 -560
- data/Rakefile +1 -0
- data/lib/nio.rb +6 -7
- data/lib/nio/fmt.rb +378 -437
- data/lib/nio/repdec.rb +31 -31
- data/lib/nio/rtnlzr.rb +88 -81
- data/lib/nio/sugar.rb +69 -99
- data/lib/nio/version.rb +1 -1
- data/tasks/nuweb.rake +53 -33
- data/test/{test_helper.rb → helper.rb} +5 -0
- data/test/test_fmt.rb +98 -100
- data/test/test_repdec.rb +3 -5
- data/test/test_rtnlzr.rb +66 -44
- data/test/test_tools.rb +2 -2
- metadata +17 -7
- data/lib/nio/flttol.rb +0 -669
data/lib/nio/repdec.rb
CHANGED
@@ -48,8 +48,8 @@ module Nio
|
|
48
48
|
ch_code = ch_code.chr if ch_code.kind_of?(Numeric)
|
49
49
|
@dncase ? ch_code.downcase[0] : ch_code.upcase[0]
|
50
50
|
end
|
51
|
-
end
|
52
|
-
|
51
|
+
end
|
52
|
+
|
53
53
|
|
54
54
|
# RepDec handles repeating decimals (repeating numerals actually)
|
55
55
|
class RepDec
|
@@ -76,7 +76,7 @@ module Nio
|
|
76
76
|
|
77
77
|
@max_d = 5000
|
78
78
|
|
79
|
-
end
|
79
|
+
end
|
80
80
|
attr_accessor :begin_rep, :end_rep, :auto_rep, :dec_sep, :grp_sep, :grp, :max_d
|
81
81
|
attr_accessor :nan_txt, :inf_txt
|
82
82
|
|
@@ -105,7 +105,7 @@ module Nio
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def set_digits(ds, dncase=false, casesens=false)
|
108
|
-
if ds
|
108
|
+
if ds
|
109
109
|
@digits_defined = true
|
110
110
|
if ds.kind_of?(DigitsDef)
|
111
111
|
@digits = ds
|
@@ -144,7 +144,7 @@ module Nio
|
|
144
144
|
self
|
145
145
|
end
|
146
146
|
|
147
|
-
def setS(str, opt=DEF_OPT)
|
147
|
+
def setS(str, opt=DEF_OPT)
|
148
148
|
setZ(opt.digits_defined? ? opt.digits.radix : @radix);
|
149
149
|
sgn,i_str,f_str,ri,detect_rep = RepDec.parse(str,opt)
|
150
150
|
if i_str.kind_of?(Symbol)
|
@@ -155,7 +155,7 @@ module Nio
|
|
155
155
|
@sign = sgn
|
156
156
|
@rep_i = ri if ri
|
157
157
|
f_str.each_byte{|b| @d.push opt.digits.digit_value(b)} unless f_str.nil?
|
158
|
-
|
158
|
+
|
159
159
|
if detect_rep then
|
160
160
|
|
161
161
|
for l in 1..(@d.length/2)
|
@@ -169,30 +169,30 @@ module Nio
|
|
169
169
|
if @d[-m..-1]!=@d[-i*m...-i*m+m] then
|
170
170
|
reduce_l = false;
|
171
171
|
break;
|
172
|
-
|
172
|
+
end
|
173
173
|
end
|
174
174
|
if reduce_l then
|
175
175
|
l = m
|
176
176
|
break
|
177
|
-
end
|
177
|
+
end
|
178
178
|
end
|
179
179
|
end
|
180
|
-
|
180
|
+
|
181
181
|
|
182
182
|
@rep_i = @d.length - 2*l;
|
183
183
|
l.times { @d.pop }
|
184
184
|
|
185
185
|
|
186
|
-
while @d.length >= 2*l && @d[-l..-1]==@d[-2*l...-l]
|
186
|
+
while @d.length >= 2*l && @d[-l..-1]==@d[-2*l...-l]
|
187
187
|
|
188
188
|
@rep_i = @d.length - 2*l;
|
189
189
|
l.times { @d.pop }
|
190
190
|
|
191
191
|
end
|
192
|
-
|
192
|
+
|
193
193
|
break
|
194
194
|
end
|
195
|
-
end
|
195
|
+
end
|
196
196
|
|
197
197
|
end
|
198
198
|
|
@@ -201,10 +201,10 @@ module Nio
|
|
201
201
|
if @d.length==@rep_i+1 && @d[@rep_i]==0 then
|
202
202
|
@rep_i = nil;
|
203
203
|
@d.pop;
|
204
|
-
end
|
204
|
+
end
|
205
205
|
end
|
206
206
|
@d.pop while @d[@d.length-1]==0
|
207
|
-
|
207
|
+
|
208
208
|
self
|
209
209
|
end
|
210
210
|
|
@@ -248,7 +248,7 @@ module Nio
|
|
248
248
|
end
|
249
249
|
|
250
250
|
unless i_str.kind_of?(Symbol)
|
251
|
-
j = 0;
|
251
|
+
j = 0;
|
252
252
|
f_str = ''
|
253
253
|
while i<l
|
254
254
|
ch = str[i,1];
|
@@ -301,9 +301,9 @@ module Nio
|
|
301
301
|
check.setS s+opt.auto_rep, opt;
|
302
302
|
#print " s=",s,"\n"
|
303
303
|
#print " self=",self.to_s,"\n"
|
304
|
-
|
304
|
+
while check!=self
|
305
305
|
for i in @rep_i...@d.length
|
306
|
-
|
306
|
+
s << opt.digits.digit_char(@d[i])
|
307
307
|
end
|
308
308
|
check.setS s+opt.auto_rep, opt;
|
309
309
|
end
|
@@ -311,7 +311,7 @@ module Nio
|
|
311
311
|
s += opt.auto_rep;
|
312
312
|
end
|
313
313
|
else
|
314
|
-
s += opt.end_rep if @rep_i!=nil;
|
314
|
+
s += opt.end_rep if @rep_i!=nil;
|
315
315
|
end
|
316
316
|
return s;
|
317
317
|
end
|
@@ -337,7 +337,7 @@ module Nio
|
|
337
337
|
@d.pop if i==@d.length;
|
338
338
|
end
|
339
339
|
i -= 1;
|
340
|
-
end
|
340
|
+
end
|
341
341
|
@ip += carry;
|
342
342
|
|
343
343
|
end
|
@@ -424,10 +424,10 @@ module Nio
|
|
424
424
|
x *= @radix
|
425
425
|
d,x = x.divmod(y)
|
426
426
|
@d.push d
|
427
|
-
i += 1;
|
427
|
+
i += 1;
|
428
428
|
end
|
429
429
|
end
|
430
|
-
self
|
430
|
+
self
|
431
431
|
end
|
432
432
|
|
433
433
|
def getQ(opt=DEF_OPT)
|
@@ -442,7 +442,7 @@ module Nio
|
|
442
442
|
end if
|
443
443
|
|
444
444
|
|
445
|
-
n = @d.length
|
445
|
+
n = @d.length
|
446
446
|
a = @ip
|
447
447
|
b = a
|
448
448
|
for i in 0...n
|
@@ -463,25 +463,25 @@ module Nio
|
|
463
463
|
d = Nio.gcd(x,y)
|
464
464
|
x /= d
|
465
465
|
y /= d
|
466
|
-
|
466
|
+
|
467
467
|
x = -x if @sign<0
|
468
|
-
|
469
|
-
return x,y;
|
468
|
+
|
469
|
+
return x,y;
|
470
470
|
end
|
471
471
|
|
472
472
|
#protected
|
473
473
|
|
474
474
|
attr_reader :d, :ip, :rep_i, :sign;
|
475
475
|
attr_writer :d, :ip, :rep_i, :sign;
|
476
|
-
|
477
|
-
end
|
478
476
|
|
477
|
+
end
|
478
|
+
|
479
479
|
|
480
480
|
def RepDec.group_digits(digits, opt)
|
481
481
|
if opt.grp_sep!=nil && opt.grp_sep!='' && opt.grp.length>0
|
482
|
-
grouped = ''
|
482
|
+
grouped = ''
|
483
483
|
i = 0
|
484
|
-
while digits.length>0
|
484
|
+
while digits.length>0
|
485
485
|
l = opt.grp[i]
|
486
486
|
l = digits.length if l>digits.length
|
487
487
|
grouped = opt.grp_sep + grouped if grouped.length>0
|
@@ -492,7 +492,7 @@ module Nio
|
|
492
492
|
grouped
|
493
493
|
else
|
494
494
|
digits
|
495
|
-
end
|
495
|
+
end
|
496
496
|
end
|
497
497
|
|
498
498
|
module_function
|
@@ -501,7 +501,7 @@ module Nio
|
|
501
501
|
while b!=0 do
|
502
502
|
a,b = b, a.modulo(b)
|
503
503
|
end
|
504
|
-
return a.abs;
|
504
|
+
return a.abs;
|
505
505
|
end
|
506
506
|
|
507
507
|
end
|
data/lib/nio/rtnlzr.rb
CHANGED
@@ -1,11 +1,6 @@
|
|
1
1
|
# Rationalization of floating point numbers.
|
2
2
|
#--
|
3
|
-
|
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.
|
3
|
+
|
9
4
|
#++
|
10
5
|
#
|
11
6
|
# Author:: Javier Goizueta (mailto:javier@goizueta.info)
|
@@ -27,12 +22,14 @@
|
|
27
22
|
|
28
23
|
require 'nio/tools'
|
29
24
|
|
30
|
-
require '
|
25
|
+
require 'flt/tolerance'
|
31
26
|
|
32
27
|
require 'rational'
|
33
28
|
|
34
29
|
require 'bigdecimal'
|
35
30
|
|
31
|
+
require 'flt'
|
32
|
+
|
36
33
|
|
37
34
|
class Float
|
38
35
|
# Conversion to Rational preserving the exact value of the number.
|
@@ -42,15 +39,15 @@ class Float
|
|
42
39
|
return Rational(0,0) if self.nan?
|
43
40
|
return self<0 ? Rational(-1,0) : Rational(1,0)
|
44
41
|
end
|
45
|
-
|
42
|
+
|
46
43
|
f,e = Math.frexp(self)
|
47
|
-
|
44
|
+
|
48
45
|
if e < Float::MIN_EXP
|
49
46
|
bits = e+Float::MANT_DIG-Float::MIN_EXP
|
50
47
|
else
|
51
|
-
bits = [Float::MANT_DIG,e].max
|
48
|
+
bits = [Float::MANT_DIG,e].max
|
52
49
|
#return Rational(self.to_i,1) if bits<e
|
53
|
-
end
|
50
|
+
end
|
54
51
|
p = Math.ldexp(f,bits)
|
55
52
|
e = bits - e
|
56
53
|
if e<Float::MAX_EXP
|
@@ -78,6 +75,13 @@ class BigDecimal
|
|
78
75
|
end
|
79
76
|
end
|
80
77
|
|
78
|
+
class Flt::Num
|
79
|
+
|
80
|
+
def nio_xr
|
81
|
+
to_r
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
81
85
|
class Integer
|
82
86
|
|
83
87
|
def nio_xr
|
@@ -90,7 +94,7 @@ class Rational
|
|
90
94
|
def nio_xr
|
91
95
|
return self
|
92
96
|
end
|
93
|
-
|
97
|
+
|
94
98
|
# helper method to return both the numerator and denominator
|
95
99
|
def nio_num_den
|
96
100
|
return [numerator,denominator]
|
@@ -99,40 +103,39 @@ end
|
|
99
103
|
|
100
104
|
|
101
105
|
class Float
|
102
|
-
|
103
|
-
|
104
|
-
# in that case, the smallest denominator rational within the
|
105
|
-
# tolerance will be found (which may take a long time for
|
106
|
-
# small tolerances.)
|
107
|
-
# - an integer that defines a maximum value for the denominator.
|
108
|
-
# in which case, the best approximation with that maximum
|
109
|
-
# denominator will be returned.
|
110
|
-
def nio_r(tol = Nio::Tolerance.big_epsilon)
|
106
|
+
|
107
|
+
def nio_r(tol = Flt.Tolerance(:big_epsilon))
|
111
108
|
case tol
|
112
109
|
when Integer
|
113
110
|
Rational(*Nio::Rtnlzr.max_denominator(self,tol,Float))
|
114
111
|
else
|
115
|
-
Rational(*Nio::Rtnlzr.new(
|
112
|
+
Rational(*Nio::Rtnlzr.new(tol).rationalize(self))
|
116
113
|
end
|
117
114
|
end
|
118
115
|
end
|
119
116
|
|
120
117
|
class BigDecimal
|
121
|
-
|
122
|
-
# - a Nio::BigTolerance that defines the admisible tolerance;
|
123
|
-
# in that case, the smallest denominator rational within the
|
124
|
-
# tolerance will be found (which may take a long time for
|
125
|
-
# small tolerances.)
|
126
|
-
# - an integer that defines a maximum value for the denominator.
|
127
|
-
# in which case, the best approximation with that maximum
|
128
|
-
# denominator will be returned.
|
118
|
+
|
129
119
|
def nio_r(tol = nil)
|
130
|
-
tol ||=
|
120
|
+
tol ||= Flt.Tolerance([precs[0],Float::DIG].max,:sig_decimals)
|
131
121
|
case tol
|
132
122
|
when Integer
|
133
123
|
Rational(*Nio::Rtnlzr.max_denominator(self,tol,BigDecimal))
|
134
124
|
else
|
135
|
-
Rational(*Nio::Rtnlzr.new(
|
125
|
+
Rational(*Nio::Rtnlzr.new(tol).rationalize(self))
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
class Flt::Num
|
131
|
+
|
132
|
+
def nio_r(tol = nil)
|
133
|
+
tol ||= Flt.Tolerance(Rational(1,2),:ulps)
|
134
|
+
case tol
|
135
|
+
when Integer
|
136
|
+
Rational(*Nio::Rtnlzr.max_denominator(self,tol,num_class))
|
137
|
+
else
|
138
|
+
Rational(*Nio::Rtnlzr.new(tol).rationalize(self))
|
136
139
|
end
|
137
140
|
end
|
138
141
|
end
|
@@ -140,14 +143,14 @@ end
|
|
140
143
|
module Nio
|
141
144
|
|
142
145
|
|
143
|
-
# This class provides conversion of fractions
|
146
|
+
# This class provides conversion of fractions
|
144
147
|
# (as approximate floating point numbers)
|
145
148
|
# to rational numbers.
|
146
149
|
class Rtnlzr
|
147
150
|
include StateEquivalent
|
148
151
|
|
149
152
|
# Create Rationalizator with given tolerance.
|
150
|
-
def initialize(tol=Tolerance
|
153
|
+
def initialize(tol=Flt.Tolerance(:epsilon))
|
151
154
|
@tol = tol
|
152
155
|
end
|
153
156
|
|
@@ -159,8 +162,8 @@ module Nio
|
|
159
162
|
def rationalize(x)
|
160
163
|
rationalize_Knuth(x)
|
161
164
|
end
|
162
|
-
|
163
|
-
# This algorithm is derived from exercise 39 of 4.5.3 in
|
165
|
+
|
166
|
+
# This algorithm is derived from exercise 39 of 4.5.3 in
|
164
167
|
# "The Art of Computer Programming", by Donald E. Knuth.
|
165
168
|
def rationalize_Knuth(x)
|
166
169
|
|
@@ -175,14 +178,14 @@ module Nio
|
|
175
178
|
negans = true
|
176
179
|
x = -x
|
177
180
|
end
|
178
|
-
dx = num_tol ? @tol : @tol.
|
179
|
-
|
181
|
+
dx = num_tol ? @tol : @tol.value(x)
|
182
|
+
|
180
183
|
|
181
184
|
x = x.nio_xr
|
182
185
|
dx = dx.nio_xr
|
183
186
|
xp,xq = (x-dx).nio_num_den
|
184
187
|
yp,yq = (x+dx).nio_num_den
|
185
|
-
|
188
|
+
|
186
189
|
a = []
|
187
190
|
fin,odd = false,false
|
188
191
|
while !fin && xp!=0 && yp!=0
|
@@ -205,13 +208,13 @@ module Nio
|
|
205
208
|
p,q = 1,0
|
206
209
|
(1..a.size).each{|i| p,q=q+p*a[-i],p}
|
207
210
|
num,den = q,p
|
208
|
-
|
209
211
|
|
212
|
+
|
210
213
|
num = -num if negans
|
211
214
|
end
|
212
215
|
return num,den
|
213
216
|
|
214
|
-
|
217
|
+
|
215
218
|
end
|
216
219
|
# This is algorithm PDQ2 by Joe Horn.
|
217
220
|
def rationalize_Horn(x)
|
@@ -227,8 +230,8 @@ module Nio
|
|
227
230
|
negans = true
|
228
231
|
x = -x
|
229
232
|
end
|
230
|
-
dx = num_tol ? @tol : @tol.
|
231
|
-
|
233
|
+
dx = num_tol ? @tol : @tol.value(x)
|
234
|
+
|
232
235
|
|
233
236
|
z,t = x,dx # renaming
|
234
237
|
|
@@ -257,19 +260,19 @@ module Nio
|
|
257
260
|
else
|
258
261
|
hi = mid
|
259
262
|
end
|
260
|
-
end until hi-lo <= 1
|
263
|
+
end until hi-lo <= 1
|
261
264
|
x = cn - pn*lo
|
262
|
-
y = cd - pd*lo
|
263
|
-
end
|
264
|
-
|
265
|
+
y = cd - pd*lo
|
266
|
+
end
|
267
|
+
|
265
268
|
num,den = x,y # renaming
|
266
|
-
|
267
269
|
|
270
|
+
|
268
271
|
num = -num if negans
|
269
272
|
end
|
270
273
|
return num,den
|
271
274
|
|
272
|
-
|
275
|
+
|
273
276
|
end
|
274
277
|
# This is from a RPL program by Tony Hutchins (PDR6).
|
275
278
|
def rationalize_HornHutchins(x)
|
@@ -285,8 +288,8 @@ module Nio
|
|
285
288
|
negans = true
|
286
289
|
x = -x
|
287
290
|
end
|
288
|
-
dx = num_tol ? @tol : @tol.
|
289
|
-
|
291
|
+
dx = num_tol ? @tol : @tol.value(x)
|
292
|
+
|
290
293
|
|
291
294
|
z,t = x,dx # renaming
|
292
295
|
|
@@ -315,19 +318,19 @@ module Nio
|
|
315
318
|
else
|
316
319
|
hi = mid
|
317
320
|
end
|
318
|
-
end until hi-lo <= 1
|
321
|
+
end until hi-lo <= 1
|
319
322
|
x = cn - pn*lo
|
320
|
-
y = cd - pd*lo
|
321
|
-
end
|
322
|
-
|
323
|
+
y = cd - pd*lo
|
324
|
+
end
|
325
|
+
|
323
326
|
num,den = x,y # renaming
|
324
|
-
|
325
327
|
|
328
|
+
|
326
329
|
num = -num if negans
|
327
330
|
end
|
328
331
|
return num,den
|
329
332
|
|
330
|
-
|
333
|
+
|
331
334
|
end
|
332
335
|
end
|
333
336
|
|
@@ -340,33 +343,36 @@ module Nio
|
|
340
343
|
def Rtnlzr.max_denominator(f, max_den=1000000000, num_class=nil)
|
341
344
|
return nil if max_den<1
|
342
345
|
num_class ||= f.class
|
346
|
+
context = num_class.context
|
343
347
|
return mth.ip(f),1 if mth.fp(f)==0
|
344
348
|
|
345
|
-
|
346
|
-
|
347
|
-
sign = f<0
|
348
|
-
f = -f if sign
|
349
|
+
cast = lambda{|x| context.Num(x)}
|
349
350
|
|
350
|
-
|
351
|
-
while b<max_den and c!=0
|
352
|
-
cc = one/c
|
353
|
-
a,b,c = b, mth.ip(cc)*b+a, mth.fp(cc)
|
354
|
-
end
|
351
|
+
one = cast.call(1)
|
355
352
|
|
356
|
-
|
357
|
-
|
358
|
-
b -= a*mth.ceil((b-max_den)/Float(a))
|
359
|
-
end
|
360
|
-
|
353
|
+
sign = f<0
|
354
|
+
f = -f if sign
|
361
355
|
|
362
|
-
|
356
|
+
a,b,c = 0,1,f
|
357
|
+
while b<max_den and c!=0
|
358
|
+
cc = one/c
|
359
|
+
a,b,c = b, mth.ip(cc)*b+a, mth.fp(cc)
|
360
|
+
end
|
363
361
|
|
364
|
-
a = f1>f2 ? b : a
|
365
362
|
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
363
|
+
if b>max_den
|
364
|
+
b -= a*mth.ceil(cast.call(b-max_den)/a)
|
365
|
+
end
|
366
|
+
|
367
|
+
|
368
|
+
f1,f2 = [a,b].collect{|x| mth.abs(cast.call(mth.rnd(x*f))/x-f)}
|
369
|
+
|
370
|
+
a = f1>f2 ? b : a
|
371
|
+
|
372
|
+
num,den = mth.rnd(a*f).to_i,a
|
373
|
+
den = 1 if mth.abs(den)<1
|
374
|
+
|
375
|
+
num = -num if sign
|
370
376
|
|
371
377
|
return num,den
|
372
378
|
end
|
@@ -381,13 +387,13 @@ module Nio
|
|
381
387
|
end
|
382
388
|
|
383
389
|
def self.ip(x)
|
384
|
-
#
|
390
|
+
# Note that ceil, floor return an Integer for Float and Flt::Num, but not for BigDecimal
|
385
391
|
(x<0 ? x.ceil : x.floor).to_i
|
386
392
|
end
|
387
393
|
|
388
394
|
def self.rnd(x)
|
389
|
-
#
|
390
|
-
x.round
|
395
|
+
# Note that round returns an Integer for Float and Flt::Num, but not for BigDecimal
|
396
|
+
x.round.to_i
|
391
397
|
end
|
392
398
|
|
393
399
|
def self.abs(x)
|
@@ -395,8 +401,9 @@ module Nio
|
|
395
401
|
end
|
396
402
|
|
397
403
|
def self.ceil(x)
|
404
|
+
# Note that ceil returns an Integer for Float and Flt::Num, but not for BigDecimal
|
398
405
|
x.ceil.to_i
|
399
|
-
end
|
406
|
+
end
|
400
407
|
end
|
401
408
|
def self.mth; Mth; end
|
402
409
|
end
|