From 6c61edcbab1ccfe456a1cade499a3c48d43c616f Mon Sep 17 00:00:00 2001 From: Jay Foad Date: Thu, 27 Feb 2020 09:57:16 +0000 Subject: [PATCH] [APFloat] Overload comparison operators Summary: These implement the usual IEEE-style floating point comparison semantics, e.g. +0.0 == -0.0 and all operators except != return false if either argument is NaN. Subscribers: arsenm, jvesely, nhaehnle, hiraditya, dexonsmith, kerbowa, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D75237 --- llvm/include/llvm/ADT/APFloat.h | 22 ++++++++++++- llvm/unittests/ADT/APFloatTest.cpp | 65 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h index 99d1b12..e5b999e 100644 --- a/llvm/include/llvm/ADT/APFloat.h +++ b/llvm/include/llvm/ADT/APFloat.h @@ -1125,7 +1125,27 @@ public: double convertToDouble() const { return getIEEE().convertToDouble(); } float convertToFloat() const { return getIEEE().convertToFloat(); } - bool operator==(const APFloat &) const = delete; + bool operator==(const APFloat &RHS) const { return compare(RHS) == cmpEqual; } + + bool operator!=(const APFloat &RHS) const { return compare(RHS) != cmpEqual; } + + bool operator<(const APFloat &RHS) const { + return compare(RHS) == cmpLessThan; + } + + bool operator>(const APFloat &RHS) const { + return compare(RHS) == cmpGreaterThan; + } + + bool operator<=(const APFloat &RHS) const { + cmpResult Res = compare(RHS); + return Res == cmpLessThan || Res == cmpEqual; + } + + bool operator>=(const APFloat &RHS) const { + cmpResult Res = compare(RHS); + return Res == cmpGreaterThan || Res == cmpEqual; + } cmpResult compare(const APFloat &RHS) const { assert(&getSemantics() == &RHS.getSemantics() && diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp index 9f68bf1..7814d94 100644 --- a/llvm/unittests/ADT/APFloatTest.cpp +++ b/llvm/unittests/ADT/APFloatTest.cpp @@ -2932,6 +2932,71 @@ TEST(APFloatTest, operatorOverloads) { EXPECT_TRUE(One.bitwiseIsEqual(Two / Two)); } +TEST(APFloatTest, Comparisons) { + enum {MNan, MInf, MBig, MOne, MZer, PZer, POne, PBig, PInf, PNan, NumVals}; + APFloat Vals[NumVals] = { + APFloat::getNaN(APFloat::IEEEsingle(), true), + APFloat::getInf(APFloat::IEEEsingle(), true), + APFloat::getLargest(APFloat::IEEEsingle(), true), + APFloat(APFloat::IEEEsingle(), "-0x1p+0"), + APFloat::getZero(APFloat::IEEEsingle(), true), + APFloat::getZero(APFloat::IEEEsingle(), false), + APFloat(APFloat::IEEEsingle(), "0x1p+0"), + APFloat::getLargest(APFloat::IEEEsingle(), false), + APFloat::getInf(APFloat::IEEEsingle(), false), + APFloat::getNaN(APFloat::IEEEsingle(), false), + }; + using Relation = void (*)(const APFloat &, const APFloat &); + Relation LT = [](const APFloat &LHS, const APFloat &RHS) { + EXPECT_FALSE(LHS == RHS); + EXPECT_TRUE(LHS != RHS); + EXPECT_TRUE(LHS < RHS); + EXPECT_FALSE(LHS > RHS); + EXPECT_TRUE(LHS <= RHS); + EXPECT_FALSE(LHS >= RHS); + }; + Relation EQ = [](const APFloat &LHS, const APFloat &RHS) { + EXPECT_TRUE(LHS == RHS); + EXPECT_FALSE(LHS != RHS); + EXPECT_FALSE(LHS < RHS); + EXPECT_FALSE(LHS > RHS); + EXPECT_TRUE(LHS <= RHS); + EXPECT_TRUE(LHS >= RHS); + }; + Relation GT = [](const APFloat &LHS, const APFloat &RHS) { + EXPECT_FALSE(LHS == RHS); + EXPECT_TRUE(LHS != RHS); + EXPECT_FALSE(LHS < RHS); + EXPECT_TRUE(LHS > RHS); + EXPECT_FALSE(LHS <= RHS); + EXPECT_TRUE(LHS >= RHS); + }; + Relation UN = [](const APFloat &LHS, const APFloat &RHS) { + EXPECT_FALSE(LHS == RHS); + EXPECT_TRUE(LHS != RHS); + EXPECT_FALSE(LHS < RHS); + EXPECT_FALSE(LHS > RHS); + EXPECT_FALSE(LHS <= RHS); + EXPECT_FALSE(LHS >= RHS); + }; + Relation Relations[NumVals][NumVals] = { + // -N -I -B -1 -0 +0 +1 +B +I +N + /* MNan */ {UN, UN, UN, UN, UN, UN, UN, UN, UN, UN}, + /* MInf */ {UN, EQ, LT, LT, LT, LT, LT, LT, LT, UN}, + /* MBig */ {UN, GT, EQ, LT, LT, LT, LT, LT, LT, UN}, + /* MOne */ {UN, GT, GT, EQ, LT, LT, LT, LT, LT, UN}, + /* MZer */ {UN, GT, GT, GT, EQ, EQ, LT, LT, LT, UN}, + /* PZer */ {UN, GT, GT, GT, EQ, EQ, LT, LT, LT, UN}, + /* POne */ {UN, GT, GT, GT, GT, GT, EQ, LT, LT, UN}, + /* PBig */ {UN, GT, GT, GT, GT, GT, GT, EQ, LT, UN}, + /* PInf */ {UN, GT, GT, GT, GT, GT, GT, GT, EQ, UN}, + /* PNan */ {UN, UN, UN, UN, UN, UN, UN, UN, UN, UN}, + }; + for (unsigned I = 0; I < NumVals; ++I) + for (unsigned J = 0; J < NumVals; ++J) + Relations[I][J](Vals[I], Vals[J]); +} + TEST(APFloatTest, abs) { APFloat PInf = APFloat::getInf(APFloat::IEEEsingle(), false); APFloat MInf = APFloat::getInf(APFloat::IEEEsingle(), true); -- 2.7.4