Commit 8b4c9998 authored by Milo Yip's avatar Milo Yip

Add Value::GetFloat(), Value::IsLossLessFloat/Double()

Fix #341
parent 3cb5733e
......@@ -788,6 +788,29 @@ public:
bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; }
bool IsString() const { return (flags_ & kStringFlag) != 0; }
// Checks whether a number can be losslessly converted to a double.
bool IsLosslessDouble() const {
if (!IsNumber()) return false;
if (IsUint64()) return static_cast<uint64_t>(static_cast<double>(GetUint64())) == GetUint64();
if (IsInt64()) return static_cast< int64_t>(static_cast<double>(GetInt64())) == GetInt64();
return true; // double, int, uint are always lossless
}
// Checks whether a number is a float (possible lossy).
bool IsFloat() const {
if ((flags_ & kDoubleFlag) == 0)
return false;
double d = GetDouble();
return d >= -3.4028234e38 && d <= 3.4028234e38;
}
// Checks whether a number can be losslessly converted to a float.
bool IsLosslessFloat() const {
if (!IsNumber()) return false;
double a = GetDouble();
double b = static_cast<double>(static_cast<float>(a));
return a >= b && a <= b; // Prevent -Wfloat-equal
}
//@}
//!@name Null
......@@ -1445,6 +1468,9 @@ public:
int64_t GetInt64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; }
uint64_t GetUint64() const { RAPIDJSON_ASSERT(flags_ & kUint64Flag); return data_.n.u64; }
//! Get the value as double type.
/*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless.
*/
double GetDouble() const {
RAPIDJSON_ASSERT(IsNumber());
if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion.
......@@ -1454,11 +1480,19 @@ public:
RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return static_cast<double>(data_.n.u64); // uint64_t -> double (may lose precision)
}
//! Get the value as double type.
/*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless.
*/
double GetFloat() const {
return static_cast<float>(GetDouble());
}
GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; }
GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; }
GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; }
GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; }
GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; }
GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(f); return *this; }
//@}
......
......@@ -579,6 +579,54 @@ TEST(Value, Double) {
EXPECT_NEAR(56.78, z.GetDouble(), 0.0);
}
TEST(Value, Float) {
// Constructor with double
Value x(12.34f);
EXPECT_EQ(kNumberType, x.GetType());
EXPECT_NEAR(12.34f, x.GetFloat(), 0.0);
EXPECT_TRUE(x.IsNumber());
EXPECT_TRUE(x.IsDouble());
EXPECT_TRUE(x.IsFloat());
EXPECT_FALSE(x.IsInt());
EXPECT_FALSE(x.IsNull());
EXPECT_FALSE(x.IsBool());
EXPECT_FALSE(x.IsFalse());
EXPECT_FALSE(x.IsTrue());
EXPECT_FALSE(x.IsString());
EXPECT_FALSE(x.IsObject());
EXPECT_FALSE(x.IsArray());
// SetFloat()
Value z;
z.SetFloat(12.34f);
EXPECT_NEAR(12.34f, z.GetFloat(), 0.0f);
z = 56.78f;
EXPECT_NEAR(56.78f, z.GetFloat(), 0.0f);
}
TEST(Value, IsLosslessDouble) {
EXPECT_TRUE(Value(12.34).IsLosslessDouble());
EXPECT_TRUE(Value(-123).IsLosslessDouble());
EXPECT_TRUE(Value(2147483648u).IsLosslessDouble());
EXPECT_TRUE(Value(static_cast<int64_t>(-RAPIDJSON_UINT64_C2(0x40000000, 0x00000000))).IsLosslessDouble());
EXPECT_TRUE(Value(RAPIDJSON_UINT64_C2(0xA0000000, 0x00000000)).IsLosslessDouble());
EXPECT_FALSE(Value(static_cast<int64_t>(-RAPIDJSON_UINT64_C2(0x7FFFFFFF, 0xFFFFFFFF))).IsLosslessDouble());
EXPECT_FALSE(Value(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF)).IsLosslessDouble());
}
TEST(Value, IsLosslessFloat) {
EXPECT_TRUE(Value(12.25).IsLosslessFloat());
EXPECT_TRUE(Value(-123).IsLosslessFloat());
EXPECT_TRUE(Value(2147483648u).IsLosslessFloat());
EXPECT_TRUE(Value(3.4028234e38f).IsLosslessFloat());
EXPECT_TRUE(Value(-3.4028234e38f).IsLosslessFloat());
EXPECT_FALSE(Value(3.4028235e38).IsLosslessFloat());
EXPECT_FALSE(Value(0.3).IsLosslessFloat());
}
TEST(Value, String) {
// Construction with const string
Value x("Hello", 5); // literal
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment