Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shirosaki/5596940 to your computer and use it in GitHub Desktop.
Save shirosaki/5596940 to your computer and use it in GitHub Desktop.
Fix numeric precision for strtod and dtoa
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment