1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

sprintf.c: rational 'f' format

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

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47214 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2014-08-18 08:06:48 +00:00
parent 22892ca6c2
commit 1d196e0d2b
4 changed files with 78 additions and 1 deletions

View file

@ -1,3 +1,8 @@
Mon Aug 18 17:06:27 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
* 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@gmail.com>
* spec/default.mspec: use 2.2 definition.

View file

@ -771,7 +771,7 @@ ruby.$(OBJEXT): {$(VPATH)}ruby.c $(RUBY_H_INCLUDES) {$(VPATH)}util.h \
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) \

View file

@ -15,6 +15,7 @@
#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 *argv, VALUE fmt)
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;

View file

@ -148,6 +148,11 @@ class TestSprintf < Test::Unit::TestCase
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))