[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [lmi] strtod("inf") and MSVC
From: |
Vaclav Slavik |
Subject: |
Re: [lmi] strtod("inf") and MSVC |
Date: |
Tue, 29 May 2012 19:08:19 +0200 |
User-agent: |
Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:12.0) Gecko/20120428 Thunderbird/12.0.1 |
Hi,
On 2011-06-27 01:37, Vadim Zeitlin wrote:
> LMI relies on strtod() accepting string "inf" as a valid input but this
> is, AFAIR[*], C99 extension and probably because of this, MSVC doesn't
> implement it and returns an error in this case, even in its latest version:
> quoting http://msdn.microsoft.com/en-us/library/kxsfc1ab%28v=VS.100%29.aspx
>
> strtod expects nptr to point to a string of the following form:
>
> [whitespace] [sign] [digits] [.digits] [ {d | D | e | E}[sign]digits]
>
> This prevents creating new census from working with MSVC right now as it
> fails to parse "inf"s in the sample data files. For now I've applied the
> smallest possible patch to make the program work for me with MSVC:
>
> --- a/numeric_io_traits.hpp
> +++ b/numeric_io_traits.hpp
> @@ -341,7 +341,25 @@ template<> struct numeric_conversion_traits<double>
> static int digits(T t) {return floating_point_decimals(t);}
> static char const* fmt() {return "%#.*f";}
> static T strtoT(char const* nptr, char** endptr)
> - {return std::strtod(nptr, endptr);}
> + {
> +#ifdef LMI_MSC
> + // COMPILER !! MSVC strtod() doesn't support C99 "inf[inity]" nor
> + // "nan[(...)]" strings nor hexadecimal notation so provide our
> + // work around for at least the first one of them which we
> actually
> + // need. This workaround is, of course, incomplete as it doesn't
> + // even support "-inf" without mentioning long and non-lower-case
> + // versions or NaN support.
> + if(strncmp(nptr, "inf", 3) == 0)
> + {
> + if(endptr)
> + {
> + *endptr = const_cast<char *>(nptr) + 3;
> + }
> + return std::numeric_limits<T>::infinity();
> + }
> +#endif // LMI_MSC
> + return std::strtod(nptr, endptr);
> + }
> };
>
> #if !defined LMI_COMPILER_PROVIDES_STRTOLD
>
> But I could extend/prettify it a little if you thought it would be useful
> to have. Would it?
Here's an updated and more complete version of the patch:
diff --git a/numeric_io_cast.hpp b/numeric_io_cast.hpp
index f7cbc4a..255c8fb 100644
--- a/numeric_io_cast.hpp
+++ b/numeric_io_cast.hpp
@@ -309,6 +309,12 @@ struct numeric_converter<std::string, From>
}
else
{
+#if defined _MSC_VER
+ // COMPILER !! MSVC formats infinity into a string as "1.#INF", not
+ // "inf" as gcc does and C99/C++11 mandates. Translate it manually.
+ if(0 == std::strcmp(buffer, "1.#INF"))
+ return "inf";
+#endif // defined _MSC_VER
return numeric_conversion_traits<From>::simplify(To(buffer));
}
}
diff --git a/numeric_io_traits.hpp b/numeric_io_traits.hpp
index 499b4bf..4c7636e 100644
--- a/numeric_io_traits.hpp
+++ b/numeric_io_traits.hpp
@@ -80,6 +80,15 @@ template<typename T>
inline int floating_point_decimals(T t)
{
BOOST_STATIC_ASSERT(boost::is_float<T>::value);
+#if defined _MSC_VER
+ // COMPILER !! Not only does Visual C++ write infinity as "1.#INF" rather
+ // than "inf", it respects decimals specification, "shortening" it into
+ // "1." if we return 0 here.
+ if(is_infinite(t))
+ {
+ return 4;
+ }
+#endif // defined _MSC_VER
// Avoid taking the logarithm of zero or infinity.
if(0 == t || is_infinite(t))
{
@@ -331,7 +340,25 @@ template<> struct numeric_conversion_traits<float>
static int digits(T t) {return floating_point_decimals(t);}
static char const* fmt() {return "%#.*f";}
static T strtoT(char const* nptr, char** endptr)
- {return strtof(nptr, endptr);}
+ {
+#if defined _MSC_VER
+ // COMPILER !! MSVC strtod() doesn't support C99 "inf[inity]" nor
+ // "nan[(...)]" strings nor hexadecimal notation so provide our
+ // work around for at least the first one of them which we actually
+ // need. This workaround is, of course, incomplete as it doesn't
+ // even support "-inf" without mentioning long and non-lower-case
+ // versions or NaN support.
+ if(strncmp(nptr, "inf", 3) == 0)
+ {
+ if(endptr)
+ {
+ *endptr = const_cast<char *>(nptr) + 3;
+ }
+ return std::numeric_limits<T>::infinity();
+ }
+#endif // defined _MSC_VER
+ return strtof(nptr, endptr);
+ }
};
template<> struct numeric_conversion_traits<double>
@@ -341,7 +368,25 @@ template<> struct numeric_conversion_traits<double>
static int digits(T t) {return floating_point_decimals(t);}
static char const* fmt() {return "%#.*f";}
static T strtoT(char const* nptr, char** endptr)
- {return std::strtod(nptr, endptr);}
+ {
+#if defined _MSC_VER
+ // COMPILER !! MSVC strtod() doesn't support C99 "inf[inity]" nor
+ // "nan[(...)]" strings nor hexadecimal notation so provide our
+ // work around for at least the first one of them which we actually
+ // need. This workaround is, of course, incomplete as it doesn't
+ // even support "-inf" without mentioning long and non-lower-case
+ // versions or NaN support.
+ if(strncmp(nptr, "inf", 3) == 0)
+ {
+ if(endptr)
+ {
+ *endptr = const_cast<char *>(nptr) + 3;
+ }
+ return std::numeric_limits<T>::infinity();
+ }
+#endif // defined _MSC_VER
+ return std::strtod(nptr, endptr);
+ }
};
#if !defined LMI_COMPILER_PROVIDES_STRTOLD
Regards,
Vaclav
- Re: [lmi] strtod("inf") and MSVC,
Vaclav Slavik <=