nio 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -15,6 +15,7 @@ require File.join(File.dirname(__FILE__),'source/lib/nio/version')
15
15
 
16
16
  task :default => 'spec:run'
17
17
 
18
+ depend_on 'flt', '1.0.0'
18
19
 
19
20
  PROJ.name = 'nio'
20
21
  PROJ.description = "Numeric input/output"
data/lib/nio.rb CHANGED
@@ -1,8 +1,7 @@
1
1
  $:.unshift File.dirname(__FILE__)
2
-
3
- require 'nio/version'
4
- require 'nio/tools'
5
- require 'nio/flttol'
6
- require 'nio/repdec'
7
- require 'nio/rtnlzr'
8
- require 'nio/fmt'
2
+
3
+ require 'nio/version'
4
+ require 'nio/tools'
5
+ require 'nio/repdec'
6
+ require 'nio/rtnlzr'
7
+ require 'nio/fmt'
@@ -18,10 +18,12 @@ require 'rational'
18
18
 
19
19
  require 'bigdecimal'
20
20
 
21
+ require 'flt'
22
+
21
23
  module Nio
22
24
 
23
25
  # positional notation, unformatted numeric literal: used as intermediate form
24
- class NeutralNum
26
+ class NeutralNum
25
27
  include StateEquivalent
26
28
  def initialize(s='',d='',p=nil,r=nil,dgs=DigitsDef.base(10), inexact=false, round=:inf)
27
29
  set s,d,p,r,dgs,dgs, inexact, round
@@ -40,7 +42,7 @@ module Nio
40
42
  @inexact = inexact
41
43
  @special = nil
42
44
  @rounding = rounding
43
- trimZeros unless inexact
45
+ trimZeros unless inexact
44
46
  self
45
47
  end
46
48
  # set infinite (:inf) and invalid (:nan) numbers
@@ -84,7 +86,7 @@ module Nio
84
86
  # in Ruby 1.6.8 Float,BigNum,Fixnum doesn't respond to dup
85
87
  n.set @sign.dup, @digits.dup, @dec_pos, @rep_pos, @dgs.dup, @inexact, @rounding
86
88
  end
87
- return n
89
+ return n
88
90
  end
89
91
 
90
92
  def zero?
@@ -119,7 +121,8 @@ module Nio
119
121
  adj = 0
120
122
  dv = :tie
121
123
  if @inexact && n==@digits.size
122
- dv = @inexact==:roundup ? :hi : :lo
124
+ # TODO: the combination of the value true with the values of Formatter#round_up makes this ugly
125
+ dv = @inexact.is_a?(Symbol) ? @inexact : :lo
123
126
  else
124
127
  v = dig_value(n)
125
128
  v2 = 2*v
@@ -128,15 +131,19 @@ module Nio
128
131
  elsif v2 > @base # v>(@base/2)
129
132
  dv = :hi
130
133
  else
131
-
132
- (n+1...@digits.length).each do |i|
133
- if dig_value(i)>0
134
- dv = :hi
135
- break
136
- end
137
- end
138
-
139
- dv = :hi if dv==:tie && @rep_pos<=n
134
+ if @inexact
135
+ dv = :hi
136
+ else
137
+
138
+ (n+1...@digits.length).each do |i|
139
+ if dig_value(i)>0
140
+ dv = :hi
141
+ break
142
+ end
143
+ end
144
+
145
+ end
146
+ dv = :hi if dv==:tie && @rep_pos<=n
140
147
  end
141
148
  end
142
149
 
@@ -149,10 +156,10 @@ module Nio
149
156
  adj = +1 if (dig_value(n-1)%2)!=0
150
157
  elsif dir==:zero # towards zero
151
158
  adj=0
152
- # elsif dir==:odd
159
+ # elsif dir==:odd
153
160
  # adj = +1 unless (dig_value(n-1)%2)!=0
154
161
  end
155
- end
162
+ end
156
163
 
157
164
  if n>@digits.length
158
165
  (@digits.length...n).each do |i|
@@ -175,17 +182,17 @@ module Nio
175
182
  adj = +1
176
183
  end
177
184
  if i<0
178
- prefix = dig_char(v)+prefix
185
+ prefix = dig_char(v)+prefix
179
186
  elsif i<@digits.length
180
187
  @digits[i] = dig_char(v)
181
188
  end
182
189
  i += -1
183
- end
190
+ end
184
191
 
185
192
  if n<0
186
- @digits = ""
193
+ @digits = ""
187
194
  else
188
- @digits = @digits[0...n]
195
+ @digits = @digits[0...n]
189
196
  end
190
197
  @rep_pos = @digits.length
191
198
 
@@ -205,10 +212,10 @@ module Nio
205
212
  return nn
206
213
  end
207
214
 
208
- def trimTrailZeros()
215
+ def trimTrailZeros()
209
216
  i = @digits.length
210
217
  while i>0 && dig_value(i-1)==0
211
- i -= 1
218
+ i -= 1
212
219
  end
213
220
  if @rep_pos>=i
214
221
  @digits = @digits[0...i]
@@ -240,7 +247,7 @@ module Nio
240
247
 
241
248
  end
242
249
 
243
- def trimZeros()
250
+ def trimZeros()
244
251
  trimLeadZeros
245
252
  trimTrailZeros
246
253
  end
@@ -249,11 +256,11 @@ module Nio
249
256
 
250
257
  def dig_value(i)
251
258
  v = 0
252
- if i>=@rep_pos
259
+ if i>=@rep_pos
253
260
  i -= @digits.length
254
261
  i %= @digits.length - @rep_pos if @rep_pos<@digits.length
255
262
  i += @rep_pos
256
- end
263
+ end
257
264
  if i>=0 && i<@digits.length
258
265
  v = @dgs.digit_value(@digits[i]) #digcode_value(@digits[i])
259
266
  end
@@ -302,8 +309,8 @@ module Nio
302
309
  n.ip = 0
303
310
  n.d = text_to_digits(dig_char(0)*(-dec_pos) + digits)
304
311
  elsif dec_pos >= digits.length
305
- n.ip = digits.to_i(@base)
306
- if rep_pos<dec_pos
312
+ n.ip = digits.to_i(@base)
313
+ if rep_pos<dec_pos
307
314
  i=0
308
315
  (dec_pos-digits.length).times do
309
316
  n.ip *= @base
@@ -326,22 +333,22 @@ module Nio
326
333
  else
327
334
  n.ip = digits[0...dec_pos].to_i(@base)
328
335
  n.d = text_to_digits(digits[dec_pos..-1])
329
- if rep_pos<dec_pos
336
+ if rep_pos<dec_pos
330
337
  new_rep_pos = n.d.size + dec_pos
331
338
  n.d += text_to_digits(digits[rep_pos..-1])
332
339
  self.rep_pos = new_rep_pos
333
340
  puts "--rep_pos=#{rep_pos}"
334
- end
341
+ end
335
342
  end
336
343
  n.sign = -1 if sign=='-'
337
- n.rep_i = rep_pos - dec_pos
344
+ n.rep_i = rep_pos - dec_pos
338
345
  end
339
346
  n.normalize!(!inexact) # keep trailing zeros for inexact numbers
340
347
  return n
341
348
  end
342
349
  protected
343
350
  def text_to_digits(txt)
344
- #txt.split('').collect{|c| @dgs.digit_value(c)}
351
+ #txt.split('').collect{|c| @dgs.digit_value(c)}
345
352
  ds = []
346
353
  txt.each_byte{|b| ds << @dgs.digit_value(b)}
347
354
  ds
@@ -364,7 +371,7 @@ module Nio
364
371
  else
365
372
  num = nil
366
373
  end
367
-
374
+
368
375
  else
369
376
  base_dgs ||= DigitsDef.base(@radix)
370
377
  # assert base_dgs.radix == @radix
@@ -376,7 +383,7 @@ module Nio
376
383
  num.set signch, decimals, dec_pos, rep_pos, base_dgs
377
384
  end
378
385
  return num
379
- end
386
+ end
380
387
  end
381
388
 
382
389
  # A Fmt object defines a numeric format.
@@ -392,7 +399,7 @@ module Nio
392
399
  # - #width() and the shortcut #pad0s()
393
400
  # * numerical base
394
401
  # - #base()
395
- # * repeating numerals
402
+ # * repeating numerals
396
403
  # - #rep()
397
404
  #
398
405
  # Note that for every aspect there are also corresponding _mutator_
@@ -461,12 +468,12 @@ module Nio
461
468
  @nan_txt = 'NAN'
462
469
  @inf_txt = 'Infinity'
463
470
 
464
- yield self if block_given?
471
+ yield self if block_given?
465
472
  end
466
473
 
467
474
  # Defines the separators used in numerals. This is relevant to
468
- # both input and output.
469
- #
475
+ # both input and output.
476
+ #
470
477
  # The first argument is the radix point separator (usually
471
478
  # a point or a comma; by default it is a point.)
472
479
  #
@@ -495,12 +502,12 @@ module Nio
495
502
  set! :grp_sep=>grp_sep, :grp=>grp
496
503
  end
497
504
 
498
- # This is a shortcut to return a new default Fmt object
505
+ # This is a shortcut to return a new default Fmt object
499
506
  # and define the separators as with #sep().
500
507
  def Fmt.sep(dec_sep,grp_sep=nil,grp=nil)
501
508
  Fmt.default.sep(dec_sep,grp_sep,grp)
502
509
  end
503
- # This is a shortcut to return a new default Fmt object
510
+ # This is a shortcut to return a new default Fmt object
504
511
  # and define the grouping as with #grouping().
505
512
  def Fmt.grouping(grp=[3],grp_sep=nil)
506
513
  Fmt.default.grouping(grp,grp_sep)
@@ -526,10 +533,10 @@ module Nio
526
533
  # - <tt>:round</tt> rounding mode applied to conversions
527
534
  # (this is relevant for both input and output). It must be one of:
528
535
  # [<tt>:inf</tt>]
529
- # rounds to nearest with ties toward infinite;
536
+ # rounds to nearest with ties toward infinite;
530
537
  # 1.5 is rounded to 2, -1.5 to -2
531
538
  # [<tt>:zero</tt>]
532
- # rounds to nearest with ties toward zero;
539
+ # rounds to nearest with ties toward zero;
533
540
  # 1.5 is rounded to 1, -1.5 to 2
534
541
  # [<tt>:even</tt>]
535
542
  # rounds to the nearest with ties toward an even digit;
@@ -544,7 +551,7 @@ module Nio
544
551
  # significant and insignificant digits.
545
552
  # [<tt>:simplify</tt>]
546
553
  # the value is simplified, if possible to a simpler (rational) value.
547
- # - <tt>:show_all_digits</tt> if true, this forces to show digits that
554
+ # - <tt>:show_all_digits</tt> if true, this forces to show digits that
548
555
  # would otherwise not be shown in the <tt>:gen</tt> format: trailing
549
556
  # zeros of exact types or non-signficative digits of inexact types.
550
557
  # - <tt>:nonsignficative_digits</tt> assigns a character to display
@@ -562,18 +569,18 @@ module Nio
562
569
  # to change the precision only. Refer to #mode().
563
570
  def prec(precision,mode=nil, options={})
564
571
  dup.prec! precision, mode, options
565
- end
572
+ end
566
573
  # This is the mutator version of #prec().
567
574
  def prec!(precision,mode=:gen, options={})
568
575
  set! options.merge(:mode=>mode, :ndig=>precision)
569
576
  end
570
577
 
571
- # This is a shortcut to return a new default Fmt object
578
+ # This is a shortcut to return a new default Fmt object
572
579
  # and define the formatting mode as with #mode()
573
580
  def Fmt.mode(mode,ndig=nil,options={})
574
581
  Fmt.default.mode(mode,ndig,options)
575
582
  end
576
- # This is a shortcut to return a new default Fmt object
583
+ # This is a shortcut to return a new default Fmt object
577
584
  # and define the formatting mode as with #prec()
578
585
  def Fmt.prec(ndig,mode=nil,options={})
579
586
  Fmt.default.prec(ndig,mode,options)
@@ -592,7 +599,7 @@ module Nio
592
599
 
593
600
  # This controls the display of the digits that are not necessary
594
601
  # to specify the value unambiguosly (e.g. trailing zeros).
595
- #
602
+ #
596
603
  # The true (default) value forces the display of the requested number of digits
597
604
  # and false will display only necessary digits.
598
605
  def show_all_digits(ad=true)
@@ -640,22 +647,22 @@ module Nio
640
647
  set! :sci_format=>n
641
648
  end
642
649
 
643
- # This is a shortcut to return a new default Fmt object
650
+ # This is a shortcut to return a new default Fmt object
644
651
  # and define show_all_digits
645
652
  def Fmt.show_all_digits(v=true)
646
653
  Fmt.default.show_all_digits(v)
647
654
  end
648
- # This is a shortcut to return a new default Fmt object
655
+ # This is a shortcut to return a new default Fmt object
649
656
  # and define approx_mode
650
657
  def Fmt.approx_mode(v)
651
658
  Fmt.default.approx_mode(v)
652
659
  end
653
- # This is a shortcut to return a new default Fmt object
660
+ # This is a shortcut to return a new default Fmt object
654
661
  # and define insignificant digits
655
662
  def Fmt.insignificant_digits(v='#')
656
663
  Fmt.default.insignificant_digits(v)
657
664
  end
658
- # This is a shortcut to return a new default Fmt object
665
+ # This is a shortcut to return a new default Fmt object
659
666
  # and define sci_digits
660
667
  def Fmt.sci_digits(v=-1)
661
668
  Fmt.default.sci_digits(v)
@@ -683,12 +690,12 @@ module Nio
683
690
  self
684
691
  end
685
692
 
686
- # This is a shortcut to return a new default Fmt object
693
+ # This is a shortcut to return a new default Fmt object
687
694
  # and define show_plus
688
695
  def Fmt.show_plus(v=true)
689
696
  Fmt.default.show_plus(v)
690
697
  end
691
- # This is a shortcut to return a new default Fmt object
698
+ # This is a shortcut to return a new default Fmt object
692
699
  # and define show_exp_plus
693
700
  def Fmt.show_exp_plus(v=true)
694
701
  Fmt.default.show_exp_plus(v)
@@ -701,7 +708,7 @@ module Nio
701
708
  # [<tt>:suffix</tt>] is the suffix used to indicate a implicit repeating decimal
702
709
  # [<tt>:rep</tt>]
703
710
  # if this parameter is greater than zero, on output the repeating section
704
- # is repeated the indicated number of times followed by the suffix;
711
+ # is repeated the indicated number of times followed by the suffix;
705
712
  # otherwise the delimited notation is used.
706
713
  # [<tt>:read</tt>]
707
714
  # (true/false) determines if repeating decimals are
@@ -710,20 +717,20 @@ module Nio
710
717
  dup.rep!(*params)
711
718
  end
712
719
  # This is the mutator version of #rep().
713
- def rep!(*params)
720
+ def rep!(*params)
714
721
 
715
722
  params << {} if params.size==0
716
723
  if params[0].kind_of?(Hash)
717
724
  params = params[0]
718
- else
719
- begch,endch,autoch,rep,read = *params
725
+ else
726
+ begch,endch,autoch,rep,read = *params
720
727
  params = {:begin=>begch,:end=>endch,:suffix=>autoch,:nreps=>rep,:read=>read}
721
728
  end
722
729
 
723
730
  set! params
724
731
  end
725
732
 
726
- # This is a shortcut to return a new default Fmt object
733
+ # This is a shortcut to return a new default Fmt object
727
734
  # and define the repeating decimals mode as with #rep()
728
735
  def Fmt.rep(*params)
729
736
  Fmt.default.rep(*params)
@@ -822,7 +829,7 @@ module Nio
822
829
 
823
830
  # Method used internally to format a neutral numeral
824
831
  def nio_write_formatted(neutral) # :nodoc:
825
- str = ''
832
+ str = ''
826
833
  if neutral.special?
827
834
  str << neutral.sign
828
835
  case neutral.special
@@ -830,9 +837,9 @@ module Nio
830
837
  str << @inf_txt
831
838
  when :nan
832
839
  str << @nan_txt
833
- end
840
+ end
834
841
  else
835
- zero = get_base_digits(neutral.base).digit_char(0).chr
842
+ zero = get_base_digits(neutral.base).digit_char(0).chr
836
843
  neutral = neutral.dup
837
844
  round! neutral
838
845
  if neutral.zero?
@@ -861,7 +868,7 @@ module Nio
861
868
  end
862
869
  end
863
870
  exp = neutral.dec_pos - integral_digits
864
-
871
+
865
872
  case actual_mode
866
873
  when :gen # general (automatic)
867
874
  # @ndig means significant digits
@@ -870,7 +877,7 @@ module Nio
870
877
  trim_trail_zeros = !@all_digits # true
871
878
  end
872
879
 
873
- case actual_mode
880
+ case actual_mode
874
881
  when :fix, :sig #, :gen
875
882
 
876
883
 
@@ -903,7 +910,7 @@ module Nio
903
910
  digits = neutral.digits + ns_digits
904
911
  if neutral.dec_pos<=0
905
912
  str << zero+@dec_sep+zero*(-neutral.dec_pos) + digits
906
- elsif neutral.dec_pos >= digits.length
913
+ elsif neutral.dec_pos >= digits.length
907
914
  str << group(digits + zero*(neutral.dec_pos-digits.length))
908
915
  else
909
916
  str << group(digits[0...neutral.dec_pos]) + @dec_sep + digits[neutral.dec_pos..-1]
@@ -917,7 +924,7 @@ module Nio
917
924
  #puts str
918
925
  end
919
926
 
920
-
927
+
921
928
  when :sci
922
929
 
923
930
 
@@ -935,7 +942,7 @@ module Nio
935
942
  if @ndig==:exact
936
943
  neutral.sign = '+'
937
944
  neutral.dec_pos-=exp
938
- str << neutral.to_RepDec.getS(@rep_n, getRepDecOpt(neutral.base))
945
+ str << neutral.to_RepDec.getS(@rep_n, getRepDecOpt(neutral.base))
939
946
  else
940
947
  ns_digits = ''
941
948
 
@@ -951,7 +958,7 @@ module Nio
951
958
  str << ((integral_digits<1) ? zero : digits[0...integral_digits])
952
959
  str << @dec_sep
953
960
  str << digits[integral_digits...@ndig]
954
- pad_right =(@ndig+1-str.length)
961
+ pad_right =(@ndig+1-str.length)
955
962
  str << zero*pad_right if pad_right>0 && !neutral.inexact? # maybe we didn't have enought digits
956
963
  end
957
964
 
@@ -967,7 +974,7 @@ module Nio
967
974
  str << (exp<0 ? (@minus_symbol || '-') : (@plus_symbol || '+'))
968
975
  end
969
976
  str << exp.abs.to_s
970
-
977
+
971
978
  end
972
979
 
973
980
  end
@@ -985,7 +992,7 @@ module Nio
985
992
  case @adjust
986
993
  when :internal
987
994
  sign = ''
988
- if str[0,1]=='+' || str[0,1]=='-'
995
+ if str[0,1]=='+' || str[0,1]=='-'
989
996
  sign = str[0,1]
990
997
  str = str[1...str.length]
991
998
  end
@@ -997,7 +1004,7 @@ module Nio
997
1004
  when :left
998
1005
  str = str + @fill_char*l
999
1006
  end
1000
- end
1007
+ end
1001
1008
  end
1002
1009
 
1003
1010
  return str
@@ -1013,14 +1020,14 @@ module Nio
1013
1020
  def nio_read_formatted(txt) # :nodoc:
1014
1021
  txt = txt.dup
1015
1022
  num = nil
1016
-
1023
+
1017
1024
  base = nil
1018
1025
 
1019
1026
  base ||= get_base
1020
-
1021
- zero = get_base_digits(base).digit_char(0).chr
1022
- txt.tr!(@non_sig,zero) # we don't simply remove it because it may be before the radix point
1023
-
1027
+
1028
+ zero = get_base_digits(base).digit_char(0).chr
1029
+ txt.tr!(@non_sig,zero) # we don't simply remove it because it may be before the radix point
1030
+
1024
1031
  exp = 0
1025
1032
  x_char = get_exp_char(base)
1026
1033
 
@@ -1028,8 +1035,8 @@ module Nio
1028
1035
  exp_i = txt.index(x_char.downcase) if exp_i===nil
1029
1036
  if exp_i!=nil
1030
1037
  exp = txt[exp_i+1...txt.length].to_i
1031
- txt = txt[0...exp_i]
1032
- end
1038
+ txt = txt[0...exp_i]
1039
+ end
1033
1040
 
1034
1041
 
1035
1042
  opt = getRepDecOpt(base)
@@ -1051,7 +1058,7 @@ module Nio
1051
1058
  return num
1052
1059
  end
1053
1060
 
1054
-
1061
+
1055
1062
  @@fmts = {
1056
1063
  :def=>Fmt.new.freeze
1057
1064
  }
@@ -1076,7 +1083,7 @@ module Nio
1076
1083
  def self.[](tag)
1077
1084
  @@fmts[tag.to_sym]
1078
1085
  end
1079
-
1086
+
1080
1087
  protected
1081
1088
 
1082
1089
  @@valid_properties = nil
@@ -1097,7 +1104,7 @@ module Nio
1097
1104
 
1098
1105
  @@valid_properties ||= instance_variables.collect{|v| v[1..-1].to_sym}
1099
1106
 
1100
-
1107
+
1101
1108
  properties.each do |k,v|
1102
1109
  al = ALIAS_PROPERTIES[k]
1103
1110
  if al
@@ -1107,16 +1114,16 @@ module Nio
1107
1114
  raise InvalidOption, "Invalid option: #{k}"
1108
1115
  end
1109
1116
  end
1110
-
1117
+
1111
1118
 
1112
- if properties[:grp_sep].nil? && !properties[:dec_sep].nil? && properties[:dec_sep]!=@dec_sep && properties[:dec_sep]==@grp_sep
1113
- properties[:grp_sep] = properties[:dec_sep]=='.' ? ',' : '.'
1119
+ if properties[:grp_sep].nil? && !properties[:dec_sep].nil? && properties[:dec_sep]!=@dec_sep && properties[:dec_sep]==@grp_sep
1120
+ properties[:grp_sep] = properties[:dec_sep]=='.' ? ',' : '.'
1114
1121
  end
1115
1122
 
1116
1123
  if properties[:all_digits].nil? && (properties[:ndig] || properties[:mode])
1117
1124
  ndig = properties[:ndig] || @ndig
1118
1125
  mode = properties[:mode] || @mode
1119
- properties[:all_digits] = ndig!=:exact && mode!=:gen
1126
+ properties[:all_digits] = ndig!=:exact && mode!=:gen
1120
1127
  end
1121
1128
 
1122
1129
  if !properties[:all_digits].nil? && properties[:non_sig].nil?
