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:
parent
22892ca6c2
commit
1d196e0d2b
4 changed files with 78 additions and 1 deletions
|
@ -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>
|
Mon Aug 18 08:03:46 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
|
||||||
|
|
||||||
* spec/default.mspec: use 2.2 definition.
|
* spec/default.mspec: use 2.2 definition.
|
||||||
|
|
|
@ -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
|
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) \
|
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
|
$(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
|
{$(VPATH)}regex.h {$(VPATH)}vsnprintf.c $(ENCODING_H_INCLUDES) {$(VPATH)}internal.h
|
||||||
st.$(OBJEXT): {$(VPATH)}st.c $(RUBY_H_INCLUDES)
|
st.$(OBJEXT): {$(VPATH)}st.c $(RUBY_H_INCLUDES)
|
||||||
strftime.$(OBJEXT): {$(VPATH)}strftime.c $(RUBY_H_INCLUDES) \
|
strftime.$(OBJEXT): {$(VPATH)}strftime.c $(RUBY_H_INCLUDES) \
|
||||||
|
|
67
sprintf.c
67
sprintf.c
|
@ -15,6 +15,7 @@
|
||||||
#include "ruby/re.h"
|
#include "ruby/re.h"
|
||||||
#include "ruby/encoding.h"
|
#include "ruby/encoding.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
#include "id.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
@ -1022,12 +1023,78 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'f':
|
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 'G':
|
case 'G':
|
||||||
case 'e':
|
case 'e':
|
||||||
case 'E':
|
case 'E':
|
||||||
|
/* TODO: rational support */
|
||||||
case 'a':
|
case 'a':
|
||||||
case 'A':
|
case 'A':
|
||||||
|
float_value:
|
||||||
{
|
{
|
||||||
VALUE val = GETARG();
|
VALUE val = GETARG();
|
||||||
double fval;
|
double fval;
|
||||||
|
|
|
@ -148,6 +148,11 @@ class TestSprintf < Test::Unit::TestCase
|
||||||
assert_equal(" Inf", sprintf("% e", inf), '[ruby-dev:34002]')
|
assert_equal(" Inf", sprintf("% e", inf), '[ruby-dev:34002]')
|
||||||
end
|
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
|
def test_hash
|
||||||
options = {:capture=>/\d+/}
|
options = {:capture=>/\d+/}
|
||||||
assert_equal("with options {:capture=>/\\d+/}", sprintf("with options %p" % options))
|
assert_equal("with options {:capture=>/\\d+/}", sprintf("with options %p" % options))
|
||||||
|
|
Loading…
Add table
Reference in a new issue