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/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
+