@@ -1131,12 +1138,12 @@ module Nio
1131
1138
  properties[:base_digits] = DigitsDef.base(base, !uppercase)
1132
1139
  end
1133
1140
 
1134
-
1141
+
1135
1142
  properties.each do |k,v|
1136
1143
  instance_variable_set "@#{k}", v unless v.nil?
1137
1144
  end
1138
-
1139
- self
1145
+
1146
+ self
1140
1147
  end
1141
1148
 
1142
1149
  def set(properties={}) # :nodoc:
@@ -1149,7 +1156,7 @@ module Nio
1149
1156
  puts " #{nd} ndpos=#{neutral.dec_pos} ndlen=#{neutral.digits.length}"
1150
1157
  neutral.dec_pos>nd || ([neutral.digits.length,nd].min-neutral.dec_pos)>nd
1151
1158
  else
1152
- exp<-4 || exp>=nd
1159
+ exp<-4 || exp>=nd
1153
1160
  end
1154
1161
  end
1155
1162
 
@@ -1162,7 +1169,7 @@ module Nio
1162
1169
  rd_opt.grp_sep = @grp_sep
1163
1170
  rd_opt.grp = @grp
1164
1171
  rd_opt.inf_txt = @inf_txt
1165
- rd_opt.nan_txt = @nan_txt
1172
+ rd_opt.nan_txt = @nan_txt
1166
1173
  rd_opt.set_digits(get_base_digits(base))
1167
1174
  # if base && (base != get_base_digits.radix)
1168
1175
  # rd_opt.set_digits(get_base_digits(base))
@@ -1197,11 +1204,11 @@ module Nio
1197
1204
 
1198
1205
  module ClassMethods
1199
1206
  # This is the method available in all formattable clases
1200
- # to read a formatted value from a text string into
1207
+ # to read a formatted value from a text string into
1201
1208
  # a value the class, according to the optional format passed.
1202
1209
  def nio_read(txt,fmt=Fmt.default)
1203
1210
  neutral = fmt.nio_read_formatted(txt)
1204
- nio_read_neutral neutral
1211
+ nio_read_neutral neutral
1205
1212
  end
1206
1213
  end
1207
1214
 
@@ -1210,14 +1217,14 @@ module Nio
1210
1217
  def nio_round(fmt=Fmt.default)
1211
1218
  neutral = nio_write_neutral(fmt)
1212
1219
  fmt.round! neutral
1213
- self.class.nio_read_neutral neutral
1220
+ self.class.nio_read_neutral neutral
1214
1221
  end
1215
1222
 
1216
1223
  def self.append_features(mod) # :nodoc:
1217
1224
  super
1218
1225
  mod.extend ClassMethods
1219
1226
  end
1220
-
1227
+
1221
1228
  end
1222
1229
 
1223
1230
  Fmt[:comma] = Fmt.sep(',','.')
@@ -1262,283 +1269,21 @@ module Nio
1262
1269
 
1263
1270
  def nio_float_to_bigdecimal(x,prec) # :nodoc:
1264
1271
  if prec.nil?
1265
- x = Fmt.convert(x,BigDecimal,:approx)
1272
+ x = Fmt.convert(x,BigDecimal,:approx)
1266
1273
  elsif prec==:exact
1267
- x = Fmt.convert(x,BigDecimal,:exact)
1274
+ x = Fmt.convert(x,BigDecimal,:exact)
1268
1275
  else
1269
1276
  x = BigDecimal(x.nio_write(Nio::Fmt.new.prec(prec,:sig)))
1270
1277
  end
1271
1278
  x
1272
1279
  end
1273
-
1274
-
1275
- module Clinger # :nodoc: all
1276
- module_function
1277
-
1278
- def algM(f,e,round_mode,eb=10,beta=Float::RADIX,n=Float::MANT_DIG,min_e=Float::MIN_EXP-Float::MANT_DIG,max_e=Float::MAX_EXP-Float::MANT_DIG)
1279
-
1280
- if e<0
1281
- u,v,k = f,eb**(-e),0
1282
- else
1283
- u,v,k = f*(eb**e),1,0
1284
- end
1285
-
1286
- loop do
1287
- x = u.div(v)
1288
- # overflow if k>=max_e
1289
- if (x>=beta**(n-1) && x<beta**n) || k==min_e || k==max_e
1290
- return ratio_float(u,v,k,round_mode,beta,n)
1291
- elsif x<beta**(n-1)
1292
- u *= beta
1293
- k -= 1
1294
- elsif x>=beta**n
1295
- v *= beta
1296
- k += 1
1297
- end
1298
- end
1299
-
1300
- end
1301
-
1302
- def ratio_float(u,v,k,round_mode,beta=Float::RADIX,n=Float::MANT_DIG)
1303
- q,r = u.divmod(v)
1304
- v_r = v-r
1305
- z = Math.ldexp(q,k)
1306
- if r<v_r
1307
- z
1308
- elsif r>v_r
1309
- nextfloat z
1310
- elsif (round_mode==:even && q.even?) || (round_mode==:zero)
1311
- z
1312
- else
1313
- nextfloat z
1314
- end
1315
- end
1316
-
1317
- # valid only for non-negative x
1318
- def nextfloat(x)
1319
- f,e = Math.frexp(x)
1320
- e = Float::MIN_EXP if f==0
1321
- e = [Float::MIN_EXP,e].max
1322
- dx = Math.ldexp(1,e-Float::MANT_DIG) #Math.ldexp(Math.ldexp(1.0,-Float::MANT_DIG),e)
1323
- if f==(1.0 - Math.ldexp(1,-Float::MANT_DIG))
1324
- x + dx*2
1325
- else
1326
- x + dx
1327
- end
1328
- end
1329
-
1330
- # valid only for non-negative x
1331
- def prevfloat(x)
1332
- f,e = Math.frexp(x)
1333
- e = Float::MIN_EXP if f==0
1334
- e = [Float::MIN_EXP,e].max
1335
- dx = Math.ldexp(1,e-Float::MANT_DIG) #Math.ldexp(Math.ldexp(1.0,-Float::MANT_DIG),e)
1336
- if e==Float::MIN_EXP || f!=0.5 #0.5==Math.ldexp(2**(bits-1),-Float::MANT_DIG)
1337
- x - dx
1338
- else
1339
- x - dx/2 # x - Math.ldexp(Math.ldexp(1.0,-Float::MANT_DIG),e-1)
1340
- end
1341
- end
1342
-
1343
- end
1344
-
1345
- module BurgerDybvig # :nodoc: all
1346
- module_function
1347
-
1348
- def float_to_digits(v,f,e,round_mode,min_e,p,b,_B)
1349
-
1350
- case round_mode
1351
- when :even
1352
- roundl = roundh = f.even?
1353
- when :inf
1354
- roundl = true
1355
- roundh = false
1356
- when :zero
1357
- roundl = false
1358
- roundh = true
1359
- else
1360
- # here we don't assume any rounding in the floating point numbers
1361
- # the result is valid for any rounding but may produce more digits
1362
- # than stricly necessary for specifica rounding modes.
1363
- roundl = false
1364
- roundh = false
1365
- end
1366
-
1367
- if e >= 0
1368
- if f != exptt(b,p-1)
1369
- be = exptt(b,e)
1370
- r,s,m_p,m_m,k = scale(f*be*2,2,be,be,0,_B,roundl ,roundh,v)
1371
- else
1372
- be = exptt(b,e)
1373
- be1 = be*b
1374
- r,s,m_p,m_m,k = scale(f*be1*2,b*2,be1,be,0,_B,roundl ,roundh,v)
1375
- end
1376
- else
1377
- if e==min_e or f != exptt(b,p-1)
1378
- r,s,m_p,m_m,k = scale(f*2,exptt(b,-e)*2,1,1,0,_B,roundl ,roundh,v)
1379
- else
1380
- r,s,m_p,m_m,k = scale(f*b*2,exptt(b,1-e)*2,b,1,0,_B,roundl ,roundh,v)
1381
- end
1382
- end
1383
- [k]+generate(r,s,m_p,m_m,_B,roundl ,roundh)
1384
- end
1385
-
1386
- def scale(r,s,m_p,m_m,k,_B,low_ok ,high_ok,v)
1387
- return scale2(r,s,m_p,m_m,k,_B,low_ok ,high_ok) if v==0
1388
- est = (logB(_B,v)-1E-10).ceil.to_i
1389
- if est>=0
1390
- fixup(r,s*exptt(_B,est),m_p,m_m,est,_B,low_ok,high_ok)
1391
- else
1392
- sc = exptt(_B,-est)
1393
- fixup(r*sc,s,m_p*sc,m_m*sc,est,_B,low_ok,high_ok)
1394
- end
1395
- end
1396
-
1397
- def fixup(r,s,m_p,m_m,k,_B,low_ok,high_ok)
1398
- if (high_ok ? (r+m_p >= s) : (r+m_p > s)) # too low?
1399
- [r,s*_B,m_p,m_m,k+1]
1400
- else
1401
- [r,s,m_p,m_m,k]
1402
- end
1403
- end
1404
1280
 
1405
- def scale2(r,s,m_p,m_m,k,_B,low_ok ,high_ok)
1406
- loop do
1407
- if (high_ok ? (r+m_p >= s) : (r+m_p > s)) # k is too low
1408
- s *= _B
1409
- k += 1
1410
- elsif (high_ok ? ((r+m_p)*_B<s) : ((r+m_p)*_B<=s)) # k is too high
1411
- r *= _B
1412
- m_p *= _B
1413
- m_m *= _B
1414
- k -= 1
1415
- else
1416
- break
1417
- end
1418
- end
1419
- [r,s,m_p,m_m,k]
1420
- end
1421
1281
 
1422
- def generate(r,s,m_p,m_m,_B,low_ok ,high_ok)
1423
- list = []
1424
- loop do
1425
- d,r = (r*_B).divmod(s)
1426
- m_p *= _B
1427
- m_m *= _B
1428
- tc1 = low_ok ? (r<=m_m) : (r<m_m)
1429
- tc2 = high_ok ? (r+m_p >= s) : (r+m_p > s)
1430
-
1431
- if not tc1
1432
- if not tc2
1433
- list << d
1434
- else
1435
- list << d+1
1436
- break
1437
- end
1438
- else
1439
- if not tc2
1440
- list << d
1441
- break
1442
- else
1443
- if r*2 < s
1444
- list << d
1445
- break
1446
- else
1447
- list << d+1
1448
- break
1449
- end
1450
- end
1451
- end
1452
-
1453
- end
1454
- list
1455
- end
1456
-
1457
- $exptt_table = Array.new(326)
1458
- (0...326).each{|i| $exptt_table[i]=10**i}
1459
- def exptt(_B, k)
1460
- if _B==10 && k>=0 && k<326
1461
- $exptt_table[k]
1462
- else
1463
- _B**k
1464
- end
1465
- end
1466
-
1467
- $logB_table = Array.new(37)
1468
- (2...37).each{|b| $logB_table[b]=1.0/Math.log(b)}
1469
- def logB(_B, x)
1470
- if _B>=2 && _B<37
1471
- Math.log(x)*$logB_table[_B]
1472
- else
1473
- Math.log(x)/Math.log(_B)
1474
- end
1475
- end
1476
-
1477
- def float_to_digits_max(v,f,e,round_mode,min_e,p,b,_B)
1478
-
1479
- case round_mode
1480
- when :even
1481
- roundl = roundh = f.even?
1482
- when :inf
1483
- roundl = true
1484
- roundh = false
1485
- when :zero
1486
- roundl = false
1487
- roundh = true
1488
- else
1489
- # here we don't assume any rounding in the floating point numbers
1490
- # the result is valid for any rounding but may produce more digits
1491
- # than stricly necessary for specifica rounding modes.
1492
- roundl = false
1493
- roundh = false
1494
- end
1495
-
1496
- if e >= 0
1497
- if f != exptt(b,p-1)
1498
- be = exptt(b,e)
1499
- r,s,m_p,m_m,k = scale(f*be*2,2,be,be,0,_B,roundl ,roundh,v)
1500
- else
1501
- be = exptt(b,e)
1502
- be1 = be*b
1503
- r,s,m_p,m_m,k = scale(f*be1*2,b*2,be1,be,0,_B,roundl ,roundh,v)
1504
- end
1505
- else
1506
- if e==min_e or f != exptt(b,p-1)
1507
- r,s,m_p,m_m,k = scale(f*2,exptt(b,-e)*2,1,1,0,_B,roundl ,roundh,v)
1508
- else
1509
- r,s,m_p,m_m,k = scale(f*b*2,exptt(b,1-e)*2,b,1,0,_B,roundl ,roundh,v)
1510
- end
1511
- end
1512
- [k]+generate_max(r,s,m_p,m_m,_B,roundl ,roundh)
1513
- end
1514
-
1515
- def generate_max(r,s,m_p,m_m,_B,low_ok ,high_ok)
1516
- list = [false]
1517
- loop do
1518
- d,r = (r*_B).divmod(s)
1519
- m_p *= _B
1520
- m_m *= _B
1521
-
1522
- list << d
1523
-
1524
- tc1 = low_ok ? (r<=m_m) : (r<m_m)
1525
- tc2 = high_ok ? (r+m_p >= s) : (r+m_p > s)
1526
-
1527
- if tc1 && tc2
1528
- list[0] = true if r*2 >= s
1529
- break
1530
- end
1531
- end
1532
- list
1533
- end
1534
-
1535
- end
1536
-
1537
1282
  end
1538
1283
 
1539
1284
  class Float
1540
1285
  include Nio::Formattable
1541
- def self.nio_read_neutral(neutral)
1286
+ def self.nio_read_neutral(neutral)
1542
1287
  x = nil
1543
1288
 
1544
1289
  honor_rounding = true
@@ -1550,13 +1295,13 @@ class Float
1550
1295
  when :inf
1551
1296
  x = (neutral.sign=='-' ? -1.0 : +1.0)/0.0
1552
1297
  end
1553
- elsif neutral.rep_pos<neutral.digits.length
1298
+ elsif neutral.rep_pos<neutral.digits.length
1554
1299
 
1555
1300
  x,y = neutral.to_RepDec.getQ
1556
1301
  x = Float(x)/y
1557
1302
 
1558
1303
  else
1559
- nd = neutral.base==10 ? Float::DIG : ((Float::MANT_DIG-1)*Math.log(2)/Math.log(neutral.base)).floor
1304
+ nd = neutral.base==10 ? Float::DIG : ((Float::MANT_DIG-1)*Math.log(2)/Math.log(neutral.base)).floor
1560
1305
  k = neutral.dec_pos-neutral.digits.length
1561
1306
  if !honor_rounding && (neutral.digits.length<=nd && k.abs<=15)
1562
1307
  x = neutral.digits.to_i(neutral.base).to_f
@@ -1576,24 +1321,62 @@ class Float
1576
1321
  f = neutral.digits.to_i(neutral.base)
1577
1322
  e = neutral.dec_pos-neutral.digits.length
1578
1323
 
1579
- rounding = neutral.rounding
1324
+ rounding = case neutral.rounding
1325
+ when :even
1326
+ :half_even
1327
+ when :zero
1328
+ :half_down
1329
+ when :inf
1330
+ :half_up
1331
+ when :truncate
1332
+ :down
1333
+ when :directed_up
1334
+ :up
1335
+ when :floor
1336
+ :floor
1337
+ when :ceil
1338
+ :ceil
1339
+ else
1340
+ nil
1341
+ end
1580
1342
 
