Format NaN.

This commit is contained in:
Victor Zverovich
2012-12-28 08:27:54 -08:00
parent 5d4ef3387f
commit ce60483833
3 changed files with 40 additions and 8 deletions

View File

@@ -33,6 +33,7 @@
#include "format.h" #include "format.h"
#include <math.h>
#include <stdint.h> #include <stdint.h>
#include <cassert> #include <cassert>
@@ -280,17 +281,21 @@ template <typename T>
void Formatter::FormatDouble(T value, const FormatSpec &spec, int precision) { void Formatter::FormatDouble(T value, const FormatSpec &spec, int precision) {
// Check type. // Check type.
char type = spec.type; char type = spec.type;
bool upper = false;
switch (type) { switch (type) {
case 0: case 0:
type = 'g'; type = 'g';
break; break;
case 'e': case 'E': case 'f': case 'g': case 'G': case 'e': case 'f': case 'g':
break; break;
case 'F': case 'F':
#ifdef _MSC_VER #ifdef _MSC_VER
// MSVC's printf doesn't support 'F'. // MSVC's printf doesn't support 'F'.
type = 'f'; type = 'f';
#endif #endif
// Fall through.
case 'E': case 'G':
upper = true;
break; break;
default: default:
ReportUnknownType(type, "double"); ReportUnknownType(type, "double");
@@ -298,12 +303,30 @@ void Formatter::FormatDouble(T value, const FormatSpec &spec, int precision) {
} }
char sign = 0; char sign = 0;
if (value < 0) { // Use signbit instead of value < 0 because the latter is always
// false for NaN.
if (signbit(value)) {
sign = '-'; sign = '-';
value = -value; value = -value;
} else if ((spec.flags & SIGN_FLAG) != 0) { } else if ((spec.flags & SIGN_FLAG) != 0) {
sign = (spec.flags & PLUS_FLAG) != 0 ? '+' : ' '; sign = (spec.flags & PLUS_FLAG) != 0 ? '+' : ' ';
} }
if (isnan(value)) {
// Format NaN ourselves because sprintf's output is not consistent
// across platforms.
std::size_t size = 4;
const char *nan = upper ? " NAN" : " nan";
if (!sign) {
--size;
++nan;
}
char *out = FormatString(nan, size, spec);
if (sign)
*out = sign;
return;
}
size_t offset = buffer_.size(); size_t offset = buffer_.size();
unsigned width = spec.width; unsigned width = spec.width;
if (sign) { if (sign) {
@@ -382,7 +405,7 @@ void Formatter::FormatDouble(T value, const FormatSpec &spec, int precision) {
} }
} }
void Formatter::FormatString( char *Formatter::FormatString(
const char *s, std::size_t size, const FormatSpec &spec) { const char *s, std::size_t size, const FormatSpec &spec) {
char *out = 0; char *out = 0;
if (spec.width > size) { if (spec.width > size) {
@@ -399,6 +422,7 @@ void Formatter::FormatString(
out = GrowBuffer(size); out = GrowBuffer(size);
} }
std::copy(s, s + size, out); std::copy(s, s + size, out);
return out;
} }
// Parses an unsigned integer advancing s to the end of the parsed input. // Parses an unsigned integer advancing s to the end of the parsed input.

View File

@@ -322,7 +322,7 @@ class Formatter : public BasicFormatter {
template <typename T> template <typename T>
void FormatDouble(T value, const FormatSpec &spec, int precision); void FormatDouble(T value, const FormatSpec &spec, int precision);
void FormatString(const char *s, std::size_t size, const FormatSpec &spec); char *FormatString(const char *s, std::size_t size, const FormatSpec &spec);
// Formats an argument of a custom type, such as a user-defined class. // Formats an argument of a custom type, such as a user-defined class.
template <typename T> template <typename T>

View File

@@ -774,16 +774,24 @@ TEST(FormatterTest, FormatDouble) {
sprintf(buffer, "%E", 392.65); sprintf(buffer, "%E", 392.65);
EXPECT_EQ(buffer, str(Format("{0:E}") << 392.65)); EXPECT_EQ(buffer, str(Format("{0:E}") << 392.65));
EXPECT_EQ("+0000392.6", str(Format("{0:+010.4g}") << 392.65)); EXPECT_EQ("+0000392.6", str(Format("{0:+010.4g}") << 392.65));
double nan = std::numeric_limits<double>::quiet_NaN();
EXPECT_EQ("nan", str(Format("{}") << nan));
EXPECT_EQ("-nan", str(Format("{}") << -nan));
EXPECT_EQ("NAN", str(Format("{:F}") << nan));
double inf = std::numeric_limits<double>::infinity(); double inf = std::numeric_limits<double>::infinity();
EXPECT_EQ("inf", str(Format("{}") << inf)); EXPECT_EQ("inf", str(Format("{}") << inf));
EXPECT_EQ("-inf", str(Format("{}") << -inf)); EXPECT_EQ("-inf", str(Format("{}") << -inf));
EXPECT_EQ("INF", str(Format("{:F}") << inf)); EXPECT_EQ("INF", str(Format("{:F}") << inf));
} }
TEST(FormatterTest, FormatNaN) {
double nan = std::numeric_limits<double>::quiet_NaN();
EXPECT_EQ("nan", str(Format("{}") << nan));
EXPECT_EQ("+nan", str(Format("{:+}") << nan));
EXPECT_EQ("-nan", str(Format("{}") << -nan));
EXPECT_EQ(" nan", str(Format("{: }") << nan));
EXPECT_EQ("NAN", str(Format("{:F}") << nan));
EXPECT_EQ("nan ", str(Format("{:<7}") << nan));
EXPECT_EQ(" nan ", str(Format("{:^7}") << nan));
EXPECT_EQ(" nan", str(Format("{:>7}") << nan));
}
TEST(FormatterTest, FormatLongDouble) { TEST(FormatterTest, FormatLongDouble) {
EXPECT_EQ("0", str(Format("{0:}") << 0.0l)); EXPECT_EQ("0", str(Format("{0:}") << 0.0l));
EXPECT_EQ("0.000000", str(Format("{0:f}") << 0.0l)); EXPECT_EQ("0.000000", str(Format("{0:f}") << 0.0l));