[libc] Fix couple of corner cases in remquo.

These two cases are fixed:
1. If numerator is not zero and denominator is infinity, then the
numerator is returned as the remainder.
2. If numerator and denominator are equal in magnitude, then quotient
with the right sign is returned.

The differet tests of remquo, remquof and remquol have been unified
into a single file to avoid duplication.

Reviewed By: lntue

Differential Revision: https://reviews.llvm.org/D92353

GitOrigin-RevId: 19c3894f9436ef68f33f80ee1fd589166267b5a1
diff --git a/test/src/math/CMakeLists.txt b/test/src/math/CMakeLists.txt
index 2220cef..cdffe73 100644
--- a/test/src/math/CMakeLists.txt
+++ b/test/src/math/CMakeLists.txt
@@ -686,6 +686,8 @@
     libc_math_unittests
   SRCS
     remquof_test.cpp
+  HDRS
+    RemQuoTest.h
   DEPENDS
     libc.include.math
     libc.src.math.remquof
@@ -699,6 +701,8 @@
     libc_math_unittests
   SRCS
     remquo_test.cpp
+  HDRS
+    RemQuoTest.h
   DEPENDS
     libc.include.math
     libc.src.math.remquo
@@ -712,6 +716,8 @@
     libc_math_unittests
   SRCS
     remquol_test.cpp
+  HDRS
+    RemQuoTest.h
   DEPENDS
     libc.include.math
     libc.src.math.remquol
diff --git a/test/src/math/RemQuoTest.h b/test/src/math/RemQuoTest.h
new file mode 100644
index 0000000..29fcdb8
--- /dev/null
+++ b/test/src/math/RemQuoTest.h
@@ -0,0 +1,144 @@
+//===-- Utility class to test different flavors of remquo -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_TEST_SRC_MATH_REMQUOTEST_H
+#define LLVM_LIBC_TEST_SRC_MATH_REMQUOTEST_H
+
+#include "utils/FPUtil/BasicOperations.h"
+#include "utils/FPUtil/FPBits.h"
+#include "utils/FPUtil/TestHelpers.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+#include "utils/UnitTest/Test.h"
+#include <math.h>
+
+namespace mpfr = __llvm_libc::testing::mpfr;
+
+template <typename T>
+class RemQuoTestTemplate : public __llvm_libc::testing::Test {
+  using FPBits = __llvm_libc::fputil::FPBits<T>;
+  using UIntType = typename FPBits::UIntType;
+
+  const T zero = __llvm_libc::fputil::FPBits<T>::zero();
+  const T negZero = __llvm_libc::fputil::FPBits<T>::negZero();
+  const T inf = __llvm_libc::fputil::FPBits<T>::inf();
+  const T negInf = __llvm_libc::fputil::FPBits<T>::negInf();
+  const T nan = __llvm_libc::fputil::FPBits<T>::buildNaN(1);
+
+public:
+  typedef T (*RemQuoFunc)(T, T, int *);
+
+  void testSpecialNumbers(RemQuoFunc func) {
+    int quotient;
+    T x, y;
+
+    y = T(1.0);
+    x = inf;
+    EXPECT_NE(isnan(func(x, y, &quotient)), 0);
+    x = negInf;
+    EXPECT_NE(isnan(func(x, y, &quotient)), 0);
+
+    x = T(1.0);
+    y = zero;
+    EXPECT_NE(isnan(func(x, y, &quotient)), 0);
+    y = negZero;
+    EXPECT_NE(isnan(func(x, y, &quotient)), 0);
+
+    y = nan;
+    x = T(1.0);
+    EXPECT_NE(isnan(func(x, y, &quotient)), 0);
+
+    y = T(1.0);
+    x = nan;
+    EXPECT_NE(isnan(func(x, y, &quotient)), 0);
+
+    x = nan;
+    y = nan;
+    EXPECT_NE(isnan(func(x, y, &quotient)), 0);
+
+    x = zero;
+    y = T(1.0);
+    EXPECT_FP_EQ(func(x, y, &quotient), zero);
+
+    x = negZero;
+    y = T(1.0);
+    EXPECT_FP_EQ(func(x, y, &quotient), negZero);
+
+    x = T(1.125);
+    y = inf;
+    EXPECT_FP_EQ(func(x, y, &quotient), x);
+    EXPECT_EQ(quotient, 0);
+  }
+
+  void testEqualNumeratorAndDenominator(RemQuoFunc func) {
+    T x = T(1.125), y = T(1.125);
+    int q;
+
+    // When the remainder is zero, the standard requires it to
+    // have the same sign as x.
+
+    EXPECT_FP_EQ(func(x, y, &q), zero);
+    EXPECT_EQ(q, 1);
+
+    EXPECT_FP_EQ(func(x, -y, &q), zero);
+    EXPECT_EQ(q, -1);
+
+    EXPECT_FP_EQ(func(-x, y, &q), negZero);
+    EXPECT_EQ(q, -1);
+
+    EXPECT_FP_EQ(func(-x, -y, &q), negZero);
+    EXPECT_EQ(q, 1);
+  }
+
+  void testSubnormalRange(RemQuoFunc func) {
+    constexpr UIntType count = 1000001;
+    constexpr UIntType step =
+        (FPBits::maxSubnormal - FPBits::minSubnormal) / count;
+    for (UIntType v = FPBits::minSubnormal, w = FPBits::maxSubnormal;
+         v <= FPBits::maxSubnormal && w >= FPBits::minSubnormal;
+         v += step, w -= step) {
+      T x = FPBits(v), y = FPBits(w);
+      mpfr::BinaryOutput<T> result;
+      mpfr::BinaryInput<T> input{x, y};
+      result.f = func(x, y, &result.i);
+      ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
+    }
+  }
+
+  void testNormalRange(RemQuoFunc func) {
+    constexpr UIntType count = 1000001;
+    constexpr UIntType step = (FPBits::maxNormal - FPBits::minNormal) / count;
+    for (UIntType v = FPBits::minNormal, w = FPBits::maxNormal;
+         v <= FPBits::maxNormal && w >= FPBits::minNormal;
+         v += step, w -= step) {
+      T x = FPBits(v), y = FPBits(w);
+      mpfr::BinaryOutput<T> result;
+      mpfr::BinaryInput<T> input{x, y};
+      result.f = func(x, y, &result.i);
+
+      // In normal range on x86 platforms, the long double implicit 1 bit can be
+      // zero making the numbers NaN. Hence we test for them separately.
+      if (isnan(x) || isnan(y)) {
+        ASSERT_NE(isnan(result.f), 0);
+        continue;
+      }
+
+      ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
+    }
+  }
+};
+
+#define LIST_REMQUO_TESTS(T, func)                                             \
+  using RemQuoTest = RemQuoTestTemplate<T>;                                    \
+  TEST_F(RemQuoTest, SpecialNumbers) { testSpecialNumbers(&func); }            \
+  TEST_F(RemQuoTest, EqualNumeratorAndDenominator) {                           \
+    testEqualNumeratorAndDenominator(&func);                                   \
+  }                                                                            \
+  TEST_F(RemQuoTest, SubnormalRange) { testSubnormalRange(&func); }            \
+  TEST_F(RemQuoTest, NormalRange) { testNormalRange(&func); }
+
+#endif // LLVM_LIBC_TEST_SRC_MATH_REMQUOTEST_H
diff --git a/test/src/math/remquo_test.cpp b/test/src/math/remquo_test.cpp
index 197d970..8efec39 100644
--- a/test/src/math/remquo_test.cpp
+++ b/test/src/math/remquo_test.cpp
@@ -6,82 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "RemQuoTest.h"
+
 #include "src/math/remquo.h"
