summaryrefslogtreecommitdiffhomepage
path: root/src/numeric.c
diff options
context:
space:
mode:
authorKOBAYASHI Shuji <[email protected]>2019-01-13 19:59:22 +0900
committerKOBAYASHI Shuji <[email protected]>2019-01-13 19:59:22 +0900
commit9f081183d2351195c821fbe1520975ba000cafb5 (patch)
treedbe9017589efa225bb520a3d7e1adbf70f83ef46 /src/numeric.c
parentc1b92f88a210d018b653dc9865fe5375cf118a61 (diff)
downloadmruby-9f081183d2351195c821fbe1520975ba000cafb5.tar.gz
mruby-9f081183d2351195c821fbe1520975ba000cafb5.zip
Improve compatibility to CRuby for `Float#to_s`
Bfore: Float::INFINITY.to_s #=> "inf" 50.0.to_s #=> "50" 1e20.to_s #=> "1e+20" After / CRuby: Float::INFINITY.to_s #=> "Infinity" 50.0.to_s #=> "50.0" 1e20.to_s #=> "1.0e+20"
Diffstat (limited to 'src/numeric.c')
-rw-r--r--src/numeric.c48
1 files changed, 44 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 */