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

ruby-changes:35132

From: nobu <ko1@a...>
Date: Mon, 18 Aug 2014 17:07:00 +0900 (JST)
Subject: [ruby-changes:35132] nobu:r47214 (trunk): sprintf.c: rational 'f' format

nobu	2014-08-18 17:06:48 +0900 (Mon, 18 Aug 2014)

  New Revision: 47214

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=47214

  Log:
    sprintf.c: rational 'f' format
    
    * sprintf.c (rb_str_format): support rational 'f' format.
      [ruby-core:64382] [Bug #10136]

  Modified files:
    trunk/ChangeLog
    trunk/common.mk
    trunk/sprintf.c
    trunk/test/ruby/test_sprintf.rb
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 47213)
+++ ChangeLog	(revision 47214)
@@ -1,3 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Mon Aug 18 17:06:27 2014  Nobuyoshi Nakada  <nobu@r...>
+
+	* sprintf.c (rb_str_format): support rational 'f' format.
+	  [ruby-core:64382] [Bug #10136]
+
 Mon Aug 18 08:03:46 2014  SHIBATA Hiroshi  <shibata.hiroshi@g...>
 
 	* spec/default.mspec: use 2.2 definition.
Index: common.mk
===================================================================
--- common.mk	(revision 47213)
+++ common.mk	(revision 47214)
@@ -771,7 +771,7 @@ ruby.$(OBJEXT): {$(VPATH)}ruby.c $(RUBY_ https://github.com/ruby/ruby/blob/trunk/common.mk#L771
 safe.$(OBJEXT): {$(VPATH)}safe.c $(RUBY_H_INCLUDES) $(VM_CORE_H_INCLUDES) {$(VPATH)}vm_opts.h {$(VPATH)}internal.h
 signal.$(OBJEXT): {$(VPATH)}signal.c $(RUBY_H_INCLUDES) \
   $(VM_CORE_H_INCLUDES) {$(VPATH)}vm_opts.h {$(VPATH)}internal.h {$(VPATH)}ruby_atomic.h {$(VPATH)}eval_intern.h
-sprintf.$(OBJEXT): {$(VPATH)}sprintf.c $(RUBY_H_INCLUDES) {$(VPATH)}re.h \
+sprintf.$(OBJEXT): {$(VPATH)}sprintf.c $(RUBY_H_INCLUDES) {$(VPATH)}re.h {$(VPATH)}id.h \
   {$(VPATH)}regex.h {$(VPATH)}vsnprintf.c $(ENCODING_H_INCLUDES) {$(VPATH)}internal.h
 st.$(OBJEXT): {$(VPATH)}st.c $(RUBY_H_INCLUDES)
 strftime.$(OBJEXT): {$(VPATH)}strftime.c $(RUBY_H_INCLUDES) \
Index: sprintf.c
===================================================================
--- sprintf.c	(revision 47213)
+++ sprintf.c	(revision 47214)
@@ -15,6 +15,7 @@ https://github.com/ruby/ruby/blob/trunk/sprintf.c#L15
 #include "ruby/re.h"
 #include "ruby/encoding.h"
 #include "internal.h"
+#include "id.h"
 #include <math.h>
 #include <stdarg.h>
 
@@ -1022,12 +1023,78 @@ rb_str_format(int argc, const VALUE *arg https://github.com/ruby/ruby/blob/trunk/sprintf.c#L1023
 	    break;
 
 	  case 'f':
+	    {
+		VALUE val = GETARG(), num, den;
+		int sign = (flags&FPLUS) ? 1 : 0, zero = 0;
+		long len;
+		if (!RB_TYPE_P(val, T_RATIONAL)) {
+		    nextvalue = val;
+		    goto float_value;
+		}
+		if (!(flags&FPREC)) prec = default_float_precision;
+		den = rb_rational_den(val);
+		num = rb_rational_num(val);
+		if (FIXNUM_P(num)) {
+		    if ((SIGNED_VALUE)num < 0) {
+			long n = -FIX2LONG(num);
+			num = LONG2FIX(n);
+			sign = -1;
+		    }
+		}
+		else if (rb_num_negative_p(num)) {
+		    sign = -1;
+		    num = rb_funcallv(num, idUMinus, 0, 0);
+		}
+		if (den != INT2FIX(1) && prec > 1) {
+		    const ID idDiv = rb_intern("div");
+		    VALUE p10 = rb_int_positive_pow(10, prec);
+		    VALUE den_2 = rb_funcall(den, idDiv, 1, INT2FIX(2));
+		    num = rb_funcallv(num, '*', 1, &p10);
+		    num = rb_funcallv(num, '+', 1, &den_2);
+		    num = rb_funcallv(num, idDiv, 1, &den);
+		}
+		else if (prec >= 0) {
+		    zero = prec;
+		}
+		val = rb_obj_as_string(num);
+		len = RSTRING_LEN(val) + zero;
+		if (prec >= len) ++len; /* integer part 0 */
+		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 ? '-' : ' ';
+		len = RSTRING_LEN(val) + zero;
+		t = RSTRING_PTR(val);
+		if (len > prec)
+		    memcpy(&buf[blen], t, len - prec);
+		else
+		    buf[blen++] = '0';
+		blen += len - prec;
+		if (prec > 0) buf[blen++] = '.';
+		if (zero) FILL('0', zero);
+		else if (prec > 0) {
+		    memcpy(&buf[blen], t + len - prec, prec);
+		    blen += prec;
+		}
+		if (width > 0) FILL(' ', width);
+		RB_GC_GUARD(val);
+		break;
+	    }
 	  case 'g':
 	  case 'G':
 	  case 'e':
 	  case 'E':
+	    /* TODO: rational support */
 	  case 'a':
 	  case 'A':
+	  float_value:
 	    {
 		VALUE val = GETARG();
 		double fval;
Index: test/ruby/test_sprintf.rb
===================================================================
--- test/ruby/test_sprintf.rb	(revision 47213)
+++ test/ruby/test_sprintf.rb	(revision 47214)
@@ -148,6 +148,11 @@ class TestSprintf < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_sprintf.rb#L148
     assert_equal(" Inf", sprintf("% e", inf), '[ruby-dev:34002]')
   end
 
+  def test_rational
+    assert_match(/\A0\.10+\z/, sprintf("%.60f", 0.1r))
+    assert_match(/\A0\.3+\z/, sprintf("%.60f", 1/3r))
+  end
+
   def test_hash
     options = {:capture=>/\d+/}
     assert_equal("with options {:capture=>/\\d+/}", sprintf("with options %p" % options))

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

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