1581
- x = Nio::Clinger::algM(f,e,rounding,neutral.base,Float::RADIX,Float::MANT_DIG,Float::MIN_EXP-Float::MANT_DIG,Float::MAX_EXP-Float::MANT_DIG)
1582
- x = -x if neutral.sign=='-'
1343
+ reader = Flt::Support::Reader.new(:mode=>:fixed)
1344
+ sign = neutral.sign == '-' ? -1 : +1
1345
+ x = reader.read(Float.context, rounding, sign, f, e, neutral.base)
1346
+ exact = reader.exact?
1583
1347
 
1584
1348
  else
1585
1349
 
1586
1350
  f = neutral.digits.to_i(neutral.base)
1587
1351
  e = neutral.dec_pos-neutral.digits.length
1588
1352
 
1589
- rounding = neutral.rounding
1353
+ rounding = case neutral.rounding
1354
+ when :even
1355
+ :half_even
1356
+ when :zero
1357
+ :half_down
1358
+ when :inf
1359
+ :half_up
1360
+ when :truncate
1361
+ :down
1362
+ when :directed_up
1363
+ :up
1364
+ when :floor
1365
+ :floor
1366
+ when :ceil
1367
+ :ceil
1368
+ else
1369
+ nil
1370
+ end
1590
1371
 
1591
- x = Nio::Clinger::algM(f,e,rounding,neutral.base,Float::RADIX,Float::MANT_DIG,Float::MIN_EXP-Float::MANT_DIG,Float::MAX_EXP-Float::MANT_DIG)
1592
- x = -x if neutral.sign=='-'
1372
+ reader = Flt::Support::Reader.new(:mode=>:fixed)
1373
+ sign = neutral.sign == '-' ? -1 : +1
1374
+ x = reader.read(Float.context, rounding, sign, f, e, neutral.base)
1375
+ exact = reader.exact?
1593
1376
 
1594
1377
  end
1595
1378
  end
1596
-
1379
+
1597
1380
  return x
1598
1381
  end
1599
1382
  def nio_write_neutral(fmt)
@@ -1609,7 +1392,7 @@ class Float
1609
1392
  if fmt.get_ndig==:exact && fmt.get_approx==:simplify
1610
1393
 
1611
1394
  if x!=0
1612
- q = x.nio_r(Nio::Tolerance.decimals(Float::DIG,:sig))
1395
+ q = x.nio_r(Flt.Tolerance(Float::DIG, :sig_decimals))
1613
1396
  if q!=0
1614
1397
  neutral = q.nio_write_neutral(fmt)
1615
1398
  converted = true if neutral.digits.length<=Float::DIG
@@ -1620,11 +1403,11 @@ class Float
1620
1403
  neutral = x.nio_xr.nio_write_neutral(fmt)
1621
1404
  converted = true
1622
1405
  end
1623
- if !converted
1406
+ if !converted
1624
1407
  if fmt.get_base==10 && false
1625
1408
  txt = format "%.*e",Float::DECIMAL_DIG-1,x # note that spec. e output precision+1 significant digits
1626
1409
 
1627
- sign = '+'
1410
+ sign = '+'
1628
1411
  if txt[0,1]=='-'
1629
1412
  sign = '-'
1630
1413
  txt = txt[1...txt.length]
@@ -1636,12 +1419,12 @@ class Float
1636
1419
  exp_i = txt.index(x_char.downcase) if exp_i===nil
1637
1420
  if exp_i!=nil
1638
1421
  exp = txt[exp_i+1...txt.length].to_i
1639
- txt = txt[0...exp_i]
1640
- end
1422
+ txt = txt[0...exp_i]
1423
+ end
1641
1424
 
1642
1425
  dec_pos = txt.index '.'
1643
1426
  if dec_pos==nil
1644
- dec_pos = txt.length
1427
+ dec_pos = txt.length
1645
1428
  else
1646
1429
  txt[dec_pos]=''
1647
1430
  end
@@ -1654,7 +1437,6 @@ class Float
1654
1437
  if !converted
1655
1438
 
1656
1439
  sign = x<0 ? '-' : '+'
1657
- x = -x if sign=='-'
1658
1440
  f,e = Math.frexp(x)
1659
1441
  if e < Float::MIN_EXP
1660
1442
  # denormalized number
@@ -1668,48 +1450,51 @@ class Float
1668
1450
  f = f.to_i
1669
1451
  inexact = true
1670
1452
 
1671
- rounding = fmt.get_round
1672
-
1673
- if fmt.get_all_digits?
1674
- # use as many digits as possible
1675
- dec_pos,r,*digits = Nio::BurgerDybvig::float_to_digits_max(x,f,e,rounding,Float::MIN_EXP-Float::MANT_DIG,Float::MANT_DIG,Float::RADIX,fmt.get_base)
1676
- inexact = :roundup if r
1453
+ rounding = case fmt.get_round
1454
+ when :even
1455
+ :half_even
1456
+ when :zero
1457
+ :half_down
1458
+ when :inf
1459
+ :half_up
1460
+ when :truncate
1461
+ :down
1462
+ when :directed_up
1463
+ :up
1464
+ when :floor
1465
+ :floor
1466
+ when :ceil
1467
+ :ceil
1677
1468
  else
1678
- # use as few digits as possible
1679
- dec_pos,*digits = Nio::BurgerDybvig::float_to_digits(x,f,e,rounding,Float::MIN_EXP-Float::MANT_DIG,Float::MANT_DIG,Float::RADIX,fmt.get_base)
1469
+ nil
1680
1470
  end
1471
+
1472
+
1473
+ # Note: it is assumed that fmt will be used for for input too, otherwise
1474
+ # rounding should be Float.context.rounding (input rounding for Float) rather than fmt.get_round (output)
1475
+ formatter = Flt::Support::Formatter.new(Float::RADIX, Float::MIN_EXP-Float::MANT_DIG, fmt.get_base)
1476
+ formatter.format(x, f, e, rounding, Float::MANT_DIG, fmt.get_all_digits?)
1477
+ inexact = formatter.round_up if formatter.round_up.is_a?(Symbol)
1478
+ dec_pos, digits = formatter.digits
1681
1479
  txt = ''
1682
1480
  digits.each{|d| txt << fmt.get_base_digits.digit_char(d)}
1683
1481
  neutral.set sign, txt, dec_pos, nil, fmt.get_base_digits, inexact, fmt.get_round
1684
1482
 
1685
1483
  end
1686
1484
  end
1687
-
1485
+
1688
1486
  return neutral
1689
- end
1690
- end
1691
-
1692
- class Numeric
1693
- unless method_defined?(:even?)
1694
- def even?
1695
- self.modulo(2)==0
1696
- end
1697
- end
1698
- unless method_defined?(:odd?)
1699
- def odd?
1700
- self.modulo(2)!=0
1701
- end
1702
1487
  end
1703
1488
  end
1704
1489
 
1705
1490
  class Integer
1706
1491
  include Nio::Formattable
1707
- def self.nio_read_neutral(neutral)
1492
+ def self.nio_read_neutral(neutral)
1708
1493
  x = nil
1709
1494
 
1710
1495
  if neutral.special?
1711
1496
  raise Nio::InvalidFormat,"Invalid integer numeral"
1712
- elsif neutral.rep_pos<neutral.digits.length
1497
+ elsif neutral.rep_pos<neutral.digits.length
1713
1498
  return Rational.nio_read_neutral(neutral).to_i
1714
1499
  else
1715
1500
  digits = neutral.digits
@@ -1719,18 +1504,18 @@ class Integer
1719
1504
  elsif neutral.dec_pos <= digits.length
1720
1505
  digits = digits[0...neutral.dec_pos]
