Fix numeric precision for strtod and dtoa

  • Download Gist
0001-Fix-numeric-precision-for-strtod-and-dtoa.patch
Diff
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
diff --git a/include/ruby/util.h b/include/ruby/util.h
index 5be5f2e..a4ac1a7 100644
--- a/include/ruby/util.h
+++ b/include/ruby/util.h
@@ -85,6 +85,21 @@ void ruby_each_words(const char *, void (*)(const char*, int, void*), void *);
RUBY_SYMBOL_EXPORT_END
+#if defined(__MINGW32__) && defined(_X86_) && !defined(__SSE2_MATH__) && defined(_MCW_PC)
+/* double-precision (53-bit) rounding precision is required for strtod and dtoa. */
+static inline double
+rb_w32_ruby_strtod(const char *s00, char **se)
+{
+ double r;
+ unsigned int default_control = _controlfp(0, 0);
+ _control87(_PC_53, _MCW_PC);
+ r = ruby_strtod(s00, se);
+ _control87(default_control, _MCW_PC);
+ return r;
+}
+#define ruby_strtod rb_w32_ruby_strtod
+#endif
+
#if defined(__cplusplus)
#if 0
{ /* satisfy cc-mode */
diff --git a/include/ruby/win32.h b/include/ruby/win32.h
index ad43dfc..b4d2b6b 100644
--- a/include/ruby/win32.h
+++ b/include/ruby/win32.h
@@ -811,4 +811,36 @@ rb_w32_pow(double x, double y)
#define pow rb_w32_pow
#endif
+#if defined(__MINGW32__) && defined(_X86_) && !defined(__SSE2_MATH__) && defined(_MCW_PC)
+/* util.c */
+/* double-precision (53-bit) rounding precision is required for strtod and dtoa. */
+static inline char *
+rb_w32_ruby_dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve)
+{
+ char *r;
+ char *ruby_dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve);
+ unsigned int default_control = _controlfp(0, 0);
+ _control87(_PC_53, _MCW_PC);
+ r = ruby_dtoa(d_, mode, ndigits, decpt, sign, rve);
+ _control87(default_control, _MCW_PC);
+ return r;
+}
+#define ruby_dtoa rb_w32_ruby_dtoa
+
+static inline char *
+rb_w32_ruby_hdtoa(double d, const char *xdigs, int ndigits, int *decpt, int *sign,
+ char **rve)
+{
+ char *r;
+ char *ruby_hdtoa(double d, const char *xdigs, int ndigits, int *decpt,
+ int *sign, char **rve);
+ unsigned int default_control = _controlfp(0, 0);
+ _control87(_PC_53, _MCW_PC);
+ r = ruby_hdtoa(d, xdigs, ndigits, decpt, sign, rve);
+ _control87(default_control, _MCW_PC);
+ return r;
+}
+#define ruby_hdtoa rb_w32_ruby_hdtoa
+#endif
+
#endif /* RUBY_WIN32_H */
diff --git a/util.c b/util.c
index fb72931..828e6ab 100644
--- a/util.c
+++ b/util.c
@@ -1929,6 +1929,8 @@ hexnan(double *rvp, const char **sp)
#endif /*No_Hex_NaN*/
#endif /* INFNAN_CHECK */
+#undef ruby_strtod
+
double
ruby_strtod(const char *s00, char **se)
{
@@ -3043,6 +3045,8 @@ static const char INFSTR[] = "Infinity";
static const char NANSTR[] = "NaN";
static const char ZEROSTR[] = "0";
+#undef ruby_dtoa
+
/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
*
* Inspired by "How to Print Floating-Point Numbers Accurately" by
@@ -3802,6 +3806,7 @@ ruby_each_words(const char *str, void (*func)(const char*, int, void*), void *ar
#define dmanh_get(u) ((uint32_t)(word0(u) & Frac_mask))
#define dmanl_get(u) ((uint32_t)word1(u))
+#undef ruby_hdtoa
/*
* This procedure converts a double-precision number in IEEE format

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.