[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]