1721
1506
  else
1722
- digits = digits + '0'*(neutral.dec_pos-digits.length)
1507
+ digits = digits + '0'*(neutral.dec_pos-digits.length)
1723
1508
  end
1724
1509
 
1725
1510
  x = digits.to_i(neutral.base)
1726
1511
  # this was formely needed because we didn't adust the digits
1727
1512
  # if neutral.dec_pos != neutral.digits.length
1728
1513
  # # with rational included, negative powers of ten are rational numbers
1729
- # x = (x*((neutral.base)**(neutral.dec_pos-neutral.digits.length))).to_i
1514
+ # x = (x*((neutral.base)**(neutral.dec_pos-neutral.digits.length))).to_i
1730
1515
  # end
1731
1516
  x = -x if neutral.sign=='-'
1732
1517
  end
1733
-
1518
+
1734
1519
  return x
1735
1520
  end
1736
1521
  def nio_write_neutral(fmt)
@@ -1739,16 +1524,16 @@ class Integer
1739
1524
 
1740
1525
  sign = x<0 ? '-' : '+'
1741
1526
  txt = x.abs.to_s(fmt.get_base)
1742
- dec_pos = rep_pos = txt.length
1527
+ dec_pos = rep_pos = txt.length
1743
1528
  neutral.set sign, txt, dec_pos, nil, fmt.get_base_digits, false ,fmt.get_round
1744
-
1529
+
1745
1530
  return neutral
1746
1531
  end
1747
1532
  end
1748
1533
 
1749
1534
  class Rational
1750
1535
  include Nio::Formattable
1751
- def self.nio_read_neutral(neutral)
1536
+ def self.nio_read_neutral(neutral)
1752
1537
  x = nil
1753
1538
 
1754
1539
  if neutral.special?
@@ -1761,7 +1546,7 @@ class Rational
1761
1546
  else
1762
1547
  x = Rational(*neutral.to_RepDec.getQ)
1763
1548
  end
1764
-
1549
+
1765
1550
  return x
1766
1551
  end
1767
1552
  def nio_write_neutral(fmt)
@@ -1769,7 +1554,7 @@ class Rational
1769
1554
  x = self
1770
1555
 
1771
1556
  if x.denominator==0
1772
- if x.numerator>0
1557
+ if x.numerator>0
1773
1558
  neutral.set_special(:inf)
1774
1559
  elsif x.numerator<0
1775
1560
  neutral.set_special(:inf,'-')
@@ -1786,7 +1571,7 @@ class Rational
1786
1571
  neutral = rd.to_NeutralNum(fmt.get_base_digits)
1787
1572
  neutral.rounding = fmt.get_round
1788
1573
  end
1789
-
1574
+
1790
1575
  return neutral
1791
1576
  end
1792
1577
  end
@@ -1794,7 +1579,7 @@ end
1794
1579
  if defined? BigDecimal
1795
1580
  class BigDecimal
1796
1581
  include Nio::Formattable
1797
- def self.nio_read_neutral(neutral)
1582
+ def self.nio_read_neutral(neutral)
1798
1583
  x = nil
1799
1584
 
1800
1585
  if neutral.special?
@@ -1804,7 +1589,7 @@ class BigDecimal
1804
1589
  when :inf
1805
1590
  x = BigDecimal(neutral.sign=='-' ? '-1.0' : '+1.0')/0
1806
1591
  end
1807
- elsif neutral.rep_pos<neutral.digits.length
1592
+ elsif neutral.rep_pos<neutral.digits.length
1808
1593
 
1809
1594
  x,y = neutral.to_RepDec.getQ
1810
1595
  x = BigDecimal(x.to_s)/y
@@ -1819,12 +1604,12 @@ class BigDecimal
1819
1604
  str += "E#{(neutral.dec_pos-neutral.digits.length)}"
1820
1605
  x = BigDecimal(str)
1821
1606
  else
1822
- x = BigDecimal(neutral.digits.to_i(neutral.base).to_s)
1607
+ x = BigDecimal(neutral.digits.to_i(neutral.base).to_s)
1823
1608
  x *= BigDecimal(neutral.base.to_s)**(neutral.dec_pos-neutral.digits.length)
1824
1609
  x = -x if neutral.sign=='-'
1825
1610
  end
1826
1611
  end
1827
-
1612
+
1828
1613
  return x
1829
1614
  end
1830
1615
  def nio_write_neutral(fmt)
@@ -1835,26 +1620,26 @@ class BigDecimal
1835
1620
  neutral.set_special(:nan)
1836
1621
  elsif x.infinite?
1837
1622
  neutral.set_special(:inf, x<0 ? '-' : '+')
1838
- else
1623
+ else
1839
1624
  converted = false
1840
1625
  if fmt.get_ndig==:exact && fmt.get_approx==:simplify
1841
1626
 
1842
1627
  prc = [x.precs[0],20].max
1843
- neutral = x.nio_r(Nio::BigTolerance.decimals(prc,:sig)).nio_write_neutral(fmt)
1628
+ neutral = x.nio_r(Flt.Tolerance(prc, :sig_decimals)).nio_write_neutral(fmt)
1844
1629
  converted = true if neutral.digits.length<prc
1845
1630
 
1846
1631
  elsif fmt.get_approx==:exact && fmt.get_base!=10
1847
1632
  neutral = x.nio_xr.nio_write_neutral(fmt)
1848
1633
  converted = true
1849
1634
  end
1850
- if !converted
1851
- if fmt.get_base==10
1635
+ if !converted
1636
+ if fmt.get_base==10
1852
1637
  # Don't use x.to_s because of bugs in BigDecimal in Ruby 1.9 revisions 20359-20797
1853
1638
  # x.to_s('F') is not affected by that problem, but produces innecesary long strings
1854
1639
  sgn,ds,b,e = x.split
1855
1640
  txt = "#{sgn<0 ? '-' : ''}0.#{ds}E#{e}"
1856
1641
 
1857
- sign = '+'
1642
+ sign = '+'
1858
1643
  if txt[0,1]=='-'
1859
1644
  sign = '-'
1860
1645
  txt = txt[1...txt.length]
@@ -1866,12 +1651,12 @@ class BigDecimal
1866
1651
  exp_i = txt.index(x_char.downcase) if exp_i===nil
1867
1652
  if exp_i!=nil
1868
1653
  exp = txt[exp_i+1...txt.length].to_i
1869
- txt = txt[0...exp_i]
1870
- end
1654
+ txt = txt[0...exp_i]
1655
+ end
1871
1656
 
1872
1657
  dec_pos = txt.index '.'
1873
1658
  if dec_pos==nil
1874
- dec_pos = txt.length
1659
+ dec_pos = txt.length
1875
1660
  else
1876
1661
  txt[dec_pos]=''
1877
1662
  end
@@ -1880,41 +1665,197 @@ class BigDecimal
1880
1665
 
1881
1666
  converted = true
1882
1667
  end
1883
- end
1668
+ end
1884
1669
  if !converted
1885
1670
 
1886
- min_prec = 24
1887
- min_exp = -1000
1888
- s,f,b,e = x.split
1889
- e -= f.size
1890
- sign = s<0 ? '-' : '+'
1891
- x = -x if sign=='-'
1892
- f_i = f.to_i
1893
- prc = [x.precs[0],min_prec].max
1894
- f_i *= 10**(prc-f.size)
1895
- e -= (prc-f.size)
1671
+ x = Flt::DecNum(x.to_s)
1672
+
1673
+ min_exp = num_class.context.etiny
1674
+ n = x.number_of_digits
1675
+ s,f,e = x.split
1676
+ b = num_class.radix
1677
+ if s < 0
1678
+ sign = '-'
1679
+ else
1680
+ sign = '+'
1681
+ end
1682
+ prc = x.number_of_digits
1683
+ f = num_class.int_mult_radix_power(f, prc-n)
1684
+ e -= (prc-n)
1896
1685
 
1897
1686
  inexact = true
1898
1687
 
1899
- rounding = fmt.get_round
1900
-
1901
- if fmt.get_all_digits?
1902
- # use as many digits as possible
1903
- dec_pos,r,*digits = Nio::BurgerDybvig::float_to_digits_max(x,f_i,e,rounding,[e,min_exp].min,prc,b,fmt.get_base)
1904
- inexact = :roundup if r
1688
+ rounding = case fmt.get_round
1689
+ when :even
1690
+ :half_even
1691
+ when :zero
1692
+ :half_down
1693
+ when :inf
1694
+ :half_up
1695
+ when :truncate
1696
+ :down
1697
+ when :directed_up
1698
+ :up
1699
+ when :floor
1700
+ :floor
1701
+ when :ceil
1702
+ :ceil
1905
1703
  else
1906
- # use as few digits as possible
1907
- dec_pos,*digits = Nio::BurgerDybvig::float_to_digits(x,f_i,e,rounding,[e,min_exp].min,prc,b,fmt.get_base)
1704
+ nil
1908
1705
  end
1706
+
1707
+
1708
+ # TODO: use Num#format instead
1709
+ # Note: it is assumed that fmt will be used for for input too, otherwise
1710
+ # rounding should be Float.context.rounding (input rounding for Float) rather than fmt.get_round (output)
1711
+ formatter = Flt::Support::Formatter.new(num_class.radix, num_class.context.etiny, fmt.get_base)
1712
+ formatter.format(x, f, e, rounding, prc, fmt.get_all_digits?)
1713
+ inexact = formatter.round_up if formatter.round_up.is_a?(Symbol)
1714
+ dec_pos,digits = formatter.digits
1909
1715
  txt = ''
1910
1716
  digits.each{|d| txt << fmt.get_base_digits.digit_char(d)}
1911
1717
  neutral.set sign, txt, dec_pos, nil, fmt.get_base_digits, inexact, fmt.get_round
1912
1718
 
1719
+
1913
1720
  end
1914
1721
  end
1915
-
1722
+
1916
1723
  return neutral
1917
1724
  end
1918
1725
  end
1919
1726
  end
1920
1727
 
1728
+ class Flt::Num
1729
+ include Nio::Formattable
1730
+ def self.nio_read_neutral(neutral)
1731
+ x = nil
1732
+
1733
+ if neutral.special?
1734
+ case neutral.special
1735
+ when :nan
1736
+ x = num_class.nan
1737
+ when :inf
1738
+ x = num_class.infinity(neutral.sign=='-' ? '-1.0' : '+1.0')
1739
+ end
1740
+ elsif neutral.rep_pos<neutral.digits.length
1741
+
1742
+ # uses num_clas.context.precision TODO: ?
1743
+ x = num_class.new Rational(*neutral.to_RepDec.getQ)
1744
+
1745
+ else
1746
+ if neutral.base==num_class.radix
1747
+ if neutral.base==10
1748
+ str = neutral.sign
1749
+ str += neutral.digits
1750
+ str += "E#{(neutral.dec_pos-neutral.digits.length)}"
1751
+ x = num_class.new(str)
1752
+ else
1753
+ f = neutral.digits.to_i(neutral.base)
1754
+ e = neutral.dec_pos-neutral.digits.length
1755
+ s = neutral.sign=='-' ? -1 : +1
1756
+ x = num_class.Num(s, f, e)
1757
+ end
1758
+ else
1759
+ # uses num_clas.context.precision TODO: ?
1760
+ if num_class.respond_to?(:power)
1761
+ x = num_class.Num(neutral.digits.to_i(neutral.base).to_s)
1762
+ x *= num_class.Num(neutral.base.to_s)**(neutral.dec_pos-neutral.digits.length)
1763
+ x = -x if neutral.sign=='-'
1764
+ else
1765
+
1766
+ # uses num_clas.context.precision TODO: ?
1767
+ x = num_class.new Rational(*neutral.to_RepDec.getQ)
1768
+
1769
+ end
1770
+ end
1771
+ end
1772
+
1773
+ return x
1774
+ end
1775
+ def nio_write_neutral(fmt)
1776
+ neutral = Nio::NeutralNum.new
1777
+ x = self
1778
+
1779
+ if x.nan?
1780
+ neutral.set_special(:nan)
1781
+ elsif x.infinite?
1782
+ neutral.set_special(:inf, x<0 ? '-' : '+')
1783
+ else
1784
+ converted = false
1785
+ if fmt.get_ndig==:exact && fmt.get_approx==:simplify
1786
+
1787
+ neutral = x.nio_r(Flt.Tolerance('0.5', :ulps)).nio_write_neutral(fmt)
1788
+ # TODO: find better method to accept the conversion
1789
+ prc = (fmt.get_base==num_class.radix) ? x.number_of_digits : x.coefficient.to_s(fmt.get_base).length
1790
+ prc = [prc, 8].max
1791
+ converted = true if neutral.digits.length<prc
1792
+
1793
+ elsif fmt.get_approx==:exact && fmt.get_base!=num_class.radix
1794
+ # TODO: num_class.context(:precision=>fmt....
1795
+ neutral = x.to_r.nio_write_neutral(fmt)
1796
+ converted = true
1797
+ end
1798
+ if !converted
1799
+ if fmt.get_base==num_class.radix
1800
+ sign = x.sign==-1 ? '-' : '+'
1801
+ txt = x.coefficient.to_s(fmt.get_base) # TODO: can use x.digits directly?
1802
+ dec_pos = rep_pos = x.fractional_exponent
1803
+ neutral.set sign, txt, dec_pos, nil, fmt.get_base_digits, false ,fmt.get_round
1804
+ converted = true
1805
+ end
1806
+ end
1807
+ if !converted
1808
+
1809
+ min_exp = num_class.context.etiny
1810
+ n = x.number_of_digits
1811
+ s,f,e = x.split
1812
+ b = num_class.radix
1813
+ if s < 0
1814
+ sign = '-'
1815
+ else
1816
+ sign = '+'
1817
+ end
1818
+ prc = x.number_of_digits
1819
+ f = num_class.int_mult_radix_power(f, prc-n)
1820
+ e -= (prc-n)
1821
+
1822
+ inexact = true
1823
+
1824
+ rounding = case fmt.get_round
1825
+ when :even
1826
+ :half_even
1827
+ when :zero
1828
+ :half_down
1829
+ when :inf
1830
+ :half_up
1831
+ when :truncate
1832
+ :down
1833
+ when :directed_up
1834
+ :up
1835
+ when :floor
1836
+ :floor
1837
+ when :ceil
1838
+ :ceil
1839
+ else
1840
+ nil
1841
+ end
1842
+
1843
+
1844
+ # TODO: use Num#format instead
1845
+ # Note: it is assumed that fmt will be used for for input too, otherwise
1846
+ # rounding should be Float.context.rounding (input rounding for Float) rather than fmt.get_round (output)
1847
+ formatter = Flt::Support::Formatter.new(num_class.radix, num_class.context.etiny, fmt.get_base)
1848
+ formatter.format(x, f, e, rounding, prc, fmt.get_all_digits?)
1849
+ inexact = formatter.round_up if formatter.round_up.is_a?(Symbol)
1850
+ dec_pos,digits = formatter.digits
1851
+ txt = ''
1852
+ digits.each{|d| txt << fmt.get_base_digits.digit_char(d)}
1853
+ neutral.set sign, txt, dec_pos, nil, fmt.get_base_digits, inexact, fmt.get_round
1854
+
1855
+ end
1856
+ end
1857
+
1858
+ return neutral
1859
+ end
1860
+ end
1861
+