ruby-changes:35506
From: nobu <ko1@a...>
Date: Mon, 15 Sep 2014 08:13:47 +0900 (JST)
Subject: [ruby-changes:35506] nobu:r47588 (trunk): sprintf.c: improve rational 'f' format
nobu 2014-09-15 08:13:36 +0900 (Mon, 15 Sep 2014) New Revision: 47588 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=47588 Log: sprintf.c: improve rational 'f' format * sprintf.c (rb_str_format): rational 'f' format works for more values. [fix GH-717] Modified files: trunk/ChangeLog trunk/sprintf.c trunk/test/ruby/test_sprintf.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 47587) +++ ChangeLog (revision 47588) @@ -1,3 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Mon Sep 15 08:13:40 2014 Matthew Draper <matthew@t...> + + * sprintf.c (rb_str_format): rational 'f' format works for more + values. [fix GH-717] + Sun Sep 14 16:57:27 2014 Eric Wong <e@8...> * template/vm.inc.tmpl: "insns.c" => "insns.def" Index: sprintf.c =================================================================== --- sprintf.c (revision 47587) +++ sprintf.c (revision 47588) @@ -1027,6 +1027,7 @@ rb_str_format(int argc, const VALUE *arg https://github.com/ruby/ruby/blob/trunk/sprintf.c#L1027 VALUE val = GETARG(), num, den; int sign = (flags&FPLUS) ? 1 : 0, zero = 0; long len; + int i, done = 0, prefix = 0; if (!RB_TYPE_P(val, T_RATIONAL)) { nextvalue = val; goto float_value; @@ -1062,28 +1063,53 @@ rb_str_format(int argc, const VALUE *arg https://github.com/ruby/ruby/blob/trunk/sprintf.c#L1063 if (sign || (flags&FSPACE)) ++len; if (prec > 0) ++len; /* period */ CHECK(len > width ? len : width); - if (width > len) { - width -= (int)len; - if (!(flags&FMINUS)) { - FILL(' ', width); - width = 0; - } + if (sign || (flags&FSPACE)) { + buf[blen++] = sign > 0 ? '+' : sign < 0 ? '-' : ' '; + prefix++; + done++; } - if (sign || (flags&FSPACE)) buf[blen++] = sign > 0 ? '+' : sign < 0 ? '-' : ' '; len = RSTRING_LEN(val) + zero; t = RSTRING_PTR(val); - if (len > prec) + if (len > prec) { memcpy(&buf[blen], t, len - prec); - else + blen += len - prec; + done += len - prec; + } + else { buf[blen++] = '0'; - blen += len - prec; - if (prec > 0) buf[blen++] = '.'; - if (zero) FILL('0', zero); + done++; + } + if (prec > 0) { + buf[blen++] = '.'; + done++; + } + if (zero) { + FILL('0', zero); + done += zero; + } + else if (prec > len) { + FILL('0', prec - len); + memcpy(&buf[blen], t, len); + blen += len; + done += prec; + } else if (prec > 0) { memcpy(&buf[blen], t + len - prec, prec); blen += prec; + done += prec; + } + if ((flags & FWIDTH) && width > done) { + if (!(flags&FMINUS)) { + int shifting = (flags&FZERO) ? done - prefix : done; + for (i = 1; i <= shifting; i++) + buf[width - i] = buf[done - i]; + blen -= shifting; + FILL((flags&FZERO) ? '0' : ' ', width - done); + blen += shifting; + } else { + FILL(' ', width - done); + } } - if (width > 0) FILL(' ', width); RB_GC_GUARD(val); break; } Index: test/ruby/test_sprintf.rb =================================================================== --- test/ruby/test_sprintf.rb (revision 47587) +++ test/ruby/test_sprintf.rb (revision 47588) @@ -150,8 +150,22 @@ class TestSprintf < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_sprintf.rb#L150 def test_rational assert_match(/\A0\.10+\z/, sprintf("%.60f", 0.1r)) + assert_match(/\A0\.010+\z/, sprintf("%.60f", 0.01r)) + assert_match(/\A0\.0010+\z/, sprintf("%.60f", 0.001r)) assert_match(/\A0\.3+\z/, sprintf("%.60f", 1/3r)) assert_match(/\A1\.20+\z/, sprintf("%.60f", 1.2r)) + + 0.upto(9) do |len| + -1.upto(9) do |prec| + ['', '+', '-', ' ', '0', '+0', '-0', ' 0', '+ ', '- ', '+ 0', '- 0'].each do |flags| + fmt = "%#{flags}#{len > 0 ? len : ''}#{prec >= 0 ? ".#{prec}" : ''}f" + [0, 0.1, 0.01, 0.001, 1.001, 100.0, 100.001, 10000000000.0, 0.00000000001, 1/3r, 2/3r, 1.2r, 10r].each do |num| + assert_equal(sprintf(fmt, num.to_f), sprintf(fmt, num.to_r), "sprintf(#{fmt.inspect}, #{num.inspect}.to_r)") + assert_equal(sprintf(fmt, -num.to_f), sprintf(fmt, -num.to_r), "sprintf(#{fmt.inspect}, #{(-num).inspect}.to_r)") if num > 0 + end + end + end + end end def test_hash -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/