Skip to content

Commit

Permalink
Add valgrind clean strtof/d/ld function supporting nan/inf
Browse files Browse the repository at this point in the history
- since sscanf / strtof etc have issues with nan/inf parsing add
valgrind clean extra treatment for that
  • Loading branch information
Soeren Sonnenburg committed Feb 9, 2014
1 parent 30fcb37 commit ee9af3b
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 14 deletions.
9 changes: 3 additions & 6 deletions src/shogun/io/SerializableXmlReader00.cpp
Expand Up @@ -81,16 +81,13 @@ SerializableXmlReader00::read_scalar_wrapped(
result = false;
break;
case PT_FLOAT32:
if (sscanf(buf, "%g", (float32_t*) param) != 1)
result = false;
result = CMath::strtof(buf, (float32_t*) param);
break;
case PT_FLOAT64:
if (sscanf(buf, "%lg", (float64_t*) param) != 1)
result = false;
result = CMath::strtod(buf, (float64_t*) param);
break;
case PT_FLOATMAX:
if (sscanf(buf, "%Lg", (floatmax_t*) param) != 1)
result = false;
result = CMath::strtold(buf, (floatmax_t*) param);
break;
case PT_COMPLEX128:
float64_t c_real, c_imag;
Expand Down
106 changes: 104 additions & 2 deletions src/shogun/mathematics/Math.cpp
Expand Up @@ -14,11 +14,18 @@
#include <shogun/mathematics/Math.h>
#include <shogun/mathematics/lapack.h>
#include <shogun/io/SGIO.h>
#include <shogun/lib/SGVector.h>

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#ifndef NAN
#include <stdlib.h>
#define NAN (strtod("NAN",NULL))
#endif


using namespace shogun;

#ifdef USE_LOGCACHE
Expand All @@ -34,7 +41,8 @@ int32_t CMath::LOGACCURACY = 0; // 100000 steps per integer

int32_t CMath::LOGRANGE = 0; // range for logtable: log(1+exp(x)) -25 <= x <= 0

const float64_t CMath::INFTY = -log(0.0); // infinity
const float64_t CMath::NOT_A_NUMBER = NAN;
const float64_t CMath::INFTY = INFINITY; // infinity
const float64_t CMath::ALMOST_INFTY = +1e+20; //a large number
const float64_t CMath::ALMOST_NEG_INFTY = -1000;
const float64_t CMath::PI=M_PI;
Expand Down Expand Up @@ -244,4 +252,98 @@ int CMath::is_finite(double f)
#endif // #ifndef HAVE_STD_ISFINITE

return std::isfinite(f);
}
}

bool CMath::strtof(const char* str, float32_t* result)
{
ASSERT(str);
ASSERT(result);

SGVector<char> buf(strlen(str)+1);

for (index_t i=0; i<buf.vlen-1; i++)
buf[i]=tolower(str[i]);
buf[buf.vlen-1]='\0';

if (strstr(buf, "inf") != NULL)
{
*result = CMath::INFTY;

if (strchr(buf,'-') != NULL)
*result *= -1;
return true;
}

if (strstr(buf, "nan") != NULL)
{
*result = CMath::NOT_A_NUMBER;
return true;
}

char* endptr = buf.vector;
*result=::strtof(str, &endptr);
return endptr != buf.vector;
}

bool CMath::strtod(const char* str, float64_t* result)
{
ASSERT(str);
ASSERT(result);

SGVector<char> buf(strlen(str)+1);

for (index_t i=0; i<buf.vlen-1; i++)
buf[i]=tolower(str[i]);
buf[buf.vlen-1]='\0';

if (strstr(buf, "inf") != NULL)
{
*result = CMath::INFTY;

if (strchr(buf,'-') != NULL)
*result *= -1;
return true;
}

if (strstr(buf, "nan") != NULL)
{
*result = CMath::NOT_A_NUMBER;
return true;
}

char* endptr = buf.vector;
*result=::strtod(str, &endptr);
return endptr != buf.vector;
}

bool CMath::strtold(const char* str, floatmax_t* result)
{
ASSERT(str);
ASSERT(result);

SGVector<char> buf(strlen(str)+1);

for (index_t i=0; i<buf.vlen-1; i++)
buf[i]=tolower(str[i]);
buf[buf.vlen-1]='\0';

if (strstr(buf, "inf") != NULL)
{
*result = CMath::INFTY;

if (strchr(buf,'-') != NULL)
*result *= -1;
return true;
}

if (strstr(buf, "nan") != NULL)
{
*result = CMath::NOT_A_NUMBER;
return true;
}

char* endptr = buf.vector;
*result=::strtold(str, &endptr);
return endptr != buf.vector;
}

13 changes: 7 additions & 6 deletions src/shogun/mathematics/Math.h
Expand Up @@ -66,11 +66,6 @@
#endif
#endif //_WIN32

#ifndef NAN
#include <stdlib.h>
#define NAN (strtod("NAN",NULL))
#endif

/* Size of RNG seed */
#define RNG_SEED_SIZE 256

Expand Down Expand Up @@ -507,6 +502,10 @@ class CMath : public CSGObject
return area;
}

static bool strtof(const char* str, float32_t* result);
static bool strtod(const char* str, float64_t* result);
static bool strtold(const char* str, floatmax_t* result);

static inline int64_t factorial(int32_t n)
{
int64_t res=1;
Expand Down Expand Up @@ -1259,7 +1258,7 @@ class CMath : public CSGObject
if (!CMath::is_finite(q))
{
SG_SWARNING("INVALID second operand to logsum(%f,%f) expect undefined results\n", p, q)
return NAN;
return NOT_A_NUMBER;
}
diff = p - q;
if (diff > 0)
Expand Down Expand Up @@ -1325,6 +1324,8 @@ class CMath : public CSGObject
public:
/**@name constants*/
//@{
/// not a number
static const float64_t NOT_A_NUMBER;
/// infinity
static const float64_t INFTY;
static const float64_t ALMOST_INFTY;
Expand Down
48 changes: 48 additions & 0 deletions tests/unit/mathematics/Math_unittest.cc
Expand Up @@ -164,3 +164,51 @@ TEST(CMath, log_mean_exp)
values.range_fill();
EXPECT_NEAR(CMath::log_mean_exp(values), 1.3089936757762706, 1e-15);
}

TEST(CMath, strtofloat)
{
float32_t float_result = 0;
EXPECT_TRUE(CMath::strtof("nan", &float_result));
EXPECT_TRUE(CMath::is_nan(float_result));

EXPECT_TRUE(CMath::strtof("inf", &float_result));
EXPECT_TRUE(CMath::is_infinity(float_result));

EXPECT_TRUE(CMath::strtof("-inf", &float_result));
EXPECT_DOUBLE_EQ(-CMath::INFTY, float_result);

EXPECT_TRUE(CMath::strtof("1.2345", &float_result));
EXPECT_FLOAT_EQ(1.2345, float_result);
}

TEST(CMath, strtodouble)
{
float64_t double_result = 0;
EXPECT_TRUE(CMath::strtod("nan", &double_result));
EXPECT_TRUE(CMath::is_nan(double_result));

EXPECT_TRUE(CMath::strtod("inf", &double_result));
EXPECT_TRUE(CMath::is_infinity(double_result));

EXPECT_TRUE(CMath::strtod("-inf", &double_result));
EXPECT_DOUBLE_EQ(-CMath::INFTY, double_result);

EXPECT_TRUE(CMath::strtod("1.234567890123", &double_result));
EXPECT_DOUBLE_EQ(1.234567890123, double_result);
}

TEST(CMath, strtolongdouble)
{
floatmax_t long_double_result = 0;
EXPECT_TRUE(CMath::strtold("nan", &long_double_result));
EXPECT_TRUE(CMath::is_nan(long_double_result));

EXPECT_TRUE(CMath::strtold("inf", &long_double_result));
EXPECT_TRUE(CMath::is_infinity(long_double_result));

EXPECT_TRUE(CMath::strtold("-inf", &long_double_result));
EXPECT_DOUBLE_EQ(-CMath::INFTY, long_double_result);

EXPECT_TRUE(CMath::strtold("1.234567890123", &long_double_result));
EXPECT_EQ(long_double_result, 1.234567890123);
}

0 comments on commit ee9af3b

Please sign in to comment.