diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index d41a87e..82a86ed 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -700,8 +700,10 @@ public: return StringEqual(rhs); case kNumberType: - if (IsDouble() || rhs.IsDouble()) - return GetDouble() == rhs.GetDouble(); // May convert one operand from integer to double. + if (IsDouble() || rhs.IsDouble()) { + float delta = GetDouble() - rhs.GetDouble(); // May convert one operand from integer to double. + return delta >= 0.0 && delta <= 0.0; // Prevent -Wfloat-equal + } else return data_.n.u64 == rhs.data_.n.u64; diff --git a/include/rapidjson/internal/diyfp.h b/include/rapidjson/internal/diyfp.h index 320d05d..0b098af 100644 --- a/include/rapidjson/internal/diyfp.h +++ b/include/rapidjson/internal/diyfp.h @@ -238,7 +238,7 @@ inline DiyFp GetCachedPower(int e, int* K) { //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive int k = static_cast(dk); - if (k != dk) + if (dk - k > 0.0) k++; unsigned index = static_cast((k >> 3) + 1); diff --git a/include/rapidjson/internal/dtoa.h b/include/rapidjson/internal/dtoa.h index bf686b0..aec6bcd 100644 --- a/include/rapidjson/internal/dtoa.h +++ b/include/rapidjson/internal/dtoa.h @@ -193,8 +193,8 @@ inline char* Prettify(char* buffer, int length, int k) { } inline char* dtoa(double value, char* buffer) { - if (value == 0) { - Double d(value); + Double d(value); + if (d.IsZero()) { if (d.Sign()) *buffer++ = '-'; // -0.0, Issue #289 buffer[0] = '0'; diff --git a/include/rapidjson/internal/ieee754.h b/include/rapidjson/internal/ieee754.h index 934cf19..152be8f 100644 --- a/include/rapidjson/internal/ieee754.h +++ b/include/rapidjson/internal/ieee754.h @@ -36,7 +36,7 @@ public: double PreviousPositiveDouble() const { RAPIDJSON_ASSERT(!Sign()); - if (d == 0.0) + if (IsZero()) return 0.0; else return Double(u - 1).Value(); @@ -49,6 +49,7 @@ public: bool IsNan() const { return (u & kExponentMask) == kExponentMask && Significand() != 0; } bool IsInf() const { return (u & kExponentMask) == kExponentMask && Significand() == 0; } bool IsNormal() const { return (u & kExponentMask) != 0 || Significand() == 0; } + bool IsZero() const { return (u & (kExponentMask | kSignificandMask)) == 0; } uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 0ee2523..d9da869 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -896,7 +896,7 @@ private: if (significandDigit < 17) { d = d * 10.0 + (s.TakePush() - '0'); --expFrac; - if (d != 0.0) + if (d > 0.0) significandDigit++; } else diff --git a/test/unittest/CMakeLists.txt b/test/unittest/CMakeLists.txt index 5e4a3e9..326e6de 100644 --- a/test/unittest/CMakeLists.txt +++ b/test/unittest/CMakeLists.txt @@ -14,9 +14,9 @@ set(UNITTEST_SOURCES writertest.cpp) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Weffc++ -Wswitch-default") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal") elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Weffc++ -Wswitch-default") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") add_definitions(-D_CRT_SECURE_NO_WARNINGS=1) endif() diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp index 6ececf7..12ea751 100644 --- a/test/unittest/documenttest.cpp +++ b/test/unittest/documenttest.cpp @@ -63,7 +63,7 @@ void ParseTest() { EXPECT_TRUE(doc.HasMember("pi")); const ValueType& pi = doc["pi"]; EXPECT_TRUE(pi.IsNumber()); - EXPECT_EQ(3.1416, pi.GetDouble()); + EXPECT_DOUBLE_EQ(3.1416, pi.GetDouble()); EXPECT_TRUE(doc.HasMember("a")); const ValueType& a = doc["a"]; diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 318f188..d41eed6 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -30,6 +30,7 @@ using namespace rapidjson; #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) +RAPIDJSON_DIAG_OFF(float-equal) #endif template @@ -190,7 +191,7 @@ static void TestParseDouble() { internal::Double e(x), a(h.actual_); \ EXPECT_EQ(e.Sign(), a.Sign()); \ if (fullPrecision) { \ - EXPECT_EQ(x, h.actual_); \ + EXPECT_NEAR(x, h.actual_, 0.0); \ if (x != h.actual_) \ printf(" String: %s\n Actual: %.17g\nExpected: %.17g\n", str, h.actual_, x); \ } \ @@ -662,7 +663,7 @@ struct ParseObjectHandler : BaseReaderHandler, ParseObjectHandler> { } } bool Uint(unsigned i) { return Int(i); } - bool Double(double d) { EXPECT_EQ(12u, step_); EXPECT_EQ(3.1416, d); step_++; return true; } + bool Double(double d) { EXPECT_EQ(12u, step_); EXPECT_DOUBLE_EQ(3.1416, d); step_++; return true; } bool String(const char* str, size_t, bool) { switch(step_) { case 1: EXPECT_STREQ("hello", str); step_++; return true; diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index b2647c0..846b1c8 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -339,7 +339,7 @@ TEST(Value, Int) { EXPECT_EQ(1234u, x.GetUint()); EXPECT_EQ(1234, x.GetInt64()); EXPECT_EQ(1234u, x.GetUint64()); - EXPECT_EQ(1234, x.GetDouble()); + EXPECT_NEAR(1234.0, x.GetDouble(), 0.0); //EXPECT_EQ(1234, (int)x); //EXPECT_EQ(1234, (unsigned)x); //EXPECT_EQ(1234, (int64_t)x); @@ -397,7 +397,7 @@ TEST(Value, Uint) { EXPECT_TRUE(x.IsUint()); EXPECT_TRUE(x.IsInt64()); EXPECT_TRUE(x.IsUint64()); - EXPECT_EQ(1234.0, x.GetDouble()); // Number can always be cast as double but !IsDouble(). + EXPECT_NEAR(1234.0, x.GetDouble(), 0.0); // Number can always be cast as double but !IsDouble(). EXPECT_FALSE(x.IsDouble()); EXPECT_FALSE(x.IsNull()); @@ -517,7 +517,7 @@ TEST(Value, Double) { // Constructor with double Value x(12.34); EXPECT_EQ(kNumberType, x.GetType()); - EXPECT_EQ(12.34, x.GetDouble()); + EXPECT_NEAR(12.34, x.GetDouble(), 0.0); EXPECT_TRUE(x.IsNumber()); EXPECT_TRUE(x.IsDouble()); @@ -533,10 +533,10 @@ TEST(Value, Double) { // SetDouble() Value z; z.SetDouble(12.34); - EXPECT_EQ(12.34, z.GetDouble()); + EXPECT_NEAR(12.34, z.GetDouble(), 0.0); z = 56.78; - EXPECT_EQ(56.78, z.GetDouble()); + EXPECT_NEAR(56.78, z.GetDouble(), 0.0); } TEST(Value, String) {