summaryrefslogtreecommitdiff
path: root/trunk/test/ruby/test_sprintf_comb.rb
diff options
context:
space:
mode:
authoryugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-08-25 15:02:05 +0000
committeryugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-08-25 15:02:05 +0000
commit0dc342de848a642ecce8db697b8fecd83a63e117 (patch)
tree2b7ed4724aff1f86073e4740134bda9c4aac1a39 /trunk/test/ruby/test_sprintf_comb.rb
parentef70cf7138ab8034b5b806f466e4b484b24f0f88 (diff)
added tag v1_9_0_4
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/tags/v1_9_0_4@18845 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'trunk/test/ruby/test_sprintf_comb.rb')
-rw-r--r--trunk/test/ruby/test_sprintf_comb.rb548
1 files changed, 548 insertions, 0 deletions
diff --git a/trunk/test/ruby/test_sprintf_comb.rb b/trunk/test/ruby/test_sprintf_comb.rb
new file mode 100644
index 0000000000..8b2c1a7e05
--- /dev/null
+++ b/trunk/test/ruby/test_sprintf_comb.rb
@@ -0,0 +1,548 @@
+require 'test/unit'
+require_relative 'allpairs'
+
+class TestSprintfComb < Test::Unit::TestCase
+ VS = [
+ #-0x1000000000000000000000000000000000000000000000002,
+ #-0x1000000000000000000000000000000000000000000000001,
+ #-0x1000000000000000000000000000000000000000000000000,
+ #-0xffffffffffffffffffffffffffffffffffffffffffffffff,
+ #-0x1000000000000000000000002,
+ #-0x1000000000000000000000001,
+ #-0x1000000000000000000000000,
+ #-0xffffffffffffffffffffffff,
+ -0x10000000000000002,
+ -0x10000000000000001,
+ -0x10000000000000000,
+ -0xffffffffffffffff,
+ -0x4000000000000002,
+ -0x4000000000000001,
+ -0x4000000000000000,
+ -0x3fffffffffffffff,
+ -0x100000002,
+ -0x100000001,
+ -0x100000000,
+ -0xffffffff,
+ #-0xc717a08d, # 0xc717a08d * 0x524b2245 = 0x4000000000000001
+ -0x80000002,
+ -0x80000001,
+ -0x80000000,
+ -0x7fffffff,
+ #-0x524b2245,
+ -0x40000002,
+ -0x40000001,
+ -0x40000000,
+ -0x3fffffff,
+ #-0x10002,
+ #-0x10001,
+ #-0x10000,
+ #-0xffff,
+ #-0x8101, # 0x8101 * 0x7f01 = 0x40000001
+ #-0x8002,
+ #-0x8001,
+ #-0x8000,
+ #-0x7fff,
+ #-0x7f01,
+ #-65,
+ #-64,
+ #-63,
+ #-62,
+ #-33,
+ #-32,
+ #-31,
+ #-30,
+ -3,
+ -2,
+ -1,
+ 0,
+ 1,
+ 2,
+ 3,
+ #30,
+ #31,
+ #32,
+ #33,
+ #62,
+ #63,
+ #64,
+ #65,
+ #0x7f01,
+ #0x7ffe,
+ #0x7fff,
+ #0x8000,
+ #0x8001,
+ #0x8101,
+ #0xfffe,
+ #0xffff,
+ #0x10000,
+ #0x10001,
+ 0x3ffffffe,
+ 0x3fffffff,
+ 0x40000000,
+ 0x40000001,
+ #0x524b2245,
+ 0x7ffffffe,
+ 0x7fffffff,
+ 0x80000000,
+ 0x80000001,
+ #0xc717a08d,
+ 0xfffffffe,
+ 0xffffffff,
+ 0x100000000,
+ 0x100000001,
+ 0x3ffffffffffffffe,
+ 0x3fffffffffffffff,
+ 0x4000000000000000,
+ 0x4000000000000001,
+ 0xfffffffffffffffe,
+ 0xffffffffffffffff,
+ 0x10000000000000000,
+ 0x10000000000000001,
+ #0xffffffffffffffffffffffff,
+ #0x1000000000000000000000000,
+ #0x1000000000000000000000001,
+ #0xffffffffffffffffffffffffffffffffffffffffffffffff,
+ #0x1000000000000000000000000000000000000000000000000,
+ #0x1000000000000000000000000000000000000000000000001
+ ]
+ VS.reverse!
+
+ def combination(*args, &b)
+ #AllPairs.exhaustive_each(*args, &b)
+ AllPairs.each(*args, &b)
+ end
+
+ def emu_int(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
+ prefix = ''
+
+ zr = nil if precision
+
+ zr = nil if mi && zr
+
+ case type
+ when 'b'
+ radix = 2
+ digitmap = {0 => '0', 1 => '1'}
+ complement = !pl && !sp
+ prefix = '0b' if hs && v != 0
+ when 'd'
+ radix = 10
+ digitmap = {}
+ 10.times {|i| digitmap[i] = i.to_s }
+ complement = false
+ when 'o'
+ radix = 8
+ digitmap = {}
+ 8.times {|i| digitmap[i] = i.to_s }
+ complement = !pl && !sp
+ when 'X'
+ radix = 16
+ digitmap = {}
+ 16.times {|i| digitmap[i] = i.to_s(16).upcase }
+ complement = !pl && !sp
+ prefix = '0X' if hs && v != 0
+ when 'x'
+ radix = 16
+ digitmap = {}
+ 16.times {|i| digitmap[i] = i.to_s(16) }
+ complement = !pl && !sp
+ prefix = '0x' if hs && v != 0
+ else
+ raise "unexpected type: #{type.inspect}"
+ end
+
+ digits = []
+ abs = v.abs
+ sign = ''
+ while 0 < abs
+ digits << (abs % radix)
+ abs /= radix
+ end
+
+ if v < 0
+ if complement
+ digits.map! {|d| radix-1 - d }
+ carry = 1
+ digits.each_index {|i|
+ digits[i] += carry
+ carry = 0
+ if radix <= digits[i]
+ digits[i] -= radix
+ carry = 1
+ end
+ }
+ if digits.last != radix-1
+ digits << (radix-1)
+ end
+ sign = '..'
+ else
+ sign = '-'
+ end
+ else
+ if pl
+ sign = '+'
+ elsif sp
+ sign = ' '
+ end
+ end
+
+ dlen = digits.length
+ dlen += 2 if sign == '..'
+
+ if v < 0 && complement
+ d = radix - 1
+ else
+ d = 0
+ end
+ if precision
+ if dlen < precision
+ (precision - dlen).times {
+ digits << d
+ }
+ end
+ else
+ if dlen == 0
+ digits << d
+ end
+ end
+ if type == 'o' && hs
+ if digits.empty? || digits.last != d
+ digits << d
+ end
+ end
+
+ digits.reverse!
+
+ str = digits.map {|d| digitmap[d] }.join
+
+ pad = ''
+ nlen = prefix.length + sign.length + str.length
+ if width && nlen < width
+ len = width - nlen
+ if zr
+ if complement && v < 0
+ pad = digitmap[radix-1] * len
+ else
+ pad = '0' * len
+ end
+ else
+ pad = ' ' * len
+ end
+ end
+
+ if / / =~ pad
+ if sign == '..'
+ str = prefix + sign + str
+ else
+ str = sign + prefix + str
+ end
+ if mi
+ str = str + pad
+ else
+ str = pad + str
+ end
+ else
+ if sign == '..'
+ str = prefix + sign + pad + str
+ else
+ str = sign + prefix + pad + str
+ end
+ end
+
+ str
+ end
+
+ def test_format_integer
+ combination(
+ %w[b d o X x],
+ [nil, 0, 5, 20],
+ ["", ".", ".0", ".8", ".20"],
+ ['', ' '],
+ ['', '#'],
+ ['', '+'],
+ ['', '-'],
+ ['', '0']) {|type, width, precision, sp, hs, pl, mi, zr|
+ format = "%#{sp}#{hs}#{pl}#{mi}#{zr}#{width}#{precision}#{type}"
+ VS.each {|v|
+ r = sprintf format, v
+ e = emu_int format, v
+ if true
+ assert_equal(e, r, "sprintf(#{format.dump}, #{v})")
+ else
+ if e != r
+ puts "#{e.dump}\t#{r.dump}\tsprintf(#{format.dump}, #{v})"
+ end
+ end
+ }
+ }
+ end
+
+ FLOAT_VALUES = [
+ -1e100,
+ -123456789.0,
+ -1.0,
+ -0.0,
+ 0.0,
+ 0.01,
+ 1/3.0,
+ 2/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