summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2019-01-14 19:13:09 +0900
committerGitHub <[email protected]>2019-01-14 19:13:09 +0900
commit348526e1add796cd8b7b6dda2889ef5627e398c5 (patch)
tree19d9c28bbe8e925b1b27986fbc376693dba5cd54
parentc1b92f88a210d018b653dc9865fe5375cf118a61 (diff)
parent0e04c46261eb9d5193f21d423f5d00f1910a460a (diff)
downloadmruby-348526e1add796cd8b7b6dda2889ef5627e398c5.tar.gz
mruby-348526e1add796cd8b7b6dda2889ef5627e398c5.zip
Merge pull request #4225 from shuujii/improve-compatibility-to-cruby-for-float-to_s
Improve compatibility to CRuby for `Float#to_s`
-rw-r--r--src/numeric.c48
-rw-r--r--src/state.c4
-rw-r--r--test/t/float.rb33
3 files changed, 81 insertions, 4 deletions
diff --git a/src/numeric.c b/src/numeric.c
index 089cc744d..fc8460300 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -10,6 +10,7 @@
#endif
#include <limits.h>
#include <stdlib.h>
+#include <string.h>
#include <mruby.h>
#include <mruby/array.h>
@@ -23,9 +24,9 @@
#define floor(f) floorf(f)
#define ceil(f) ceilf(f)
#define fmod(x,y) fmodf(x,y)
-#define MRB_FLO_TO_STR_FMT "%.8g"
+#define FLO_TO_STR_PREC 8
#else
-#define MRB_FLO_TO_STR_FMT "%.16g"
+#define FLO_TO_STR_PREC 16
#endif
#endif
@@ -177,10 +178,49 @@ num_div(mrb_state *mrb, mrb_value x)
static mrb_value
flo_to_s(mrb_state *mrb, mrb_value flt)
{
- if (isnan(mrb_float(flt))) {
+ mrb_float f = mrb_float(flt);
+
+ if (isinf(f)) {
+ return f < 0 ? mrb_str_new_lit(mrb, "-Infinity")
+ : mrb_str_new_lit(mrb, "Infinity");
+ }
+ else if (isnan(f)) {
return mrb_str_new_lit(mrb, "NaN");
}
- return mrb_float_to_str(mrb, flt, MRB_FLO_TO_STR_FMT);
+ else {
+ char fmt[] = "%." MRB_STRINGIZE(FLO_TO_STR_PREC) "g";
+ mrb_value str = mrb_float_to_str(mrb, flt, fmt);
+ mrb_int len;
+ char *begp;
+
+ insert_dot_zero:
+ begp = RSTRING_PTR(str);
+ len = RSTRING_LEN(str);
+ for (char *p = begp, *endp = p + len; p < endp; ++p) {
+ if (*p == '.') {
+ return str;
+ }
+ else if (*p == 'e') {
+ ptrdiff_t e_pos = p - begp;
+ mrb_str_cat(mrb, str, ".0", 2);
+ p = RSTRING_PTR(str) + e_pos;
+ memmove(p + 2, p, len - e_pos);
+ memcpy(p, ".0", 2);
+ return str;
+ }
+ }
+
+ if (FLO_TO_STR_PREC + (begp[0] == '-') <= len) {
+ --fmt[sizeof(fmt) - 3]; /* %.16g(%.8g) -> %.15g(%.7g) */
+ str = mrb_float_to_str(mrb, flt, fmt);
+ goto insert_dot_zero;
+ }
+ else {
+ mrb_str_cat(mrb, str, ".0", 2);
+ }
+
+ return str;
+ }
}
/* 15.2.9.3.2 */
diff --git a/src/state.c b/src/state.c
index 5583a77e5..e678b37f3 100644
--- a/src/state.c
+++ b/src/state.c
@@ -41,6 +41,10 @@ mrb_open_core(mrb_allocf f, void *ud)
mrb_init_core(mrb);
+#if !defined(MRB_DISABLE_STDIO) && defined(_MSC_VER) && _MSC_VER < 1900
+ _set_output_format(_TWO_DIGIT_EXPONENT);
+#endif
+
return mrb;
}
diff --git a/test/t/float.rb b/test/t/float.rb
index 68fd31b9a..eac5c5792 100644
--- a/test/t/float.rb
+++ b/test/t/float.rb
@@ -206,4 +206,37 @@ assert('Float#>>') do
assert_equal(-1, -23.0 >> 128)
end
+assert('Float#to_s') do
+ uses_float = 4e38.infinite? # enable MRB_USE_FLOAT?
+
+ assert_equal("Infinity", Float::INFINITY.to_s)
+ assert_equal("-Infinity", (-Float::INFINITY).to_s)
+ assert_equal("NaN", Float::NAN.to_s)
+ assert_equal("0.0", 0.0.to_s)
+ assert_equal("-0.0", -0.0.to_s)
+ assert_equal("-3.21", -3.21.to_s)
+ assert_equal("50.0", 50.0.to_s)
+ assert_equal("0.00021", 0.00021.to_s)
+ assert_equal("-0.00021", -0.00021.to_s)
+ assert_equal("2.1e-05", 0.000021.to_s)
+ assert_equal("-2.1e-05", -0.000021.to_s)
+ assert_equal("1.0e+20", 1e20.to_s)
+ assert_equal("-1.0e+20", -1e20.to_s)
+ assert_equal("1.0e+16", 10000000000000000.0.to_s)
+ assert_equal("-1.0e+16", -10000000000000000.0.to_s)
+ assert_equal("100000.0", 100000.0.to_s)
+ assert_equal("-100000.0", -100000.0.to_s)
+ if uses_float
+ assert_equal("1.0e+08", 100000000.0.to_s)
+ assert_equal("-1.0e+08", -100000000.0.to_s)
+ assert_equal("1.0e+07", 10000000.0.to_s)
+ assert_equal("-1.0e+07", -10000000.0.to_s)
+ else
+ assert_equal("1.0e+15", 1000000000000000.0.to_s)
+ assert_equal("-1.0e+15", -1000000000000000.0.to_s)
+ assert_equal("100000000000000.0", 100000000000000.0.to_s)
+ assert_equal("-100000000000000.0", -100000000000000.0.to_s)
+ end
+end
+
end # const_defined?(:Float)