diff options
author | Serge Pavlov <sepavloff@gmail.com> | 2021-05-07 02:17:42 +0700 |
---|---|---|
committer | Serge Pavlov <sepavloff@gmail.com> | 2021-05-21 11:02:51 +0700 |
commit | c162f086ba632ffaedfe92d63bf21571bc8ae4da (patch) | |
tree | 6798043c54cf97d5db4d936c36fe7b689aaace48 /llvm/unittests/ADT/APFloatTest.cpp | |
parent | 49028858637946ce8c00f12e41138b5ed7783276 (diff) | |
download | llvm-c162f086ba632ffaedfe92d63bf21571bc8ae4da.zip llvm-c162f086ba632ffaedfe92d63bf21571bc8ae4da.tar.gz llvm-c162f086ba632ffaedfe92d63bf21571bc8ae4da.tar.bz2 |
[APFloat] convertToDouble/Float can work on shorter types
Previously APFloat::convertToDouble may be called only for APFloats that
were built using double semantics. Other semantics like single precision
were not allowed although corresponding numbers could be converted to
double without loss of precision. The similar restriction applied to
APFloat::convertToFloat.
With this change any APFloat that can be precisely represented by double
can be handled with convertToDouble. Behavior of convertToFloat was
updated similarly. It make the conversion operations more convenient and
adds support for formats like half and bfloat.
Differential Revision: https://reviews.llvm.org/D102671
Diffstat (limited to 'llvm/unittests/ADT/APFloatTest.cpp')
-rw-r--r-- | llvm/unittests/ADT/APFloatTest.cpp | 261 |
1 files changed, 259 insertions, 2 deletions
diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp index 2088df0..1683a9d 100644 --- a/llvm/unittests/ADT/APFloatTest.cpp +++ b/llvm/unittests/ADT/APFloatTest.cpp @@ -1271,8 +1271,10 @@ TEST(APFloatTest, makeNaN) { #ifdef GTEST_HAS_DEATH_TEST #ifndef NDEBUG TEST(APFloatTest, SemanticsDeath) { - EXPECT_DEATH(APFloat(APFloat::IEEEsingle(), 0).convertToDouble(), "Float semantics are not IEEEdouble"); - EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), 0).convertToFloat(), "Float semantics are not IEEEsingle"); + EXPECT_DEATH(APFloat(APFloat::IEEEquad(), 0).convertToDouble(), + "Float semantics is not representable by IEEEdouble"); + EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), 0).convertToFloat(), + "Float semantics is not representable by IEEEsingle"); } #endif #endif @@ -4709,4 +4711,259 @@ TEST(APFloatTest, x87Next) { F.next(false); EXPECT_TRUE(ilogb(F) == -1); } + +TEST(APFloatTest, ToDouble) { + APFloat DPosZero(0.0); + APFloat DPosZeroToDouble(DPosZero.convertToDouble()); + EXPECT_TRUE(DPosZeroToDouble.isPosZero()); + APFloat DNegZero(-0.0); + APFloat DNegZeroToDouble(DNegZero.convertToDouble()); + EXPECT_TRUE(DNegZeroToDouble.isNegZero()); + + APFloat DOne(1.0); + EXPECT_EQ(1.0, DOne.convertToDouble()); + APFloat DPosLargest = APFloat::getLargest(APFloat::IEEEdouble(), false); + EXPECT_EQ(std::numeric_limits<double>::max(), DPosLargest.convertToDouble()); + APFloat DNegLargest = APFloat::getLargest(APFloat::IEEEdouble(), true); + EXPECT_EQ(-std::numeric_limits<double>::max(), DNegLargest.convertToDouble()); + APFloat DPosSmallest = + APFloat::getSmallestNormalized(APFloat::IEEEdouble(), false); + EXPECT_EQ(std::numeric_limits<double>::min(), DPosSmallest.convertToDouble()); + APFloat DNegSmallest = + APFloat::getSmallestNormalized(APFloat::IEEEdouble(), true); + EXPECT_EQ(-std::numeric_limits<double>::min(), + DNegSmallest.convertToDouble()); + + APFloat DSmallestDenorm = APFloat::getSmallest(APFloat::IEEEdouble(), false); + EXPECT_EQ(std::numeric_limits<double>::denorm_min(), + DSmallestDenorm.convertToDouble()); + APFloat DLargestDenorm(APFloat::IEEEdouble(), "0x0.FFFFFFFFFFFFFp-1022"); + EXPECT_EQ(/*0x0.FFFFFFFFFFFFFp-1022*/ 2.225073858507201e-308, + DLargestDenorm.convertToDouble()); + + APFloat DPosInf = APFloat::getInf(APFloat::IEEEdouble()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), DPosInf.convertToDouble()); + APFloat DNegInf = APFloat::getInf(APFloat::IEEEdouble(), true); + EXPECT_EQ(-std::numeric_limits<double>::infinity(), + DNegInf.convertToDouble()); + APFloat DQNaN = APFloat::getQNaN(APFloat::IEEEdouble()); + EXPECT_TRUE(std::isnan(DQNaN.convertToDouble())); + + APFloat FPosZero(0.0F); + APFloat FPosZeroToDouble(FPosZero.convertToDouble()); + EXPECT_TRUE(FPosZeroToDouble.isPosZero()); + APFloat FNegZero(-0.0F); + APFloat FNegZeroToDouble(FNegZero.convertToDouble()); + EXPECT_TRUE(FNegZeroToDouble.isNegZero()); + + APFloat FOne(1.0F); + EXPECT_EQ(1.0, FOne.convertToDouble()); + APFloat FPosLargest = APFloat::getLargest(APFloat::IEEEsingle(), false); + EXPECT_EQ(std::numeric_limits<float>::max(), FPosLargest.convertToDouble()); + APFloat FNegLargest = APFloat::getLargest(APFloat::IEEEsingle(), true); + EXPECT_EQ(-std::numeric_limits<float>::max(), FNegLargest.convertToDouble()); + APFloat FPosSmallest = + APFloat::getSmallestNormalized(APFloat::IEEEsingle(), false); + EXPECT_EQ(std::numeric_limits<float>::min(), FPosSmallest.convertToDouble()); + APFloat FNegSmallest = + APFloat::getSmallestNormalized(APFloat::IEEEsingle(), true); + EXPECT_EQ(-std::numeric_limits<float>::min(), FNegSmallest.convertToDouble()); + + APFloat FSmallestDenorm = APFloat::getSmallest(APFloat::IEEEsingle(), false); + EXPECT_EQ(std::numeric_limits<float>::denorm_min(), + FSmallestDenorm.convertToDouble()); + APFloat FLargestDenorm(APFloat::IEEEdouble(), "0x0.FFFFFEp-126"); + EXPECT_EQ(/*0x0.FFFFFEp-126*/ 1.1754942106924411e-38, + FLargestDenorm.convertToDouble()); + + APFloat FPosInf = APFloat::getInf(APFloat::IEEEsingle()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), FPosInf.convertToDouble()); + APFloat FNegInf = APFloat::getInf(APFloat::IEEEsingle(), true); + EXPECT_EQ(-std::numeric_limits<double>::infinity(), + FNegInf.convertToDouble()); + APFloat FQNaN = APFloat::getQNaN(APFloat::IEEEsingle()); + EXPECT_TRUE(std::isnan(FQNaN.convertToDouble())); + + APFloat HPosZero = APFloat::getZero(APFloat::IEEEhalf()); + APFloat HPosZeroToDouble(HPosZero.convertToDouble()); + EXPECT_TRUE(HPosZeroToDouble.isPosZero()); + APFloat HNegZero = APFloat::getZero(APFloat::IEEEhalf(), true); + APFloat HNegZeroToDouble(HNegZero.convertToDouble()); + EXPECT_TRUE(HNegZeroToDouble.isNegZero()); + + APFloat HOne(APFloat::IEEEhalf(), "1.0"); + EXPECT_EQ(1.0, HOne.convertToDouble()); + APFloat HPosLargest = APFloat::getLargest(APFloat::IEEEhalf(), false); + EXPECT_EQ(65504.0, HPosLargest.convertToDouble()); + APFloat HNegLargest = APFloat::getLargest(APFloat::IEEEhalf(), true); + EXPECT_EQ(-65504.0, HNegLargest.convertToDouble()); + APFloat HPosSmallest = + APFloat::getSmallestNormalized(APFloat::IEEEhalf(), false); + EXPECT_EQ(/*0x1.p-14*/ 6.103515625e-05, HPosSmallest.convertToDouble()); + APFloat HNegSmallest = + APFloat::getSmallestNormalized(APFloat::IEEEhalf(), true); + EXPECT_EQ(/*-0x1.p-14*/ -6.103515625e-05, HNegSmallest.convertToDouble()); + + APFloat HSmallestDenorm = APFloat::getSmallest(APFloat::IEEEhalf(), false); + EXPECT_EQ(/*0x1.p-24*/ 5.960464477539063e-08, + HSmallestDenorm.convertToDouble()); + APFloat HLargestDenorm(APFloat::IEEEhalf(), "0x1.FFCp-14"); + EXPECT_EQ(/*0x1.FFCp-14*/ 0.00012201070785522461, + HLargestDenorm.convertToDouble()); + + APFloat HPosInf = APFloat::getInf(APFloat::IEEEhalf()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), HPosInf.convertToDouble()); + APFloat HNegInf = APFloat::getInf(APFloat::IEEEhalf(), true); + EXPECT_EQ(-std::numeric_limits<double>::infinity(), + HNegInf.convertToDouble()); + APFloat HQNaN = APFloat::getQNaN(APFloat::IEEEhalf()); + EXPECT_TRUE(std::isnan(HQNaN.convertToDouble())); + + APFloat BPosZero = APFloat::getZero(APFloat::IEEEhalf()); + APFloat BPosZeroToDouble(BPosZero.convertToDouble()); + EXPECT_TRUE(BPosZeroToDouble.isPosZero()); + APFloat BNegZero = APFloat::getZero(APFloat::IEEEhalf(), true); + APFloat BNegZeroToDouble(BNegZero.convertToDouble()); + EXPECT_TRUE(BNegZeroToDouble.isNegZero()); + + APFloat BOne(APFloat::BFloat(), "1.0"); + EXPECT_EQ(1.0, BOne.convertToDouble()); + APFloat BPosLargest = APFloat::getLargest(APFloat::BFloat(), false); + EXPECT_EQ(/*0x1.FEp127*/ 3.3895313892515355e+38, + BPosLargest.convertToDouble()); + APFloat BNegLargest = APFloat::getLargest(APFloat::BFloat(), true); + EXPECT_EQ(/*-0x1.FEp127*/ -3.3895313892515355e+38, + BNegLargest.convertToDouble()); + APFloat BPosSmallest = + APFloat::getSmallestNormalized(APFloat::BFloat(), false); + EXPECT_EQ(/*0x1.p-126*/ 1.1754943508222875e-38, + BPosSmallest.convertToDouble()); + APFloat BNegSmallest = + APFloat::getSmallestNormalized(APFloat::BFloat(), true); + EXPECT_EQ(/*-0x1.p-126*/ -1.1754943508222875e-38, + BNegSmallest.convertToDouble()); + + APFloat BSmallestDenorm = APFloat::getSmallest(APFloat::BFloat(), false); + EXPECT_EQ(/*0x1.p-133*/ 9.183549615799121e-41, + BSmallestDenorm.convertToDouble()); + APFloat BLargestDenorm(APFloat::BFloat(), "0x1.FCp-127"); + EXPECT_EQ(/*0x1.FCp-127*/ 1.1663108012064884e-38, + BLargestDenorm.convertToDouble()); + + APFloat BPosInf = APFloat::getInf(APFloat::BFloat()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), BPosInf.convertToDouble()); + APFloat BNegInf = APFloat::getInf(APFloat::BFloat(), true); + EXPECT_EQ(-std::numeric_limits<double>::infinity(), + BNegInf.convertToDouble()); + APFloat BQNaN = APFloat::getQNaN(APFloat::BFloat()); + EXPECT_TRUE(std::isnan(BQNaN.convertToDouble())); +} + +TEST(APFloatTest, ToFloat) { + APFloat FPosZero(0.0F); + APFloat FPosZeroToFloat(FPosZero.convertToFloat()); + EXPECT_TRUE(FPosZeroToFloat.isPosZero()); + APFloat FNegZero(-0.0F); + APFloat FNegZeroToFloat(FNegZero.convertToFloat()); + EXPECT_TRUE(FNegZeroToFloat.isNegZero()); + + APFloat FOne(1.0F); + EXPECT_EQ(1.0F, FOne.convertToFloat()); + APFloat FPosLargest = APFloat::getLargest(APFloat::IEEEsingle(), false); + EXPECT_EQ(std::numeric_limits<float>::max(), FPosLargest.convertToFloat()); + APFloat FNegLargest = APFloat::getLargest(APFloat::IEEEsingle(), true); + EXPECT_EQ(-std::numeric_limits<float>::max(), FNegLargest.convertToFloat()); + APFloat FPosSmallest = + APFloat::getSmallestNormalized(APFloat::IEEEsingle(), false); + EXPECT_EQ(std::numeric_limits<float>::min(), FPosSmallest.convertToFloat()); + APFloat FNegSmallest = + APFloat::getSmallestNormalized(APFloat::IEEEsingle(), true); + EXPECT_EQ(-std::numeric_limits<float>::min(), FNegSmallest.convertToFloat()); + + APFloat FSmallestDenorm = APFloat::getSmallest(APFloat::IEEEsingle(), false); + EXPECT_EQ(std::numeric_limits<float>::denorm_min(), + FSmallestDenorm.convertToFloat()); + APFloat FLargestDenorm(APFloat::IEEEsingle(), "0x1.FFFFFEp-126"); + EXPECT_EQ(/*0x1.FFFFFEp-126*/ 2.3509885615147286e-38F, + FLargestDenorm.convertToFloat()); + + APFloat FPosInf = APFloat::getInf(APFloat::IEEEsingle()); + EXPECT_EQ(std::numeric_limits<float>::infinity(), FPosInf.convertToFloat()); + APFloat FNegInf = APFloat::getInf(APFloat::IEEEsingle(), true); + EXPECT_EQ(-std::numeric_limits<float>::infinity(), FNegInf.convertToFloat()); + APFloat FQNaN = APFloat::getQNaN(APFloat::IEEEsingle()); + EXPECT_TRUE(std::isnan(FQNaN.convertToFloat())); + + APFloat HPosZero = APFloat::getZero(APFloat::IEEEhalf()); + APFloat HPosZeroToFloat(HPosZero.convertToFloat()); + EXPECT_TRUE(HPosZeroToFloat.isPosZero()); + APFloat HNegZero = APFloat::getZero(APFloat::IEEEhalf(), true); + APFloat HNegZeroToFloat(HNegZero.convertToFloat()); + EXPECT_TRUE(HNegZeroToFloat.isNegZero()); + + APFloat HOne(APFloat::IEEEhalf(), "1.0"); + EXPECT_EQ(1.0F, HOne.convertToFloat()); + APFloat HPosLargest = APFloat::getLargest(APFloat::IEEEhalf(), false); + EXPECT_EQ(/*0x1.FFCp15*/ 65504.0F, HPosLargest.convertToFloat()); + APFloat HNegLargest = APFloat::getLargest(APFloat::IEEEhalf(), true); + EXPECT_EQ(/*-0x1.FFCp15*/ -65504.0F, HNegLargest.convertToFloat()); + APFloat HPosSmallest = + APFloat::getSmallestNormalized(APFloat::IEEEhalf(), false); + EXPECT_EQ(/*0x1.p-14*/ 6.103515625e-05F, HPosSmallest.convertToFloat()); + APFloat HNegSmallest = + APFloat::getSmallestNormalized(APFloat::IEEEhalf(), true); + EXPECT_EQ(/*-0x1.p-14*/ -6.103515625e-05F, HNegSmallest.convertToFloat()); + + APFloat HSmallestDenorm = APFloat::getSmallest(APFloat::IEEEhalf(), false); + EXPECT_EQ(/*0x1.p-24*/ 5.960464477539063e-08F, + HSmallestDenorm.convertToFloat()); + APFloat HLargestDenorm(APFloat::IEEEhalf(), "0x1.FFCp-14"); + EXPECT_EQ(/*0x1.FFCp-14*/ 0.00012201070785522461F, + HLargestDenorm.convertToFloat()); + + APFloat HPosInf = APFloat::getInf(APFloat::IEEEhalf()); + EXPECT_EQ(std::numeric_limits<float>::infinity(), HPosInf.convertToFloat()); + APFloat HNegInf = APFloat::getInf(APFloat::IEEEhalf(), true); + EXPECT_EQ(-std::numeric_limits<float>::infinity(), HNegInf.convertToFloat()); + APFloat HQNaN = APFloat::getQNaN(APFloat::IEEEhalf()); + EXPECT_TRUE(std::isnan(HQNaN.convertToFloat())); + + APFloat BPosZero = APFloat::getZero(APFloat::BFloat()); + APFloat BPosZeroToDouble(BPosZero.convertToFloat()); + EXPECT_TRUE(BPosZeroToDouble.isPosZero()); + APFloat BNegZero = APFloat::getZero(APFloat::BFloat(), true); + APFloat BNegZeroToDouble(BNegZero.convertToFloat()); + EXPECT_TRUE(BNegZeroToDouble.isNegZero()); + + APFloat BOne(APFloat::BFloat(), "1.0"); + EXPECT_EQ(1.0F, BOne.convertToFloat()); + APFloat BPosLargest = APFloat::getLargest(APFloat::BFloat(), false); + EXPECT_EQ(/*0x1.FEp127*/ 3.3895313892515355e+38F, + BPosLargest.convertToFloat()); + APFloat BNegLargest = APFloat::getLargest(APFloat::BFloat(), true); + EXPECT_EQ(/*-0x1.FEp127*/ -3.3895313892515355e+38F, + BNegLargest.convertToFloat()); + APFloat BPosSmallest = + APFloat::getSmallestNormalized(APFloat::BFloat(), false); + EXPECT_EQ(/*0x1.p-126*/ 1.1754943508222875e-38F, + BPosSmallest.convertToFloat()); + APFloat BNegSmallest = + APFloat::getSmallestNormalized(APFloat::BFloat(), true); + EXPECT_EQ(/*-0x1.p-126*/ -1.1754943508222875e-38F, + BNegSmallest.convertToFloat()); + + APFloat BSmallestDenorm = APFloat::getSmallest(APFloat::BFloat(), false); + EXPECT_EQ(/*0x1.p-133*/ 9.183549615799121e-41F, + BSmallestDenorm.convertToFloat()); + APFloat BLargestDenorm(APFloat::BFloat(), "0x1.FCp-127"); + EXPECT_EQ(/*0x1.FCp-127*/ 1.1663108012064884e-38F, + BLargestDenorm.convertToFloat()); + + APFloat BPosInf = APFloat::getInf(APFloat::BFloat()); + EXPECT_EQ(std::numeric_limits<float>::infinity(), BPosInf.convertToFloat()); + APFloat BNegInf = APFloat::getInf(APFloat::BFloat(), true); + EXPECT_EQ(-std::numeric_limits<float>::infinity(), BNegInf.convertToFloat()); + APFloat BQNaN = APFloat::getQNaN(APFloat::BFloat()); + EXPECT_TRUE(std::isnan(BQNaN.convertToFloat())); +} } |