lib/nio/fmt.rb in nio-0.2.3 vs lib/nio/fmt.rb in nio-0.2.4
- old
+ new
@@ -16,14 +16,16 @@
require 'rational'
require 'bigdecimal'
+require 'flt'
+
module Nio
# positional notation, unformatted numeric literal: used as intermediate form
- class NeutralNum
+ class NeutralNum
include StateEquivalent
def initialize(s='',d='',p=nil,r=nil,dgs=DigitsDef.base(10), inexact=false, round=:inf)
set s,d,p,r,dgs,dgs, inexact, round
end
attr_reader :sign, :digits, :dec_pos, :rep_pos, :special, :inexact, :rounding
@@ -38,11 +40,11 @@
@dgs = dgs
@base = @dgs.radix
@inexact = inexact
@special = nil
@rounding = rounding
- trimZeros unless inexact
+ trimZeros unless inexact
self
end
# set infinite (:inf) and invalid (:nan) numbers
def set_special(s,sgn='') # :inf, :nan
@special = s
@@ -82,11 +84,11 @@
else
#n.set @sign.dup, @digits.dup, @dec_pos.dup, @rep_pos.dup, @dgs.dup
# in Ruby 1.6.8 Float,BigNum,Fixnum doesn't respond to dup
n.set @sign.dup, @digits.dup, @dec_pos, @rep_pos, @dgs.dup, @inexact, @rounding
end
- return n
+ return n
end
def zero?
z = false
if !special
@@ -117,28 +119,33 @@
n = [n,@digits.size].min if @inexact
adj = 0
dv = :tie
if @inexact && n==@digits.size
- dv = @inexact==:roundup ? :hi : :lo
+ # TODO: the combination of the value true with the values of Formatter#round_up makes this ugly
+ dv = @inexact.is_a?(Symbol) ? @inexact : :lo
else
v = dig_value(n)
v2 = 2*v
if v2 < @base # v<((@base+1)/2)
dv = :lo
elsif v2 > @base # v>(@base/2)
dv = :hi
else
-
- (n+1...@digits.length).each do |i|
- if dig_value(i)>0
- dv = :hi
- break
- end
- end
-
- dv = :hi if dv==:tie && @rep_pos<=n
+ if @inexact
+ dv = :hi
+ else
+
+ (n+1...@digits.length).each do |i|
+ if dig_value(i)>0
+ dv = :hi
+ break
+ end
+ end
+
+ end
+ dv = :hi if dv==:tie && @rep_pos<=n
end
end
if dv==:hi
adj = +1
@@ -147,14 +154,14 @@
adj = +1
elsif dir==:even # to nearest even digit (IEEE unbiased rounding)
adj = +1 if (dig_value(n-1)%2)!=0
elsif dir==:zero # towards zero
adj=0
- # elsif dir==:odd
+ # elsif dir==:odd
# adj = +1 unless (dig_value(n-1)%2)!=0
end
- end
+ end
if n>@digits.length
(@digits.length...n).each do |i|
@digits << dig_char(dig_value(i))
@rep_pos += 1
@@ -173,21 +180,21 @@
elsif v>=@base
v -= @base
adj = +1
end
if i<0
- prefix = dig_char(v)+prefix
+ prefix = dig_char(v)+prefix
elsif i<@digits.length
@digits[i] = dig_char(v)
end
i += -1
- end
+ end
if n<0
- @digits = ""
+ @digits = ""
else
- @digits = @digits[0...n]
+ @digits = @digits[0...n]
end
@rep_pos = @digits.length
if prefix!=''
@digits = prefix + @digits
@@ -203,14 +210,14 @@
nn = dup
nn.round!(n,mode,dir)
return nn
end
- def trimTrailZeros()
+ def trimTrailZeros()
i = @digits.length
while i>0 && dig_value(i-1)==0
- i -= 1
+ i -= 1
end
if @rep_pos>=i
@digits = @digits[0...i]
@rep_pos = i
end
@@ -238,24 +245,24 @@
@dec_pos = 1
end
end
- def trimZeros()
+ def trimZeros()
trimLeadZeros
trimTrailZeros
end
protected
def dig_value(i)
v = 0
- if i>=@rep_pos
+ if i>=@rep_pos
i -= @digits.length
i %= @digits.length - @rep_pos if @rep_pos<@digits.length
i += @rep_pos
- end
+ end
if i>=0 && i<@digits.length
v = @dgs.digit_value(@digits[i]) #digcode_value(@digits[i])
end
return v>=0 && v<@base ? v : nil
end
@@ -300,12 +307,12 @@
else
if dec_pos<=0
n.ip = 0
n.d = text_to_digits(dig_char(0)*(-dec_pos) + digits)
elsif dec_pos >= digits.length
- n.ip = digits.to_i(@base)
- if rep_pos<dec_pos
+ n.ip = digits.to_i(@base)
+ if rep_pos<dec_pos
i=0
(dec_pos-digits.length).times do
n.ip *= @base
n.ip += @dgs.digit_value(digits[rep_pos+i]) if rep_pos+i<digits.length
i += 1
@@ -324,26 +331,26 @@
n.d = []
end
else
n.ip = digits[0...dec_pos].to_i(@base)
n.d = text_to_digits(digits[dec_pos..-1])
- if rep_pos<dec_pos
+ if rep_pos<dec_pos
new_rep_pos = n.d.size + dec_pos
n.d += text_to_digits(digits[rep_pos..-1])
self.rep_pos = new_rep_pos
puts "--rep_pos=#{rep_pos}"
- end
+ end
end
n.sign = -1 if sign=='-'
- n.rep_i = rep_pos - dec_pos
+ n.rep_i = rep_pos - dec_pos
end
n.normalize!(!inexact) # keep trailing zeros for inexact numbers
return n
end
protected
def text_to_digits(txt)
- #txt.split('').collect{|c| @dgs.digit_value(c)}
+ #txt.split('').collect{|c| @dgs.digit_value(c)}
ds = []
txt.each_byte{|b| ds << @dgs.digit_value(b)}
ds
end
end
@@ -362,11 +369,11 @@
when :neginfinity
num.set_special :inf,'-'
else
num = nil
end
-
+
else
base_dgs ||= DigitsDef.base(@radix)
# assert base_dgs.radix == @radix
signch = sign<0 ? '-' : '+'
decimals = ip.to_s(@radix)
@@ -374,11 +381,11 @@
d.each {|dig| decimals << base_dgs.digit_char(dig) }
rep_pos = rep_i==nil ? decimals.length : dec_pos + rep_i
num.set signch, decimals, dec_pos, rep_pos, base_dgs
end
return num
- end
+ end
end
# A Fmt object defines a numeric format.
#
# The formatting aspects managed by Fmt are:
@@ -390,11 +397,11 @@
# - see #sep() and #grouping()
# * field justfification
# - #width() and the shortcut #pad0s()
# * numerical base
# - #base()
- # * repeating numerals
+ # * repeating numerals
# - #rep()
#
# Note that for every aspect there are also corresponding _mutator_
# methos (its name ending with a bang) that modify an object in place,
# instead of returning an altered copy.
@@ -459,16 +466,16 @@
@base_prefix = false
@nan_txt = 'NAN'
@inf_txt = 'Infinity'
- yield self if block_given?
+ yield self if block_given?
end
# Defines the separators used in numerals. This is relevant to
- # both input and output.
- #
+ # both input and output.
+ #
# The first argument is the radix point separator (usually
# a point or a comma; by default it is a point.)
#
# The second argument is the group separator.
#
@@ -493,16 +500,16 @@
# This is the mutator version of #grouping().
def grouping!(grp=[3],grp_sep=nil)
set! :grp_sep=>grp_sep, :grp=>grp
end
- # This is a shortcut to return a new default Fmt object
+ # This is a shortcut to return a new default Fmt object
# and define the separators as with #sep().
def Fmt.sep(dec_sep,grp_sep=nil,grp=nil)
Fmt.default.sep(dec_sep,grp_sep,grp)
end
- # This is a shortcut to return a new default Fmt object
+ # This is a shortcut to return a new default Fmt object
# and define the grouping as with #grouping().
def Fmt.grouping(grp=[3],grp_sep=nil)
Fmt.default.grouping(grp,grp_sep)
end
@@ -524,14 +531,14 @@
#
# Other paramters can be passed in a hash after <tt>precision</tt>
# - <tt>:round</tt> rounding mode applied to conversions
# (this is relevant for both input and output). It must be one of:
# [<tt>:inf</tt>]
- # rounds to nearest with ties toward infinite;
+ # rounds to nearest with ties toward infinite;
# 1.5 is rounded to 2, -1.5 to -2
# [<tt>:zero</tt>]
- # rounds to nearest with ties toward zero;
+ # rounds to nearest with ties toward zero;
# 1.5 is rounded to 1, -1.5 to 2
# [<tt>:even</tt>]
# rounds to the nearest with ties toward an even digit;
# 1.5 rounds to 2, 2.5 to 2
# - <tt>:approx</tt> approximate mode
@@ -542,11 +549,11 @@
# [<tt>:exact</tt>]
# the value is interpreted as exact, there's no distinction between
# significant and insignificant digits.
# [<tt>:simplify</tt>]
# the value is simplified, if possible to a simpler (rational) value.
- # - <tt>:show_all_digits</tt> if true, this forces to show digits that
+ # - <tt>:show_all_digits</tt> if true, this forces to show digits that
# would otherwise not be shown in the <tt>:gen</tt> format: trailing
# zeros of exact types or non-signficative digits of inexact types.
# - <tt>:nonsignficative_digits</tt> assigns a character to display
# insignificant digits, # by default
def mode(mode,precision=nil,options={})
@@ -560,22 +567,22 @@
# Defines the formatting mode like #mode() but using a different
# order of the first two parameters parameters, which is useful
# to change the precision only. Refer to #mode().
def prec(precision,mode=nil, options={})
dup.prec! precision, mode, options
- end
+ end
# This is the mutator version of #prec().
def prec!(precision,mode=:gen, options={})
set! options.merge(:mode=>mode, :ndig=>precision)
end
- # This is a shortcut to return a new default Fmt object
+ # This is a shortcut to return a new default Fmt object
# and define the formatting mode as with #mode()
def Fmt.mode(mode,ndig=nil,options={})
Fmt.default.mode(mode,ndig,options)
end
- # This is a shortcut to return a new default Fmt object
+ # This is a shortcut to return a new default Fmt object
# and define the formatting mode as with #prec()
def Fmt.prec(ndig,mode=nil,options={})
Fmt.default.prec(ndig,mode,options)
end
@@ -590,11 +597,11 @@
Fmt.default = Fmt.default.round(m)
end
# This controls the display of the digits that are not necessary
# to specify the value unambiguosly (e.g. trailing zeros).
- #
+ #
# The true (default) value forces the display of the requested number of digits
# and false will display only necessary digits.
def show_all_digits(ad=true)
dup.show_all_digits! ad
end
@@ -638,26 +645,26 @@
# This is the mutator version of #sci_digits().
def sci_digits!(n=-1)
set! :sci_format=>n
end
- # This is a shortcut to return a new default Fmt object
+ # This is a shortcut to return a new default Fmt object
# and define show_all_digits
def Fmt.show_all_digits(v=true)
Fmt.default.show_all_digits(v)
end
- # This is a shortcut to return a new default Fmt object
+ # This is a shortcut to return a new default Fmt object
# and define approx_mode
def Fmt.approx_mode(v)
Fmt.default.approx_mode(v)
end
- # This is a shortcut to return a new default Fmt object
+ # This is a shortcut to return a new default Fmt object
# and define insignificant digits
def Fmt.insignificant_digits(v='#')
Fmt.default.insignificant_digits(v)
end
- # This is a shortcut to return a new default Fmt object
+ # This is a shortcut to return a new default Fmt object
# and define sci_digits
def Fmt.sci_digits(v=-1)
Fmt.default.sci_digits(v)
end
@@ -681,16 +688,16 @@
set! :show_exp_plus=>sp
set! :plus_symbol=>sp if sp.kind_of?(String)
self
end
- # This is a shortcut to return a new default Fmt object
+ # This is a shortcut to return a new default Fmt object
# and define show_plus
def Fmt.show_plus(v=true)
Fmt.default.show_plus(v)
end
- # This is a shortcut to return a new default Fmt object
+ # This is a shortcut to return a new default Fmt object
# and define show_exp_plus
def Fmt.show_exp_plus(v=true)
Fmt.default.show_exp_plus(v)
end
@@ -699,33 +706,33 @@
# [<tt>:begin</tt>] is the beginning delimiter of repeating section (<)
# [<tt>:end</tt>] is the ending delimiter of repeating section (<)
# [<tt>:suffix</tt>] is the suffix used to indicate a implicit repeating decimal
# [<tt>:rep</tt>]
# if this parameter is greater than zero, on output the repeating section
- # is repeated the indicated number of times followed by the suffix;
+ # is repeated the indicated number of times followed by the suffix;
# otherwise the delimited notation is used.
# [<tt>:read</tt>]
# (true/false) determines if repeating decimals are
# recognized on input (true)
def rep(*params)
dup.rep!(*params)
end
# This is the mutator version of #rep().
- def rep!(*params)
+ def rep!(*params)
params << {} if params.size==0
if params[0].kind_of?(Hash)
params = params[0]
- else
- begch,endch,autoch,rep,read = *params
+ else
+ begch,endch,autoch,rep,read = *params
params = {:begin=>begch,:end=>endch,:suffix=>autoch,:nreps=>rep,:read=>read}
end
set! params
end
- # This is a shortcut to return a new default Fmt object
+ # This is a shortcut to return a new default Fmt object
# and define the repeating decimals mode as with #rep()
def Fmt.rep(*params)
Fmt.default.rep(*params)
end
@@ -820,21 +827,21 @@
@round
end
# Method used internally to format a neutral numeral
def nio_write_formatted(neutral) # :nodoc:
- str = ''
+ str = ''
if neutral.special?
str << neutral.sign
case neutral.special
when :inf
str << @inf_txt
when :nan
str << @nan_txt
- end
+ end
else
- zero = get_base_digits(neutral.base).digit_char(0).chr
+ zero = get_base_digits(neutral.base).digit_char(0).chr
neutral = neutral.dup
round! neutral
if neutral.zero?
str << neutral.sign if neutral.sign=='-' # show - if number was <0 before rounding
str << zero
@@ -859,20 +866,20 @@
else
integral_digits = neutral.digits.length
end
end
exp = neutral.dec_pos - integral_digits
-
+
case actual_mode
when :gen # general (automatic)
# @ndig means significant digits
actual_mode = :sig
actual_mode = :sci if use_scientific?(neutral, exp)
trim_trail_zeros = !@all_digits # true
end
- case actual_mode
+ case actual_mode
when :fix, :sig #, :gen
if @show_plus || neutral.sign!='+'
str << ({'-'=>@minus_symbol, '+'=>@plus_symbol}[neutral.sign] || neutral.sign)
@@ -901,11 +908,11 @@
end
digits = neutral.digits + ns_digits
if neutral.dec_pos<=0
str << zero+@dec_sep+zero*(-neutral.dec_pos) + digits
- elsif neutral.dec_pos >= digits.length
+ elsif neutral.dec_pos >= digits.length
str << group(digits + zero*(neutral.dec_pos-digits.length))
else
str << group(digits[0...neutral.dec_pos]) + @dec_sep + digits[neutral.dec_pos..-1]
end
end
@@ -915,11 +922,11 @@
str.chop! while str[-1]==zero[0]
str.chomp!(@dec_sep)
#puts str
end
-
+
when :sci
if @show_plus || neutral.sign!='+'
str << ({'-'=>@minus_symbol, '+'=>@plus_symbol}[neutral.sign] || neutral.sign)
@@ -933,11 +940,11 @@
#zero = get_base_digits.digit_char(0).chr
if @ndig==:exact
neutral.sign = '+'
neutral.dec_pos-=exp
- str << neutral.to_RepDec.getS(@rep_n, getRepDecOpt(neutral.base))
+ str << neutral.to_RepDec.getS(@rep_n, getRepDecOpt(neutral.base))
else
ns_digits = ''
nd = neutral.digits.length
if actual_mode==:fix
@@ -949,11 +956,11 @@
digits = neutral.digits + ns_digits
str << ((integral_digits<1) ? zero : digits[0...integral_digits])
str << @dec_sep
str << digits[integral_digits...@ndig]
- pad_right =(@ndig+1-str.length)
+ pad_right =(@ndig+1-str.length)
str << zero*pad_right if pad_right>0 && !neutral.inexact? # maybe we didn't have enought digits
end
#str = str.chomp(zero).chomp(@dec_sep) if trim_trail_zeros && str.include?(@dec_sep)
if trim_trail_zeros && str.include?(@dec_sep) && str[-@rep_auto.size..-1]!=@rep_auto
@@ -965,11 +972,11 @@
str << get_exp_char(neutral.base)
if @show_exp_plus || exp<0
str << (exp<0 ? (@minus_symbol || '-') : (@plus_symbol || '+'))
end
str << exp.abs.to_s
-
+
end
end
end
@@ -983,11 +990,11 @@
l = @width - str.length
if l>0
case @adjust
when :internal
sign = ''
- if str[0,1]=='+' || str[0,1]=='-'
+ if str[0,1]=='+' || str[0,1]=='-'
sign = str[0,1]
str = str[1...str.length]
end
str = sign + @fill_char*l + str
when :center
@@ -995,11 +1002,11 @@
when :right
str = @fill_char*l + str
when :left
str = str + @fill_char*l
end
- end
+ end
end
return str
end
@@ -1011,27 +1018,27 @@
@@sci_fmt = nil
def nio_read_formatted(txt) # :nodoc:
txt = txt.dup
num = nil
-
+
base = nil
base ||= get_base
-
- zero = get_base_digits(base).digit_char(0).chr
- txt.tr!(@non_sig,zero) # we don't simply remove it because it may be before the radix point
-
+
+ zero = get_base_digits(base).digit_char(0).chr
+ txt.tr!(@non_sig,zero) # we don't simply remove it because it may be before the radix point
+
exp = 0
x_char = get_exp_char(base)
exp_i = txt.index(x_char)
exp_i = txt.index(x_char.downcase) if exp_i===nil
if exp_i!=nil
exp = txt[exp_i+1...txt.length].to_i
- txt = txt[0...exp_i]
- end
+ txt = txt[0...exp_i]
+ end
opt = getRepDecOpt(base)
if @rep_in
#raise InvalidFormat,"Invalid numerical base" if base!=10
@@ -1049,11 +1056,11 @@
num.rounding = get_round
num.dec_pos += exp
return num
end
-
+
@@fmts = {
:def=>Fmt.new.freeze
}
# Returns the current default format.
def self.default
@@ -1074,11 +1081,11 @@
end
# Retrieves a named format from the repository.
def self.[](tag)
@@fmts[tag.to_sym]
end
-
+
protected
@@valid_properties = nil
ALIAS_PROPERTIES = {
:show_all_digits=>:all_digits,
@@ -1095,30 +1102,30 @@
def set!(properties={}) # :nodoc:
@@valid_properties ||= instance_variables.collect{|v| v[1..-1].to_sym}
-
+
properties.each do |k,v|
al = ALIAS_PROPERTIES[k]
if al
properties[al] = v
properties.delete k
elsif !@@valid_properties.include?(k)
raise InvalidOption, "Invalid option: #{k}"
end
end
-
+
- if properties[:grp_sep].nil? && !properties[:dec_sep].nil? && properties[:dec_sep]!=@dec_sep && properties[:dec_sep]==@grp_sep
- properties[:grp_sep] = properties[:dec_sep]=='.' ? ',' : '.'
+ if properties[:grp_sep].nil? && !properties[:dec_sep].nil? && properties[:dec_sep]!=@dec_sep && properties[:dec_sep]==@grp_sep
+ properties[:grp_sep] = properties[:dec_sep]=='.' ? ',' : '.'
end
if properties[:all_digits].nil? && (properties[:ndig] || properties[:mode])
ndig = properties[:ndig] || @ndig
mode = properties[:mode] || @mode
- properties[:all_digits] = ndig!=:exact && mode!=:gen
+ properties[:all_digits] = ndig!=:exact && mode!=:gen
end
if !properties[:all_digits].nil? && properties[:non_sig].nil?
properties[:non_sig] = '' unless properties[:all_digits]
elsif !properties[:non_sig].nil? && properties[:all_digits].nil?
@@ -1129,16 +1136,16 @@
base = properties[:base_radix] || @base_radix
uppercase = properties[:base_uppercase] || @base_uppercase
properties[:base_digits] = DigitsDef.base(base, !uppercase)
end
-
+
properties.each do |k,v|
instance_variable_set "@#{k}", v unless v.nil?
end
-
- self
+
+ self
end
def set(properties={}) # :nodoc:
self.dup.set!(properties)
end
@@ -1147,11 +1154,11 @@
nd = @ndig.kind_of?(Numeric) ? @ndig : [neutral.digits.length,10].max
if @@sci_fmt==:hp
puts " #{nd} ndpos=#{neutral.dec_pos} ndlen=#{neutral.digits.length}"
neutral.dec_pos>nd || ([neutral.digits.length,nd].min-neutral.dec_pos)>nd
else
- exp<-4 || exp>=nd
+ exp<-4 || exp>=nd
end
end
def getRepDecOpt(base=nil) # :nodoc:
rd_opt = RepDec::Opt.new
@@ -1160,11 +1167,11 @@
rd_opt.auto_rep = @rep_auto
rd_opt.dec_sep = @dec_sep
rd_opt.grp_sep = @grp_sep
rd_opt.grp = @grp
rd_opt.inf_txt = @inf_txt
- rd_opt.nan_txt = @nan_txt
+ rd_opt.nan_txt = @nan_txt
rd_opt.set_digits(get_base_digits(base))
# if base && (base != get_base_digits.radix)
# rd_opt.set_digits(get_base_digits(base))
# else
# rd_opt.set_digits get_base_digits
@@ -1195,31 +1202,31 @@
fmt.nio_write_formatted(neutral)
end
module ClassMethods
# This is the method available in all formattable clases
- # to read a formatted value from a text string into
+ # to read a formatted value from a text string into
# a value the class, according to the optional format passed.
def nio_read(txt,fmt=Fmt.default)
neutral = fmt.nio_read_formatted(txt)
- nio_read_neutral neutral
+ nio_read_neutral neutral
end
end
# Round a formattable object according to the rounding mode and
# precision of a format.
def nio_round(fmt=Fmt.default)
neutral = nio_write_neutral(fmt)
fmt.round! neutral
- self.class.nio_read_neutral neutral
+ self.class.nio_read_neutral neutral
end
def self.append_features(mod) # :nodoc:
super
mod.extend ClassMethods
end
-
+
end
Fmt[:comma] = Fmt.sep(',','.')
Fmt[:comma_th] = Fmt.sep(',','.',[3])
Fmt[:dot] = Fmt.sep('.',',')
@@ -1260,287 +1267,25 @@
module_function
def nio_float_to_bigdecimal(x,prec) # :nodoc:
if prec.nil?
- x = Fmt.convert(x,BigDecimal,:approx)
+ x = Fmt.convert(x,BigDecimal,:approx)
elsif prec==:exact
- x = Fmt.convert(x,BigDecimal,:exact)
+ x = Fmt.convert(x,BigDecimal,:exact)
else
x = BigDecimal(x.nio_write(Nio::Fmt.new.prec(prec,:sig)))
end
x
end
-
- module Clinger # :nodoc: all
- module_function
-
- 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)
-
- if e<0
- u,v,k = f,eb**(-e),0
- else
- u,v,k = f*(eb**e),1,0
- end
-
- loop do
- x = u.div(v)
- # overflow if k>=max_e
- if (x>=beta**(n-1) && x<beta**n) || k==min_e || k==max_e
- return ratio_float(u,v,k,round_mode,beta,n)
- elsif x<beta**(n-1)
- u *= beta
- k -= 1
- elsif x>=beta**n
- v *= beta
- k += 1
- end
- end
-
- end
- def ratio_float(u,v,k,round_mode,beta=Float::RADIX,n=Float::MANT_DIG)
- q,r = u.divmod(v)
- v_r = v-r
- z = Math.ldexp(q,k)
- if r<v_r
- z
- elsif r>v_r
- nextfloat z
- elsif (round_mode==:even && q.even?) || (round_mode==:zero)
- z
- else
- nextfloat z
- end
- end
-
- # valid only for non-negative x
- def nextfloat(x)
- f,e = Math.frexp(x)
- e = Float::MIN_EXP if f==0
- e = [Float::MIN_EXP,e].max
- dx = Math.ldexp(1,e-Float::MANT_DIG) #Math.ldexp(Math.ldexp(1.0,-Float::MANT_DIG),e)
- if f==(1.0 - Math.ldexp(1,-Float::MANT_DIG))
- x + dx*2
- else
- x + dx
- end
- end
-
- # valid only for non-negative x
- def prevfloat(x)
- f,e = Math.frexp(x)
- e = Float::MIN_EXP if f==0
- e = [Float::MIN_EXP,e].max
- dx = Math.ldexp(1,e-Float::MANT_DIG) #Math.ldexp(Math.ldexp(1.0,-Float::MANT_DIG),e)
- if e==Float::MIN_EXP || f!=0.5 #0.5==Math.ldexp(2**(bits-1),-Float::MANT_DIG)
- x - dx
- else
- x - dx/2 # x - Math.ldexp(Math.ldexp(1.0,-Float::MANT_DIG),e-1)
- end
- end
-
- end
-
- module BurgerDybvig # :nodoc: all
- module_function
-
- def float_to_digits(v,f,e,round_mode,min_e,p,b,_B)
-
- case round_mode
- when :even
- roundl = roundh = f.even?
- when :inf
- roundl = true
- roundh = false
- when :zero
- roundl = false
- roundh = true
- else
- # here we don't assume any rounding in the floating point numbers
- # the result is valid for any rounding but may produce more digits
- # than stricly necessary for specifica rounding modes.
- roundl = false
- roundh = false
- end
-
- if e >= 0
- if f != exptt(b,p-1)
- be = exptt(b,e)
- r,s,m_p,m_m,k = scale(f*be*2,2,be,be,0,_B,roundl ,roundh,v)
- else
- be = exptt(b,e)
- be1 = be*b
- r,s,m_p,m_m,k = scale(f*be1*2,b*2,be1,be,0,_B,roundl ,roundh,v)
- end
- else
- if e==min_e or f != exptt(b,p-1)
- r,s,m_p,m_m,k = scale(f*2,exptt(b,-e)*2,1,1,0,_B,roundl ,roundh,v)
- else
- r,s,m_p,m_m,k = scale(f*b*2,exptt(b,1-e)*2,b,1,0,_B,roundl ,roundh,v)
- end
- end
- [k]+generate(r,s,m_p,m_m,_B,roundl ,roundh)
- end
-
- def scale(r,s,m_p,m_m,k,_B,low_ok ,high_ok,v)
- return scale2(r,s,m_p,m_m,k,_B,low_ok ,high_ok) if v==0
- est = (logB(_B,v)-1E-10).ceil.to_i
- if est>=0
- fixup(r,s*exptt(_B,est),m_p,m_m,est,_B,low_ok,high_ok)
- else
- sc = exptt(_B,-est)
- fixup(r*sc,s,m_p*sc,m_m*sc,est,_B,low_ok,high_ok)
- end
- end
-
- def fixup(r,s,m_p,m_m,k,_B,low_ok,high_ok)
- if (high_ok ? (r+m_p >= s) : (r+m_p > s)) # too low?
- [r,s*_B,m_p,m_m,k+1]
- else
- [r,s,m_p,m_m,k]
- end
- end
-
- def scale2(r,s,m_p,m_m,k,_B,low_ok ,high_ok)
- loop do
- if (high_ok ? (r+m_p >= s) : (r+m_p > s)) # k is too low
- s *= _B
- k += 1
- elsif (high_ok ? ((r+m_p)*_B<s) : ((r+m_p)*_B<=s)) # k is too high
- r *= _B
- m_p *= _B
- m_m *= _B
- k -= 1
- else
- break
- end
- end
- [r,s,m_p,m_m,k]
- end
-
- def generate(r,s,m_p,m_m,_B,low_ok ,high_ok)
- list = []
- loop do
- d,r = (r*_B).divmod(s)
- m_p *= _B
- m_m *= _B
- tc1 = low_ok ? (r<=m_m) : (r<m_m)
- tc2 = high_ok ? (r+m_p >= s) : (r+m_p > s)
-
- if not tc1
- if not tc2
- list << d
- else
- list << d+1
- break
- end
- else
- if not tc2
- list << d
- break
- else
- if r*2 < s
- list << d
- break
- else
- list << d+1
- break
- end
- end
- end
-
- end
- list
- end
-
- $exptt_table = Array.new(326)
- (0...326).each{|i| $exptt_table[i]=10**i}
- def exptt(_B, k)
- if _B==10 && k>=0 && k<326
- $exptt_table[k]
- else
- _B**k
- end
- end
-
- $logB_table = Array.new(37)
- (2...37).each{|b| $logB_table[b]=1.0/Math.log(b)}
- def logB(_B, x)
- if _B>=2 && _B<37
- Math.log(x)*$logB_table[_B]
- else
- Math.log(x)/Math.log(_B)
- end
- end
-
- def float_to_digits_max(v,f,e,round_mode,min_e,p,b,_B)
-
- case round_mode
- when :even
- roundl = roundh = f.even?
- when :inf
- roundl = true
- roundh = false
- when :zero
- roundl = false
- roundh = true
- else
- # here we don't assume any rounding in the floating point numbers
- # the result is valid for any rounding but may produce more digits
- # than stricly necessary for specifica rounding modes.
- roundl = false
- roundh = false
- end
-
- if e >= 0
- if f != exptt(b,p-1)
- be = exptt(b,e)
- r,s,m_p,m_m,k = scale(f*be*2,2,be,be,0,_B,roundl ,roundh,v)
- else
- be = exptt(b,e)
- be1 = be*b
- r,s,m_p,m_m,k = scale(f*be1*2,b*2,be1,be,0,_B,roundl ,roundh,v)
- end
- else
- if e==min_e or f != exptt(b,p-1)
- r,s,m_p,m_m,k = scale(f*2,exptt(b,-e)*2,1,1,0,_B,roundl ,roundh,v)
- else
- r,s,m_p,m_m,k = scale(f*b*2,exptt(b,1-e)*2,b,1,0,_B,roundl ,roundh,v)
- end
- end
- [k]+generate_max(r,s,m_p,m_m,_B,roundl ,roundh)
- end
-
- def generate_max(r,s,m_p,m_m,_B,low_ok ,high_ok)
- list = [false]
- loop do
- d,r = (r*_B).divmod(s)
- m_p *= _B
- m_m *= _B
-
- list << d
-
- tc1 = low_ok ? (r<=m_m) : (r<m_m)
- tc2 = high_ok ? (r+m_p >= s) : (r+m_p > s)
-
- if tc1 && tc2
- list[0] = true if r*2 >= s
- break
- end
- end
- list
- end
-
- end
-
end
class Float
include Nio::Formattable
- def self.nio_read_neutral(neutral)
+ def self.nio_read_neutral(neutral)
x = nil
honor_rounding = true
if neutral.special?
@@ -1548,17 +1293,17 @@
when :nan
x = 0.0/0.0
when :inf
x = (neutral.sign=='-' ? -1.0 : +1.0)/0.0
end
- elsif neutral.rep_pos<neutral.digits.length
+ elsif neutral.rep_pos<neutral.digits.length
x,y = neutral.to_RepDec.getQ
x = Float(x)/y
else
- nd = neutral.base==10 ? Float::DIG : ((Float::MANT_DIG-1)*Math.log(2)/Math.log(neutral.base)).floor
+ nd = neutral.base==10 ? Float::DIG : ((Float::MANT_DIG-1)*Math.log(2)/Math.log(neutral.base)).floor
k = neutral.dec_pos-neutral.digits.length
if !honor_rounding && (neutral.digits.length<=nd && k.abs<=15)
x = neutral.digits.to_i(neutral.base).to_f
if k<0
x /= Float(neutral.base**-k)
@@ -1574,28 +1319,66 @@
elsif neutral.base.modulo(Float::RADIX)==0
f = neutral.digits.to_i(neutral.base)
e = neutral.dec_pos-neutral.digits.length
- rounding = neutral.rounding
+ rounding = case neutral.rounding
+ when :even
+ :half_even
+ when :zero
+ :half_down
+ when :inf
+ :half_up
+ when :truncate
+ :down
+ when :directed_up
+ :up
+ when :floor
+ :floor
+ when :ceil
+ :ceil
+ else
+ nil
+ end
- 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)
- x = -x if neutral.sign=='-'
+ reader = Flt::Support::Reader.new(:mode=>:fixed)
+ sign = neutral.sign == '-' ? -1 : +1
+ x = reader.read(Float.context, rounding, sign, f, e, neutral.base)
+ exact = reader.exact?
else
f = neutral.digits.to_i(neutral.base)
e = neutral.dec_pos-neutral.digits.length
- rounding = neutral.rounding
+ rounding = case neutral.rounding
+ when :even
+ :half_even
+ when :zero
+ :half_down
+ when :inf
+ :half_up
+ when :truncate
+ :down
+ when :directed_up
+ :up
+ when :floor
+ :floor
+ when :ceil
+ :ceil
+ else
+ nil
+ end
- 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)
- x = -x if neutral.sign=='-'
+ reader = Flt::Support::Reader.new(:mode=>:fixed)
+ sign = neutral.sign == '-' ? -1 : +1
+ x = reader.read(Float.context, rounding, sign, f, e, neutral.base)
+ exact = reader.exact?
end
end
-
+
return x
end
def nio_write_neutral(fmt)
neutral = Nio::NeutralNum.new
x = self
@@ -1607,26 +1390,26 @@
else
converted = false
if fmt.get_ndig==:exact && fmt.get_approx==:simplify
if x!=0
- q = x.nio_r(Nio::Tolerance.decimals(Float::DIG,:sig))
+ q = x.nio_r(Flt.Tolerance(Float::DIG, :sig_decimals))
if q!=0
neutral = q.nio_write_neutral(fmt)
converted = true if neutral.digits.length<=Float::DIG
end
end
elsif fmt.get_approx==:exact
neutral = x.nio_xr.nio_write_neutral(fmt)
converted = true
end
- if !converted
+ if !converted
if fmt.get_base==10 && false
txt = format "%.*e",Float::DECIMAL_DIG-1,x # note that spec. e output precision+1 significant digits
- sign = '+'
+ sign = '+'
if txt[0,1]=='-'
sign = '-'
txt = txt[1...txt.length]
end
exp = 0
@@ -1634,16 +1417,16 @@
exp_i = txt.index(x_char)
exp_i = txt.index(x_char.downcase) if exp_i===nil
if exp_i!=nil
exp = txt[exp_i+1...txt.length].to_i
- txt = txt[0...exp_i]
- end
+ txt = txt[0...exp_i]
+ end
dec_pos = txt.index '.'
if dec_pos==nil
- dec_pos = txt.length
+ dec_pos = txt.length
else
txt[dec_pos]=''
end
dec_pos += exp
neutral.set sign, txt, dec_pos, nil, fmt.get_base_digits(10), true, fmt.get_round
@@ -1652,11 +1435,10 @@
end
end
if !converted
sign = x<0 ? '-' : '+'
- x = -x if sign=='-'
f,e = Math.frexp(x)
if e < Float::MIN_EXP
# denormalized number
f = Math.ldexp(f,e-Float::MIN_EXP+Float::MANT_DIG)
e = Float::MIN_EXP-Float::MANT_DIG
@@ -1666,91 +1448,94 @@
e -= Float::MANT_DIG
end
f = f.to_i
inexact = true
- rounding = fmt.get_round
-
- if fmt.get_all_digits?
- # use as many digits as possible
- 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)
- inexact = :roundup if r
+ rounding = case fmt.get_round
+ when :even
+ :half_even
+ when :zero
+ :half_down
+ when :inf
+ :half_up
+ when :truncate
+ :down
+ when :directed_up
+ :up
+ when :floor
+ :floor
+ when :ceil
+ :ceil
else
- # use as few digits as possible
- 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)
+ nil
end
+
+
+ # Note: it is assumed that fmt will be used for for input too, otherwise
+ # rounding should be Float.context.rounding (input rounding for Float) rather than fmt.get_round (output)
+ formatter = Flt::Support::Formatter.new(Float::RADIX, Float::MIN_EXP-Float::MANT_DIG, fmt.get_base)
+ formatter.format(x, f, e, rounding, Float::MANT_DIG, fmt.get_all_digits?)
+ inexact = formatter.round_up if formatter.round_up.is_a?(Symbol)
+ dec_pos, digits = formatter.digits
txt = ''
digits.each{|d| txt << fmt.get_base_digits.digit_char(d)}
neutral.set sign, txt, dec_pos, nil, fmt.get_base_digits, inexact, fmt.get_round
end
end
-
+
return neutral
- end
-end
-
-class Numeric
- unless method_defined?(:even?)
- def even?
- self.modulo(2)==0
- end
end
- unless method_defined?(:odd?)
- def odd?
- self.modulo(2)!=0
- end
- end
end
class Integer
include Nio::Formattable
- def self.nio_read_neutral(neutral)
+ def self.nio_read_neutral(neutral)
x = nil
if neutral.special?
raise Nio::InvalidFormat,"Invalid integer numeral"
- elsif neutral.rep_pos<neutral.digits.length
+ elsif neutral.rep_pos<neutral.digits.length
return Rational.nio_read_neutral(neutral).to_i
else
digits = neutral.digits
if neutral.dec_pos <= 0
digits = '0'
elsif neutral.dec_pos <= digits.length
digits = digits[0...neutral.dec_pos]
else
- digits = digits + '0'*(neutral.dec_pos-digits.length)
+ digits = digits + '0'*(neutral.dec_pos-digits.length)
end
x = digits.to_i(neutral.base)
# this was formely needed because we didn't adust the digits
# if neutral.dec_pos != neutral.digits.length
# # with rational included, negative powers of ten are rational numbers
- # x = (x*((neutral.base)**(neutral.dec_pos-neutral.digits.length))).to_i
+ # x = (x*((neutral.base)**(neutral.dec_pos-neutral.digits.length))).to_i
# end
x = -x if neutral.sign=='-'
end
-
+
return x
end
def nio_write_neutral(fmt)
neutral = Nio::NeutralNum.new
x = self
sign = x<0 ? '-' : '+'
txt = x.abs.to_s(fmt.get_base)
- dec_pos = rep_pos = txt.length
+ dec_pos = rep_pos = txt.length
neutral.set sign, txt, dec_pos, nil, fmt.get_base_digits, false ,fmt.get_round
-
+
return neutral
end
end
class Rational
include Nio::Formattable
- def self.nio_read_neutral(neutral)
+ def self.nio_read_neutral(neutral)
x = nil
if neutral.special?
case neutral.special
when :nan
@@ -1759,19 +1544,19 @@
x = Rational((neutral.sign=='-' ? -1 : +1),0)
end
else
x = Rational(*neutral.to_RepDec.getQ)
end
-
+
return x
end
def nio_write_neutral(fmt)
neutral = Nio::NeutralNum.new
x = self
if x.denominator==0
- if x.numerator>0
+ if x.numerator>0
neutral.set_special(:inf)
elsif x.numerator<0
neutral.set_special(:inf,'-')
else
neutral.set_special(:nan)
@@ -1784,29 +1569,29 @@
rd = Nio::RepDec.new.setQ(x.numerator,x.denominator, opt)
end
neutral = rd.to_NeutralNum(fmt.get_base_digits)
neutral.rounding = fmt.get_round
end
-
+
return neutral
end
end
if defined? BigDecimal
class BigDecimal
include Nio::Formattable
- def self.nio_read_neutral(neutral)
+ def self.nio_read_neutral(neutral)
x = nil
if neutral.special?
case neutral.special
when :nan
x = BigDecimal('NaN') # BigDecimal("0")/0
when :inf
x = BigDecimal(neutral.sign=='-' ? '-1.0' : '+1.0')/0
end
- elsif neutral.rep_pos<neutral.digits.length
+ elsif neutral.rep_pos<neutral.digits.length
x,y = neutral.to_RepDec.getQ
x = BigDecimal(x.to_s)/y
else
@@ -1817,46 +1602,46 @@
str = neutral.sign
str += neutral.digits
str += "E#{(neutral.dec_pos-neutral.digits.length)}"
x = BigDecimal(str)
else
- x = BigDecimal(neutral.digits.to_i(neutral.base).to_s)
+ x = BigDecimal(neutral.digits.to_i(neutral.base).to_s)
x *= BigDecimal(neutral.base.to_s)**(neutral.dec_pos-neutral.digits.length)
x = -x if neutral.sign=='-'
end
end
-
+
return x
end
def nio_write_neutral(fmt)
neutral = Nio::NeutralNum.new
x = self
if x.nan?
neutral.set_special(:nan)
elsif x.infinite?
neutral.set_special(:inf, x<0 ? '-' : '+')
- else
+ else
converted = false
if fmt.get_ndig==:exact && fmt.get_approx==:simplify
prc = [x.precs[0],20].max
- neutral = x.nio_r(Nio::BigTolerance.decimals(prc,:sig)).nio_write_neutral(fmt)
+ neutral = x.nio_r(Flt.Tolerance(prc, :sig_decimals)).nio_write_neutral(fmt)
converted = true if neutral.digits.length<prc
elsif fmt.get_approx==:exact && fmt.get_base!=10
neutral = x.nio_xr.nio_write_neutral(fmt)
converted = true
end
- if !converted
- if fmt.get_base==10
+ if !converted
+ if fmt.get_base==10
# Don't use x.to_s because of bugs in BigDecimal in Ruby 1.9 revisions 20359-20797
# x.to_s('F') is not affected by that problem, but produces innecesary long strings
sgn,ds,b,e = x.split
txt = "#{sgn<0 ? '-' : ''}0.#{ds}E#{e}"
- sign = '+'
+ sign = '+'
if txt[0,1]=='-'
sign = '-'
txt = txt[1...txt.length]
end
exp = 0
@@ -1864,57 +1649,213 @@
exp_i = txt.index(x_char)
exp_i = txt.index(x_char.downcase) if exp_i===nil
if exp_i!=nil
exp = txt[exp_i+1...txt.length].to_i
- txt = txt[0...exp_i]
- end
+ txt = txt[0...exp_i]
+ end
dec_pos = txt.index '.'
if dec_pos==nil
- dec_pos = txt.length
+ dec_pos = txt.length
else
txt[dec_pos]=''
end
dec_pos += exp
neutral.set sign, txt, dec_pos, nil, fmt.get_base_digits(10), true, fmt.get_round
converted = true
end
- end
+ end
if !converted
- min_prec = 24
- min_exp = -1000
- s,f,b,e = x.split
- e -= f.size
- sign = s<0 ? '-' : '+'
- x = -x if sign=='-'
- f_i = f.to_i
- prc = [x.precs[0],min_prec].max
- f_i *= 10**(prc-f.size)
- e -= (prc-f.size)
+ x = Flt::DecNum(x.to_s)
+ min_exp = num_class.context.etiny
+ n = x.number_of_digits
+ s,f,e = x.split
+ b = num_class.radix
+ if s < 0
+ sign = '-'
+ else
+ sign = '+'
+ end
+ prc = x.number_of_digits
+ f = num_class.int_mult_radix_power(f, prc-n)
+ e -= (prc-n)
+
inexact = true
- rounding = fmt.get_round
-
- if fmt.get_all_digits?
- # use as many digits as possible
- dec_pos,r,*digits = Nio::BurgerDybvig::float_to_digits_max(x,f_i,e,rounding,[e,min_exp].min,prc,b,fmt.get_base)
- inexact = :roundup if r
+ rounding = case fmt.get_round
+ when :even
+ :half_even
+ when :zero
+ :half_down
+ when :inf
+ :half_up
+ when :truncate
+ :down
+ when :directed_up
+ :up
+ when :floor
+ :floor
+ when :ceil
+ :ceil
else
- # use as few digits as possible
- dec_pos,*digits = Nio::BurgerDybvig::float_to_digits(x,f_i,e,rounding,[e,min_exp].min,prc,b,fmt.get_base)
+ nil
end
+
+
+ # TODO: use Num#format instead
+ # Note: it is assumed that fmt will be used for for input too, otherwise
+ # rounding should be Float.context.rounding (input rounding for Float) rather than fmt.get_round (output)
+ formatter = Flt::Support::Formatter.new(num_class.radix, num_class.context.etiny, fmt.get_base)
+ formatter.format(x, f, e, rounding, prc, fmt.get_all_digits?)
+ inexact = formatter.round_up if formatter.round_up.is_a?(Symbol)
+ dec_pos,digits = formatter.digits
txt = ''
digits.each{|d| txt << fmt.get_base_digits.digit_char(d)}
neutral.set sign, txt, dec_pos, nil, fmt.get_base_digits, inexact, fmt.get_round
+
end
end
-
+
return neutral
end
end
+end
+
+class Flt::Num
+ include Nio::Formattable
+ def self.nio_read_neutral(neutral)
+ x = nil
+
+ if neutral.special?
+ case neutral.special
+ when :nan
+ x = num_class.nan
+ when :inf
+ x = num_class.infinity(neutral.sign=='-' ? '-1.0' : '+1.0')
+ end
+ elsif neutral.rep_pos<neutral.digits.length
+
+ # uses num_clas.context.precision TODO: ?
+ x = num_class.new Rational(*neutral.to_RepDec.getQ)
+
+ else
+ if neutral.base==num_class.radix
+ if neutral.base==10
+ str = neutral.sign
+ str += neutral.digits
+ str += "E#{(neutral.dec_pos-neutral.digits.length)}"
+ x = num_class.new(str)
+ else
+ f = neutral.digits.to_i(neutral.base)
+ e = neutral.dec_pos-neutral.digits.length
+ s = neutral.sign=='-' ? -1 : +1
+ x = num_class.Num(s, f, e)
+ end
+ else
+ # uses num_clas.context.precision TODO: ?
+ if num_class.respond_to?(:power)
+ x = num_class.Num(neutral.digits.to_i(neutral.base).to_s)
+ x *= num_class.Num(neutral.base.to_s)**(neutral.dec_pos-neutral.digits.length)
+ x = -x if neutral.sign=='-'
+ else
+
+ # uses num_clas.context.precision TODO: ?
+ x = num_class.new Rational(*neutral.to_RepDec.getQ)
+
+ end
+ end
+ end
+
+ return x
+ end
+ def nio_write_neutral(fmt)
+ neutral = Nio::NeutralNum.new
+ x = self
+
+ if x.nan?
+ neutral.set_special(:nan)
+ elsif x.infinite?
+ neutral.set_special(:inf, x<0 ? '-' : '+')
+ else
+ converted = false
+ if fmt.get_ndig==:exact && fmt.get_approx==:simplify
+
+ neutral = x.nio_r(Flt.Tolerance('0.5', :ulps)).nio_write_neutral(fmt)
+ # TODO: find better method to accept the conversion
+ prc = (fmt.get_base==num_class.radix) ? x.number_of_digits : x.coefficient.to_s(fmt.get_base).length
+ prc = [prc, 8].max
+ converted = true if neutral.digits.length<prc
+
+ elsif fmt.get_approx==:exact && fmt.get_base!=num_class.radix
+ # TODO: num_class.context(:precision=>fmt....
+ neutral = x.to_r.nio_write_neutral(fmt)
+ converted = true
+ end
+ if !converted
+ if fmt.get_base==num_class.radix
+ sign = x.sign==-1 ? '-' : '+'
+ txt = x.coefficient.to_s(fmt.get_base) # TODO: can use x.digits directly?
+ dec_pos = rep_pos = x.fractional_exponent
+ neutral.set sign, txt, dec_pos, nil, fmt.get_base_digits, false ,fmt.get_round
+ converted = true
+ end
+ end
+ if !converted
+
+ min_exp = num_class.context.etiny
+ n = x.number_of_digits
+ s,f,e = x.split
+ b = num_class.radix
+ if s < 0
+ sign = '-'
+ else
+ sign = '+'
+ end
+ prc = x.number_of_digits
+ f = num_class.int_mult_radix_power(f, prc-n)
+ e -= (prc-n)
+
+ inexact = true
+
+ rounding = case fmt.get_round
+ when :even
+ :half_even
+ when :zero
+ :half_down
+ when :inf
+ :half_up
+ when :truncate
+ :down
+ when :directed_up
+ :up
+ when :floor
+ :floor
+ when :ceil
+ :ceil
+ else
+ nil
+ end
+
+
+ # TODO: use Num#format instead
+ # Note: it is assumed that fmt will be used for for input too, otherwise
+ # rounding should be Float.context.rounding (input rounding for Float) rather than fmt.get_round (output)
+ formatter = Flt::Support::Formatter.new(num_class.radix, num_class.context.etiny, fmt.get_base)
+ formatter.format(x, f, e, rounding, prc, fmt.get_all_digits?)
+ inexact = formatter.round_up if formatter.round_up.is_a?(Symbol)
+ dec_pos,digits = formatter.digits
+ txt = ''
+ digits.each{|d| txt << fmt.get_base_digits.digit_char(d)}
+ neutral.set sign, txt, dec_pos, nil, fmt.get_base_digits, inexact, fmt.get_round
+
+ end
+ end
+
+ return neutral
+ end
end