[llvm] r299256 - Fix APFloat mod (committing for simonbyrne)
Stephen Canon via llvm-commits
llvm-commits at lists.llvm.org
Fri Mar 31 13:31:33 PDT 2017
Author: scanon
Date: Fri Mar 31 15:31:33 2017
New Revision: 299256
URL: http://llvm.org/viewvc/llvm-project?rev=299256&view=rev
Log:
Fix APFloat mod (committing for simonbyrne)
The previous version was prone to intermediate rounding or overflow.
Differential Revision: https://reviews.llvm.org/D29346
Modified:
llvm/trunk/lib/Support/APFloat.cpp
llvm/trunk/unittests/ADT/APFloatTest.cpp
Modified: llvm/trunk/lib/Support/APFloat.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/APFloat.cpp?rev=299256&r1=299255&r2=299256&view=diff
==============================================================================
--- llvm/trunk/lib/Support/APFloat.cpp (original)
+++ llvm/trunk/lib/Support/APFloat.cpp Fri Mar 31 15:31:33 2017
@@ -1740,44 +1740,20 @@ IEEEFloat::opStatus IEEEFloat::remainder
return fs;
}
-/* Normalized llvm frem (C fmod).
- This is not currently correct in all cases. */
+/* Normalized llvm frem (C fmod). */
IEEEFloat::opStatus IEEEFloat::mod(const IEEEFloat &rhs) {
opStatus fs;
fs = modSpecials(rhs);
- if (isFiniteNonZero() && rhs.isFiniteNonZero()) {
- IEEEFloat V = *this;
- unsigned int origSign = sign;
-
- fs = V.divide(rhs, rmNearestTiesToEven);
- if (fs == opDivByZero)
- return fs;
-
- int parts = partCount();
- integerPart *x = new integerPart[parts];
- bool ignored;
- fs = V.convertToInteger(makeMutableArrayRef(x, parts),
- parts * integerPartWidth, true, rmTowardZero,
- &ignored);
- if (fs == opInvalidOp) {
- delete[] x;
- return fs;
- }
-
- fs = V.convertFromZeroExtendedInteger(x, parts * integerPartWidth, true,
- rmNearestTiesToEven);
- assert(fs==opOK); // should always work
-
- fs = V.multiply(rhs, rmNearestTiesToEven);
- assert(fs==opOK || fs==opInexact); // should not overflow or underflow
-
+ while (isFiniteNonZero() && rhs.isFiniteNonZero() &&
+ compareAbsoluteValue(rhs) != cmpLessThan) {
+ IEEEFloat V = scalbn(rhs, ilogb(*this) - ilogb(rhs), rmNearestTiesToEven);
+ if (compareAbsoluteValue(V) == cmpLessThan)
+ V = scalbn(V, -1, rmNearestTiesToEven);
+ V.sign = sign;
+
fs = subtract(V, rmNearestTiesToEven);
- assert(fs==opOK || fs==opInexact); // likewise
-
- if (isZero())
- sign = origSign; // IEEE754 requires this
- delete[] x;
+ assert(fs==opOK);
}
return fs;
}
Modified: llvm/trunk/unittests/ADT/APFloatTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/APFloatTest.cpp?rev=299256&r1=299255&r2=299256&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/APFloatTest.cpp (original)
+++ llvm/trunk/unittests/ADT/APFloatTest.cpp Fri Mar 31 15:31:33 2017
@@ -3192,10 +3192,73 @@ TEST(APFloatTest, frexp) {
EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1.c60f120d9f87cp-1").bitwiseIsEqual(Frac));
}
+TEST(APFloatTest, mod) {
+ {
+ APFloat f1(APFloat::IEEEdouble(), "1.5");
+ APFloat f2(APFloat::IEEEdouble(), "1.0");
+ APFloat expected(APFloat::IEEEdouble(), "0.5");
+ EXPECT_EQ(f1.mod(f2), APFloat::opOK);
+ EXPECT_TRUE(f1.bitwiseIsEqual(expected));
+ }
+ {
+ APFloat f1(APFloat::IEEEdouble(), "0.5");
+ APFloat f2(APFloat::IEEEdouble(), "1.0");
+ APFloat expected(APFloat::IEEEdouble(), "0.5");
+ EXPECT_EQ(f1.mod(f2), APFloat::opOK);
+ EXPECT_TRUE(f1.bitwiseIsEqual(expected));
+ }
+ {
+ APFloat f1(APFloat::IEEEdouble(), "0x1.3333333333333p-2"); // 0.3
+ APFloat f2(APFloat::IEEEdouble(), "0x1.47ae147ae147bp-7"); // 0.01
+ APFloat expected(APFloat::IEEEdouble(),
+ "0x1.47ae147ae1471p-7"); // 0.009999999999999983
+ EXPECT_EQ(f1.mod(f2), APFloat::opOK);
+ EXPECT_TRUE(f1.bitwiseIsEqual(expected));
+ }
+ {
+ APFloat f1(APFloat::IEEEdouble(), "0x1p64"); // 1.8446744073709552e19
+ APFloat f2(APFloat::IEEEdouble(), "1.5");
+ APFloat expected(APFloat::IEEEdouble(), "1.0");
+ EXPECT_EQ(f1.mod(f2), APFloat::opOK);
+ EXPECT_TRUE(f1.bitwiseIsEqual(expected));
+ }
+ {
+ APFloat f1(APFloat::IEEEdouble(), "0x1p1000");
+ APFloat f2(APFloat::IEEEdouble(), "0x1p-1000");
+ APFloat expected(APFloat::IEEEdouble(), "0.0");
+ EXPECT_EQ(f1.mod(f2), APFloat::opOK);
+ EXPECT_TRUE(f1.bitwiseIsEqual(expected));
+ }
+ {
+ APFloat f1(APFloat::IEEEdouble(), "0.0");
+ APFloat f2(APFloat::IEEEdouble(), "1.0");
+ APFloat expected(APFloat::IEEEdouble(), "0.0");
+ EXPECT_EQ(f1.mod(f2), APFloat::opOK);
+ EXPECT_TRUE(f1.bitwiseIsEqual(expected));
+ }
+ {
+ APFloat f1(APFloat::IEEEdouble(), "1.0");
+ APFloat f2(APFloat::IEEEdouble(), "0.0");
+ EXPECT_EQ(f1.mod(f2), APFloat::opInvalidOp);
+ EXPECT_TRUE(f1.isNaN());
+ }
+ {
+ APFloat f1(APFloat::IEEEdouble(), "0.0");
+ APFloat f2(APFloat::IEEEdouble(), "0.0");
+ EXPECT_EQ(f1.mod(f2), APFloat::opInvalidOp);
+ EXPECT_TRUE(f1.isNaN());
+ }
+ {
+ APFloat f1 = APFloat::getInf(APFloat::IEEEdouble(), false);
+ APFloat f2(APFloat::IEEEdouble(), "1.0");
+ EXPECT_EQ(f1.mod(f2), APFloat::opInvalidOp);
+ EXPECT_TRUE(f1.isNaN());
+ }
+}
+
TEST(APFloatTest, PPCDoubleDoubleAddSpecial) {
using DataType = std::tuple<uint64_t, uint64_t, uint64_t, uint64_t,
- APFloat::fltCategory, APFloat::roundingMode>;
- DataType Data[] = {
+ APFloat::fltCategory, APFloat::roundingMode>; DataType Data[] = {
// (1 + 0) + (-1 + 0) = fcZero
std::make_tuple(0x3ff0000000000000ull, 0, 0xbff0000000000000ull, 0,
APFloat::fcZero, APFloat::rmNearestTiesToEven),
More information about the llvm-commits
mailing list