[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [lmi] strtod("inf") and MSVC
From: |
Greg Chicares |
Subject: |
Re: [lmi] strtod("inf") and MSVC |
Date: |
Thu, 31 May 2012 17:37:31 +0000 |
User-agent: |
Mozilla/5.0 (Windows NT 5.1; rv:10.0.2) Gecko/20120216 Thunderbird/10.0.2 |
On 2012-05-29 17:08Z, Vaclav Slavik wrote:
[...]
> Here's an updated and more complete version of the patch:
Committed 20120531T1516Z:
http://svn.savannah.nongnu.org/viewvc?view=rev&root=lmi&revision=5478
I extended it to include Comeau C++, which uses the same flawed C runtime.
However, these tests in 'numeric_io_test.cpp' still don't pass:
BOOST_TEST_EQUAL(inf_dbl, numeric_io_cast<double>("INF"));
BOOST_TEST_EQUAL(inf_dbl, numeric_io_cast<double>("infinity"));
BOOST_TEST_EQUAL(inf_dbl, numeric_io_cast<double>("INFINITY"));
so I'd guess that they don't pass for msvc either. You anticipated the
case-sensitivity issue:
> + // 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;
but I was surprised that converting the string "infinity" failed. I don't
remember the C standard library very well, but in this snippet I think
you used strncmp() in order to match "inf[inity]": { inf | infinity },
but the "3" on the last quoted line doesn't seem to work for the lengthier
forms.
Oh, wait--you explained that:
> + // 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.
but I thought you meant 'long double'...so I figured I might as well just
fix that...and one thing led to another, and now I have a patch that converts
all infinities for como, and I'd guess for msvc too; but does it look right,
and is there a less awful way to write it that isn't slower?
Index: numeric_io_traits.hpp
===================================================================
--- numeric_io_traits.hpp (revision 5478)
+++ numeric_io_traits.hpp (working copy)
@@ -31,7 +31,7 @@
#include <algorithm> // std::max()
#include <cmath> // C99 functions fabsl(), log10l(),
strtold()
#include <cstdlib> // std::strto*()
-#include <cstring> // std::strncmp()
+#include <cstring> // std::strlen(), std::strcmp()
#include <limits>
#include <stdexcept>
#include <string>
@@ -343,22 +343,47 @@
static T strtoT(char const* nptr, char** endptr)
{
#if defined LMI_MSC || defined LMI_COMO_WITH_MINGW
- // 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(0 == std::strncmp(nptr, "inf", 3))
+ // COMPILER !! MSVC strtof() doesn't support C99 "inf[inity]".
+ // Work around that, but don't worry about "nan".
+ //
+ // Pointer to which strtoT()'s 'endptr' argument refers.
+ char* rendptr;
+ T z = strtof(nptr, &rendptr);
+ if('\0' == *rendptr)
{
if(endptr)
{
- *endptr = const_cast<char *>(nptr) + 3;
+ *endptr = rendptr;
}
- return std::numeric_limits<T>::infinity();
+ return z;
}
-#endif // defined LMI_MSC || defined LMI_COMO_WITH_MINGW
+ else if
+ ( 0 == std::strcmp(nptr, "inf")
+ || 0 == std::strcmp(nptr, "INF")
+ || 0 == std::strcmp(nptr, "infinity")
+ || 0 == std::strcmp(nptr, "INFINITY")
+ || 0 == std::strcmp(nptr,"-inf")
+ || 0 == std::strcmp(nptr,"-INF")
+ || 0 == std::strcmp(nptr,"-infinity")
+ || 0 == std::strcmp(nptr,"-INFINITY")
+ )
+ {
+ if(endptr)
+ {
+ *endptr = const_cast<char *>(nptr) + std::strlen(nptr);
+ }
+ return '-' == *nptr
+ ? -std::numeric_limits<T>::infinity()
+ : std::numeric_limits<T>::infinity()
+ ;
+ }
+ else
+ {
+ throw std::invalid_argument("Numeric conversion failed.");
+ }
+#else // !(defined LMI_MSC || defined LMI_COMO_WITH_MINGW)
return strtof(nptr, endptr);
+#endif // !(defined LMI_MSC || defined LMI_COMO_WITH_MINGW)
}
};
@@ -371,22 +396,47 @@
static T strtoT(char const* nptr, char** endptr)
{
#if defined LMI_MSC || defined LMI_COMO_WITH_MINGW
- // 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(0 == std::strncmp(nptr, "inf", 3))
+ // COMPILER !! MSVC strtod() doesn't support C99 "inf[inity]".
+ // Work around that, but don't worry about "nan".
+ //
+ // Pointer to which strtoT()'s 'endptr' argument refers.
+ char* rendptr;
+ T z = std::strtod(nptr, &rendptr);
+ if('\0' == *rendptr)
{
if(endptr)
{
- *endptr = const_cast<char *>(nptr) + 3;
+ *endptr = rendptr;
}
- return std::numeric_limits<T>::infinity();
+ return z;
}
-#endif // defined LMI_MSC || defined LMI_COMO_WITH_MINGW
+ else if
+ ( 0 == std::strcmp(nptr, "inf")
+ || 0 == std::strcmp(nptr, "INF")
+ || 0 == std::strcmp(nptr, "infinity")
+ || 0 == std::strcmp(nptr, "INFINITY")
+ || 0 == std::strcmp(nptr,"-inf")
+ || 0 == std::strcmp(nptr,"-INF")
+ || 0 == std::strcmp(nptr,"-infinity")
+ || 0 == std::strcmp(nptr,"-INFINITY")
+ )
+ {
+ if(endptr)
+ {
+ *endptr = const_cast<char *>(nptr) + std::strlen(nptr);
+ }
+ return '-' == *nptr
+ ? -std::numeric_limits<T>::infinity()
+ : std::numeric_limits<T>::infinity()
+ ;
+ }
+ else
+ {
+ throw std::invalid_argument("Numeric conversion failed.");
+ }
+#else // !(defined LMI_MSC || defined LMI_COMO_WITH_MINGW)
return std::strtod(nptr, endptr);
+#endif // !(defined LMI_MSC || defined LMI_COMO_WITH_MINGW)
}
};