-#include "utils/FPUtil/BasicOperations.h"
-#include "utils/FPUtil/FPBits.h"
-#include "utils/FPUtil/TestHelpers.h"
-#include "utils/MPFRWrapper/MPFRUtils.h"
-#include "utils/UnitTest/Test.h"
-#include <math.h>
 
-using FPBits = __llvm_libc::fputil::FPBits<double>;
-using UIntType = FPBits::UIntType;
-
-namespace mpfr = __llvm_libc::testing::mpfr;
-
-DECLARE_SPECIAL_CONSTANTS(double)
-
-TEST(RemquoTest, SpecialNumbers) {
-  int exponent;
-  double x, y;
-
-  y = 1.0;
-  x = inf;
-  EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
-  x = negInf;
-  EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
-
-  x = 1.0;
-  y = zero;
-  EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
-  y = negZero;
-  EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
-
-  y = nan;
-  x = 1.0;
-  EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
-
-  y = 1.0;
-  x = nan;
-  EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
-
-  x = nan;
-  y = nan;
-  EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
-
-  x = zero;
-  y = 1.0;
-  EXPECT_FP_EQ(__llvm_libc::remquo(x, y, &exponent), zero);
-
-  x = negZero;
-  y = 1.0;
-  EXPECT_FP_EQ(__llvm_libc::remquo(x, y, &exponent), negZero);
-}
-
-TEST(RemquoTest, SubnormalRange) {
-  constexpr UIntType count = 1000001;
-  constexpr UIntType step =
-      (FPBits::maxSubnormal - FPBits::minSubnormal) / count;
-  for (UIntType v = FPBits::minSubnormal, w = FPBits::maxSubnormal;
-       v <= FPBits::maxSubnormal && w >= FPBits::minSubnormal;
-       v += step, w -= step) {
-    double x = FPBits(v), y = FPBits(w);
-    mpfr::BinaryOutput<double> result;
-    mpfr::BinaryInput<double> input{x, y};
-    result.f = __llvm_libc::remquo(x, y, &result.i);
-    ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
-  }
-}
-
-TEST(RemquoTest, NormalRange) {
-  constexpr UIntType count = 1000001;
-  constexpr UIntType step = (FPBits::maxNormal - FPBits::minNormal) / count;
-  for (UIntType v = FPBits::minNormal, w = FPBits::maxNormal;
-       v <= FPBits::maxNormal && w >= FPBits::minNormal; v += step, w -= step) {
-    double x = FPBits(v), y = FPBits(w);
-    mpfr::BinaryOutput<double> result;
-    mpfr::BinaryInput<double> input{x, y};
-    result.f = __llvm_libc::remquo(x, y, &result.i);
-    ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
-  }
-}
+LIST_REMQUO_TESTS(double, __llvm_libc::remquo)
diff --git a/test/src/math/remquof_test.cpp b/test/src/math/remquof_test.cpp
index 4ede7fb..1af4ba4 100644
--- a/test/src/math/remquof_test.cpp
+++ b/test/src/math/remquof_test.cpp
@@ -6,82 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "RemQuoTest.h"
+
 #include "src/math/remquof.h"
-#include "utils/FPUtil/BasicOperations.h"
-#include "utils/FPUtil/FPBits.h"
-#include "utils/FPUtil/TestHelpers.h"
-#include "utils/MPFRWrapper/MPFRUtils.h"
-#include "utils/UnitTest/Test.h"
-#include <math.h>
 
-using FPBits = __llvm_libc::fputil::FPBits<float>;
-using UIntType = FPBits::UIntType;
-
-namespace mpfr = __llvm_libc::testing::mpfr;
-
-DECLARE_SPECIAL_CONSTANTS(float)
-
-TEST(RemquofTest, SpecialNumbers) {
-  int exponent;
-  float x, y;
-
-  y = 1.0f;
-  x = inf;
-  EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
-  x = negInf;
-  EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
-
-  x = 1.0f;
-  y = zero;
-  EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
-  y = negZero;
-  EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
-
-  y = nan;
-  x = 1.0f;
-  EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
-
-  y = 1.0f;
-  x = nan;
-  EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
-
-  x = nan;
-  y = nan;
-  EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
-
-  x = zero;
-  y = 1.0f;
-  EXPECT_FP_EQ(__llvm_libc::remquof(x, y, &exponent), zero);
-
-  x = negZero;
-  y = 1.0f;
-  EXPECT_FP_EQ(__llvm_libc::remquof(x, y, &exponent), negZero);
-}
-
-TEST(RemquofTest, SubnormalRange) {
-  constexpr UIntType count = 1000001;
-  constexpr UIntType step =
-      (FPBits::maxSubnormal - FPBits::minSubnormal) / count;
-  for (UIntType v = FPBits::minSubnormal, w = FPBits::maxSubnormal;
-       v <= FPBits::maxSubnormal && w >= FPBits::minSubnormal;
-       v += step, w -= step) {
-    float x = FPBits(v), y = FPBits(w);
-    mpfr::BinaryOutput<float> result;
-    mpfr::BinaryInput<float> input{x, y};
-    result.f = __llvm_libc::remquof(x, y, &result.i);
-    ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
-  }
-}
-
-TEST(RemquofTest, NormalRange) {
-  constexpr UIntType count = 1000001;
-  constexpr UIntType step = (FPBits::maxNormal - FPBits::minNormal) / count;
-  for (UIntType v = FPBits::minNormal, w = FPBits::maxNormal;
-       v <= FPBits::maxNormal && w >= FPBits::minNormal; v += step, w -= step) {
-    float x = FPBits(v), y = FPBits(w);
-    mpfr::BinaryOutput<float> result;
-    mpfr::BinaryInput<float> input{x, y};
-    result.f = __llvm_libc::remquof(x, y, &result.i);
-    ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
-  }
-}
+LIST_REMQUO_TESTS(float, __llvm_libc::remquof)
diff --git a/test/src/math/remquol_test.cpp b/test/src/math/remquol_test.cpp
index 1539aab..e4438e8 100644
--- a/test/src/math/remquol_test.cpp
+++ b/test/src/math/remquol_test.cpp
@@ -6,88 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "RemQuoTest.h"
+
 #include "src/math/remquol.h"
-#include "utils/FPUtil/BasicOperations.h"
-#include "utils/FPUtil/FPBits.h"
-#include "utils/FPUtil/TestHelpers.h"
-#include "utils/MPFRWrapper/MPFRUtils.h"
-#include "utils/UnitTest/Test.h"
-#include <math.h>
 
-using FPBits = __llvm_libc::fputil::FPBits<long double>;
-using UIntType = FPBits::UIntType;
-
-namespace mpfr = __llvm_libc::testing::mpfr;
-
-DECLARE_SPECIAL_CONSTANTS(long double)
-
-TEST(RemquolTest, SpecialNumbers) {
-  int exponent;
-  long double x, y;
-
-  y = 1.0l;
-  x = inf;
-  EXPECT_NE(isnan(__llvm_libc::remquol(x, y, &exponent)), 0);
-  x = negInf;
-  EXPECT_NE(isnan(__llvm_libc::remquol(x, y, &exponent)), 0);
-
-  x = 1.0l;
-  y = zero;
-  EXPECT_NE(isnan(__llvm_libc::remquol(x, y, &exponent)), 0);
-  y = negZero;
-  EXPECT_NE(isnan(__llvm_libc::remquol(x, y, &exponent)), 0);
-
-  y = nan;
-  x = 1.0l;
-  EXPECT_NE(isnan(__llvm_libc::remquol(x, y, &exponent)), 0);
-
-  y = 1.0l;
-  x = nan;
-  EXPECT_NE(isnan(__llvm_libc::remquol(x, y, &exponent)), 0);
-
-  x = nan;
-  y = nan;
-  EXPECT_NE(isnan(__llvm_libc::remquol(x, y, &exponent)), 0);
-
-  x = zero;
-  y = 1.0l;
-  EXPECT_FP_EQ(__llvm_libc::remquol(x, y, &exponent), zero);
-
-  x = negZero;
-  y = 1.0l;
-  EXPECT_FP_EQ(__llvm_libc::remquol(x, y, &exponent), negZero);
-}
-
-TEST(RemquolTest, SubnormalRange) {
-  constexpr UIntType count = 1000001;
-  constexpr UIntType step =
-      (FPBits::maxSubnormal - FPBits::minSubnormal) / count;
-  for (UIntType v = FPBits::minSubnormal, w = FPBits::maxSubnormal;
-       v <= FPBits::maxSubnormal && w >= FPBits::minSubnormal;
-       v += step, w -= step) {
-    long double x = FPBits(v), y = FPBits(w);
-    mpfr::BinaryOutput<long double> result;
-    mpfr::BinaryInput<long double> input{x, y};
-    result.f = __llvm_libc::remquol(x, y, &result.i);
-    ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
-  }
-}
-
-TEST(RemquolTest, NormalRange) {
-  constexpr UIntType count = 1000001;
-  constexpr UIntType step = (FPBits::maxNormal - FPBits::minNormal) / count;
-  for (UIntType v = FPBits::minNormal, w = FPBits::maxNormal;
-       v <= FPBits::maxNormal && w >= FPBits::minNormal; v += step, w -= step) {
-    long double x = FPBits(v), y = FPBits(w);
-    mpfr::BinaryOutput<long double> result;
-    result.f = __llvm_libc::remquol(x, y, &result.i);
-    // In normal range on x86 platforms, the implicit 1 bit can be zero making
-    // the numbers NaN. Hence we test for them separately.
-    if (isnan(x) || isnan(y)) {
-      ASSERT_NE(isnan(result.f), 0);
-    } else {
-      mpfr::BinaryInput<long double> input{x, y};
-      ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
-    }
-  }
-}
+LIST_REMQUO_TESTS(long double, __llvm_libc::remquol)
diff --git a/utils/FPUtil/DivisionAndRemainderOperations.h b/utils/FPUtil/DivisionAndRemainderOperations.h
index ceae538..b4732c7 100644
--- a/utils/FPUtil/DivisionAndRemainderOperations.h
+++ b/utils/FPUtil/DivisionAndRemainderOperations.h
@@ -33,11 +33,16 @@
   if (xbits.isInf() || ybits.isZero())
     return FPBits<T>::buildNaN(1);
 
-  if (xbits.isZero() || ybits.isInf()) {
+  if (xbits.isZero()) {
     q = 0;
     return __llvm_libc::fputil::copysign(T(0.0), x);
   }
 
+  if (ybits.isInf()) {
+    q = 0;
+    return x;
+  }
+
   bool resultSign = (xbits.sign == ybits.sign ? false : true);
 
   // Once we know the sign of the result, we can just operate on the absolute
@@ -65,8 +70,10 @@
       q |= (1 << exp);
 
     mx = n - my;
-    if (mx == 0)
+    if (mx == 0) {
+      q = resultSign ? -q : q;
       return __llvm_libc::fputil::copysign(T(0.0), x);
+    }
   }
 
   NormalFloat<T> remainder(exp + normaly.exponent, mx, 0);