mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
add tests for float format.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@15699 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
8c889459cf
commit
579f16d985
1 changed files with 263 additions and 8 deletions
|
@ -109,11 +109,12 @@ class TestSprintfComb < Test::Unit::TestCase
|
|||
VS.reverse!
|
||||
|
||||
def combination(*args, &b)
|
||||
#AllPairs.exhaustive_each(*args, &b)
|
||||
AllPairs.each(*args, &b)
|
||||
end
|
||||
|
||||
def emu(format, v)
|
||||
/\A%( )?(\#)?(\+)?(-)?(0)?(\d+)?(?:\.(\d+))?(.)\z/ =~ format
|
||||
def emu_int(format, v)
|
||||
/\A%( )?(\#)?(\+)?(-)?(0)?(\d+)?(?:\.(\d*))?(.)\z/ =~ format
|
||||
sp = $1
|
||||
hs = $2
|
||||
pl = $3
|
||||
|
@ -263,23 +264,20 @@ class TestSprintfComb < Test::Unit::TestCase
|
|||
str
|
||||
end
|
||||
|
||||
def test_format
|
||||
def test_format_integer
|
||||
combination(
|
||||
%w[b d o X x],
|
||||
[nil, 0, 5, 20],
|
||||
[nil, 0, 8, 20],
|
||||
["", ".", ".0", ".8", ".20"],
|
||||
['', ' '],
|
||||
['', '#'],
|
||||
['', '+'],
|
||||
['', '-'],
|
||||
['', '0']) {|type, width, precision, sp, hs, pl, mi, zr|
|
||||
if precision
|
||||
precision = ".#{precision}"
|
||||
end
|
||||
format = "%#{sp}#{hs}#{pl}#{mi}#{zr}#{width}#{precision}#{type}"
|
||||
VS.each {|v|
|
||||
r = sprintf format, v
|
||||
e = emu format, v
|
||||
e = emu_int format, v
|
||||
if true
|
||||
assert_equal(e, r, "sprintf(#{format.dump}, #{v})")
|
||||
else
|
||||
|
@ -290,4 +288,261 @@ class TestSprintfComb < Test::Unit::TestCase
|
|||
}
|
||||
}
|
||||
end
|
||||
|
||||
FLOAT_VALUES = [
|
||||
-1e100,
|
||||
-123456789.0,
|
||||
-1.0,
|
||||
-0.0,
|
||||
0.0,
|
||||
0.01,
|
||||
1/3.0,
|
||||
1.0,
|
||||
2.0,
|
||||
9.99999999,
|
||||
123456789.0,
|
||||
1e100,
|
||||
Float::MAX,
|
||||
Float::MIN,
|
||||
Float::EPSILON,
|
||||
1+Float::EPSILON,
|
||||
#1-Float::EPSILON/2,
|
||||
10 + Float::EPSILON*10,
|
||||
10 - Float::EPSILON*5,
|
||||
1.0/0.0,
|
||||
-1.0/0.0,
|
||||
0.0/0.0,
|
||||
]
|
||||
|
||||
def split_float10(v)
|
||||
if v == 0
|
||||
if 1/v < 0
|
||||
sign = -1
|
||||
v = -v
|
||||
else
|
||||
sign = 1
|
||||
end
|
||||
else
|
||||
if v < 0
|
||||
sign = -1
|
||||
v = -v
|
||||
else
|
||||
sign = 1
|
||||
end
|
||||
end
|
||||
exp = 0
|
||||
int = v.floor
|
||||
v -= int
|
||||
while v != 0
|
||||
v *= 2
|
||||
int *= 2
|
||||
i = v.floor
|
||||
v -= i
|
||||
int += i
|
||||
exp -= 1
|
||||
end
|
||||
int *= 5 ** (-exp)
|
||||
[sign, int, exp]
|
||||
end
|
||||
|
||||
def emu_e(sp, hs, pl, mi, zr, width, precision, type, v, sign, int, exp)
|
||||
precision = 6 unless precision
|
||||
if int == 0
|
||||
if precision == 0 && !hs
|
||||
result = "0#{type}+00"
|
||||
else
|
||||
result = "0." + "0" * precision + "#{type}+00"
|
||||
end
|
||||
else
|
||||
if int < 10**precision
|
||||
int *= 10**precision
|
||||
exp -= precision
|
||||
end
|
||||
digits = int.to_s.length
|
||||
discard = digits - (precision+1)
|
||||
if discard != 0
|
||||
q, r = int.divmod(10**discard)
|
||||
if r < 10**discard / 2
|
||||
int = q
|
||||
exp += discard
|
||||
elsif (q+1).to_s.length == q.to_s.length
|
||||
int = q+1
|
||||
exp += discard
|
||||
else
|
||||
discard += 1
|
||||
q, r = int.divmod(10**discard)
|
||||
int = q+1
|
||||
exp += discard
|
||||
end
|
||||
end
|
||||
ints = int.to_s
|
||||
frac = ints[1..-1]
|
||||
result = ints[0,1]
|
||||
e = exp + frac.length
|
||||
if precision != 0 || hs
|
||||
result << "."
|
||||
if precision != 0
|
||||
result << frac
|
||||
end
|
||||
end
|
||||
result << type
|
||||
if e == 0
|
||||
if v.abs < 1
|
||||
result << '-00' # glibc 2.7 causes '+00'
|
||||
else
|
||||
result << '+00'
|
||||
end
|
||||
else
|
||||
result << sprintf("%+03d", e)
|
||||
end
|
||||
result
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def emu_f(sp, hs, pl, mi, zr, width, precision, type, sign, int, exp)
|
||||
precision = 6 unless precision
|
||||
if int == 0
|
||||
if precision == 0 && !hs
|
||||
result = '0'
|
||||
else
|
||||
result = '0.' + '0' * precision
|
||||
end
|
||||
else
|
||||
if -precision < exp
|
||||
int *= 10 ** (precision+exp)
|
||||
exp = -precision
|
||||
end
|
||||
if exp < -precision
|
||||
discard = -exp - precision
|
||||
q, r = int.divmod(10**discard)
|
||||
if 10**discard / 2 <= r
|
||||
q += 1
|
||||
end
|
||||
int = q
|
||||
exp += discard
|
||||
end
|
||||
result = int.to_s
|
||||
if result.length <= precision
|
||||
result = '0' * (precision+1 - result.length) + result
|
||||
end
|
||||
if precision != 0 || hs
|
||||
if precision == 0
|
||||
result << '.'
|
||||
else
|
||||
result[-precision,0] = '.'
|
||||
end
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def emu_float(format, v)
|
||||
/\A%( )?(\#)?(\+)?(-)?(0)?(\d+)?(?:\.(\d*))?(.)\z/ =~ format
|
||||
sp = $1
|
||||
hs = $2
|
||||
pl = $3
|
||||
mi = $4
|
||||
zr = $5
|
||||
width = $6
|
||||
precision = $7
|
||||
type = $8
|
||||
width = width.to_i if width
|
||||
precision = precision.to_i if precision
|
||||
|
||||
zr = nil if mi && zr
|
||||
|
||||
if v.infinite?
|
||||
sign = v < 0 ? -1 : 1
|
||||
int = :inf
|
||||
hs = zr = nil
|
||||
elsif v.nan?
|
||||
sign = 1
|
||||
int = :nan
|
||||
hs = zr = nil
|
||||
else
|
||||
sign, int, exp = split_float10(v)
|
||||
end
|
||||
|
||||
if sign < 0
|
||||
sign = '-'
|
||||
elsif sign == 0
|
||||
sign = ''
|
||||
elsif pl
|
||||
sign = '+'
|
||||
elsif sp
|
||||
sign = ' '
|
||||
else
|
||||
sign = ''
|
||||
end
|
||||
|
||||
if v.nan?
|
||||
result = 'NaN'
|
||||
elsif v.infinite?
|
||||
result = 'Inf'
|
||||
else
|
||||
case type
|
||||
when /[eE]/
|
||||
result = emu_e(sp, hs, pl, mi, zr, width, precision, type, v, sign, int, exp)
|
||||
when /f/
|
||||
result = emu_f(sp, hs, pl, mi, zr, width, precision, type, sign, int, exp)
|
||||
when /[gG]/
|
||||
precision = 6 unless precision
|
||||
precision = 1 if precision == 0
|
||||
r = emu_e(sp, hs, pl, mi, zr, width, precision-1, type.tr('gG', 'eE'), v, sign, int, exp)
|
||||
/[eE]([+-]\d+)/ =~ r
|
||||
e = $1.to_i
|
||||
if e < -4 || precision <= e
|
||||
result = r
|
||||
else
|
||||
result = emu_f(sp, hs, pl, mi, zr, width, precision-1-e, type, sign, int, exp)
|
||||
end
|
||||
result.sub!(/\.[0-9]*/) { $&.sub(/\.?0*\z/, '') } if !hs
|
||||
else
|
||||
raise "unexpected type: #{type}"
|
||||
end
|
||||
end
|
||||
|
||||
pad = ''
|
||||
if width && sign.length + result.length < width
|
||||
if zr
|
||||
pad = '0' * (width - sign.length - result.length)
|
||||
else
|
||||
pad = ' ' * (width - sign.length - result.length)
|
||||
end
|
||||
end
|
||||
if mi
|
||||
sign + result + pad
|
||||
elsif zr
|
||||
sign + pad + result
|
||||
else
|
||||
pad + sign + result
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def test_format_float
|
||||
combination(
|
||||
%w[e E f g G],
|
||||
[nil, 0, 5, 20],
|
||||
["", ".", ".0", ".8", ".20", ".200"],
|
||||
['', ' '],
|
||||
['', '#'],
|
||||
['', '+'],
|
||||
['', '-'],
|
||||
['', '0']) {|type, width, precision, sp, hs, pl, mi, zr|
|
||||
format = "%#{sp}#{hs}#{pl}#{mi}#{zr}#{width}#{precision}#{type}"
|
||||
FLOAT_VALUES.each {|v|
|
||||
r = sprintf format, v
|
||||
e = emu_float format, v
|
||||
if true
|
||||
assert_equal(e, r, "sprintf(#{format.dump}, #{'%.20g' % v})")
|
||||
else
|
||||
if e != r
|
||||
puts "#{e.dump}\t#{r.dump}\tsprintf(#{format.dump}, #{'%.20g' % v})"
|
||||
end
|
||||
end
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue