Skip to content

Commit 19c3894

Browse files
author
Siva Chandra Reddy
committed
[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
1 parent bc044a8 commit 19c3894

File tree

6 files changed

+168
-239
lines changed

6 files changed

+168
-239
lines changed

libc/test/src/math/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,8 @@ add_fp_unittest(
686686
libc_math_unittests
687687
SRCS
688688
remquof_test.cpp
689+
HDRS
690+
RemQuoTest.h
689691
DEPENDS
690692
libc.include.math
691693
libc.src.math.remquof
@@ -699,6 +701,8 @@ add_fp_unittest(
699701
libc_math_unittests
700702
SRCS
701703
remquo_test.cpp
704+
HDRS
705+
RemQuoTest.h
702706
DEPENDS
703707
libc.include.math
704708
libc.src.math.remquo
@@ -712,6 +716,8 @@ add_fp_unittest(
712716
libc_math_unittests
713717
SRCS
714718
remquol_test.cpp
719+
HDRS
720+
RemQuoTest.h
715721
DEPENDS
716722
libc.include.math
717723
libc.src.math.remquol

libc/test/src/math/RemQuoTest.h

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
//===-- Utility class to test different flavors of remquo -------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_TEST_SRC_MATH_REMQUOTEST_H
10+
#define LLVM_LIBC_TEST_SRC_MATH_REMQUOTEST_H
11+
12+
#include "utils/FPUtil/BasicOperations.h"
13+
#include "utils/FPUtil/FPBits.h"
14+
#include "utils/FPUtil/TestHelpers.h"
15+
#include "utils/MPFRWrapper/MPFRUtils.h"
16+
#include "utils/UnitTest/Test.h"
17+
#include <math.h>
18+
19+
namespace mpfr = __llvm_libc::testing::mpfr;
20+
21+
template <typename T>
22+
class RemQuoTestTemplate : public __llvm_libc::testing::Test {
23+
using FPBits = __llvm_libc::fputil::FPBits<T>;
24+
using UIntType = typename FPBits::UIntType;
25+
26+
const T zero = __llvm_libc::fputil::FPBits<T>::zero();
27+
const T negZero = __llvm_libc::fputil::FPBits<T>::negZero();
28+
const T inf = __llvm_libc::fputil::FPBits<T>::inf();
29+
const T negInf = __llvm_libc::fputil::FPBits<T>::negInf();
30+
const T nan = __llvm_libc::fputil::FPBits<T>::buildNaN(1);
31+
32+
public:
33+
typedef T (*RemQuoFunc)(T, T, int *);
34+
35+
void testSpecialNumbers(RemQuoFunc func) {
36+
int quotient;
37+
T x, y;
38+
39+
y = T(1.0);
40+
x = inf;
41+
EXPECT_NE(isnan(func(x, y, &quotient)), 0);
42+
x = negInf;
43+
EXPECT_NE(isnan(func(x, y, &quotient)), 0);
44+
45+
x = T(1.0);
46+
y = zero;
47+
EXPECT_NE(isnan(func(x, y, &quotient)), 0);
48+
y = negZero;
49+
EXPECT_NE(isnan(func(x, y, &quotient)), 0);
50+
51+
y = nan;
52+
x = T(1.0);
53+
EXPECT_NE(isnan(func(x, y, &quotient)), 0);
54+
55+
y = T(1.0);
56+
x = nan;
57+
EXPECT_NE(isnan(func(x, y, &quotient)), 0);
58+
59+
x = nan;
60+
y = nan;
61+
EXPECT_NE(isnan(func(x, y, &quotient)), 0);
62+
63+
x = zero;
64+
y = T(1.0);
65+
EXPECT_FP_EQ(func(x, y, &quotient), zero);
66+
67+
x = negZero;
68+
y = T(1.0);
69+
EXPECT_FP_EQ(func(x, y, &quotient), negZero);
70+
71+
x = T(1.125);
72+
y = inf;
73+
EXPECT_FP_EQ(func(x, y, &quotient), x);
74+
EXPECT_EQ(quotient, 0);
75+
}
76+
77+
void testEqualNumeratorAndDenominator(RemQuoFunc func) {
78+
T x = T(1.125), y = T(1.125);
79+
int q;
80+
81+
// When the remainder is zero, the standard requires it to
82+
// have the same sign as x.
83+
84+
EXPECT_FP_EQ(func(x, y, &q), zero);
85+
EXPECT_EQ(q, 1);
86+
87+
EXPECT_FP_EQ(func(x, -y, &q), zero);
88+
EXPECT_EQ(q, -1);
89+
90+
EXPECT_FP_EQ(func(-x, y, &q), negZero);
91+
EXPECT_EQ(q, -1);
92+
93+
EXPECT_FP_EQ(func(-x, -y, &q), negZero);
94+
EXPECT_EQ(q, 1);
95+
}
96+
97+
void testSubnormalRange(RemQuoFunc func) {
98+
constexpr UIntType count = 1000001;
99+
constexpr UIntType step =
100+
(FPBits::maxSubnormal - FPBits::minSubnormal) / count;
101+
for (UIntType v = FPBits::minSubnormal, w = FPBits::maxSubnormal;
102+
v <= FPBits::maxSubnormal && w >= FPBits::minSubnormal;
103+
v += step, w -= step) {
104+
T x = FPBits(v), y = FPBits(w);
105+
mpfr::BinaryOutput<T> result;
106+
mpfr::BinaryInput<T> input{x, y};
107+
result.f = func(x, y, &result.i);
108+
ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
109+
}
110+
}
111+
112+
void testNormalRange(RemQuoFunc func) {
113+
constexpr UIntType count = 1000001;
114+
constexpr UIntType step = (FPBits::maxNormal - FPBits::minNormal) / count;
115+
for (UIntType v = FPBits::minNormal, w = FPBits::maxNormal;
116+
v <= FPBits::maxNormal && w >= FPBits::minNormal;
117+
v += step, w -= step) {
118+
T x = FPBits(v), y = FPBits(w);
119+
mpfr::BinaryOutput<T> result;
120+
mpfr::BinaryInput<T> input{x, y};
121+
result.f = func(x, y, &result.i);
122+
123+
// In normal range on x86 platforms, the long double implicit 1 bit can be
124+
// zero making the numbers NaN. Hence we test for them separately.
125+
if (isnan(x) || isnan(y)) {
126+
ASSERT_NE(isnan(result.f), 0);
127+
continue;
128+
}
129+
130+
ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
131+
}
132+
}
133+
};
134+
135+
#define LIST_REMQUO_TESTS(T, func) \
136+
using RemQuoTest = RemQuoTestTemplate<T>; \
137+
TEST_F(RemQuoTest, SpecialNumbers) { testSpecialNumbers(&func); } \
138+
TEST_F(RemQuoTest, EqualNumeratorAndDenominator) { \
139+
testEqualNumeratorAndDenominator(&func); \
140+
} \
141+
TEST_F(RemQuoTest, SubnormalRange) { testSubnormalRange(&func); } \
142+
TEST_F(RemQuoTest, NormalRange) { testNormalRange(&func); }
143+
144+
#endif // LLVM_LIBC_TEST_SRC_MATH_REMQUOTEST_H

libc/test/src/math/remquo_test.cpp

Lines changed: 3 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -6,82 +6,8 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
#include "src/math/remquo.h"
10-
#include "utils/FPUtil/BasicOperations.h"
11-
#include "utils/FPUtil/FPBits.h"
12-
#include "utils/FPUtil/TestHelpers.h"
13-
#include "utils/MPFRWrapper/MPFRUtils.h"
14-
#include "utils/UnitTest/Test.h"
15-
#include <math.h>
16-
17-
using FPBits = __llvm_libc::fputil::FPBits<double>;
18-
using UIntType = FPBits::UIntType;
19-
20-
namespace mpfr = __llvm_libc::testing::mpfr;
21-
22-
DECLARE_SPECIAL_CONSTANTS(double)
23-
24-
TEST(RemquoTest, SpecialNumbers) {
25-
int exponent;
26-
double x, y;
27-
28-
y = 1.0;
29-
x = inf;
30-
EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
31-
x = negInf;
32-
EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
33-
34-
x = 1.0;
35-
y = zero;
36-
EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
37-
y = negZero;
38-
EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
9+
#include "RemQuoTest.h"
3910

40-
y = nan;
41-
x = 1.0;
42-
EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
43-
44-
y = 1.0;
45-
x = nan;
46-
EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
47-
48-
x = nan;
49-
y = nan;
50-
EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
51-
52-
x = zero;
53-
y = 1.0;
54-
EXPECT_FP_EQ(__llvm_libc::remquo(x, y, &exponent), zero);
55-
56-
x = negZero;
57-
y = 1.0;
58-
EXPECT_FP_EQ(__llvm_libc::remquo(x, y, &exponent), negZero);
59-
}
60-
61-
TEST(RemquoTest, SubnormalRange) {
62-
constexpr UIntType count = 1000001;
63-
constexpr UIntType step =
64-
(FPBits::maxSubnormal - FPBits::minSubnormal) / count;
65-
for (UIntType v = FPBits::minSubnormal, w = FPBits::maxSubnormal;
66-
v <= FPBits::maxSubnormal && w >= FPBits::minSubnormal;
67-
v += step, w -= step) {
68-
double x = FPBits(v), y = FPBits(w);
69-
mpfr::BinaryOutput<double> result;
70-
mpfr::BinaryInput<double> input{x, y};
71-
result.f = __llvm_libc::remquo(x, y, &result.i);
72-
ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
73-
}
74-
}
11+
#include "src/math/remquo.h"
7512

76-
TEST(RemquoTest, NormalRange) {
77-
constexpr UIntType count = 1000001;
78-
constexpr UIntType step = (FPBits::maxNormal - FPBits::minNormal) / count;
79-
for (UIntType v = FPBits::minNormal, w = FPBits::maxNormal;
80-
v <= FPBits::maxNormal && w >= FPBits::minNormal; v += step, w -= step) {
81-
double x = FPBits(v), y = FPBits(w);
82-
mpfr::BinaryOutput<double> result;
83-
mpfr::BinaryInput<double> input{x, y};
84-
result.f = __llvm_libc::remquo(x, y, &result.i);
85-
ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
86-
}
87-
}
13+
LIST_REMQUO_TESTS(double, __llvm_libc::remquo)

libc/test/src/math/remquof_test.cpp

Lines changed: 3 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -6,82 +6,8 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
#include "src/math/remquof.h"
10-
#include "utils/FPUtil/BasicOperations.h"
11-
#include "utils/FPUtil/FPBits.h"
12-
#include "utils/FPUtil/TestHelpers.h"
13-
#include "utils/MPFRWrapper/MPFRUtils.h"
14-
#include "utils/UnitTest/Test.h"
15-
#include <math.h>
16-
17-
using FPBits = __llvm_libc::fputil::FPBits<float>;
18-
using UIntType = FPBits::UIntType;
19-
20-
namespace mpfr = __llvm_libc::testing::mpfr;
21-
22-
DECLARE_SPECIAL_CONSTANTS(float)
23-
24-
TEST(RemquofTest, SpecialNumbers) {
25-
int exponent;
26-
float x, y;
27-
28-
y = 1.0f;
29-
x = inf;
30-
EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
31-
x = negInf;
32-
EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
33-
34-
x = 1.0f;
35-
y = zero;
36-
EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
37-
y = negZero;
38-
EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
9+
#include "RemQuoTest.h"
3910

40-
y = nan;
41-
x = 1.0f;
42-
EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
43-
44-
y = 1.0f;
45-
x = nan;
46-
EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
47-
48-
x = nan;
49-
y = nan;
50-
EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
51-
52-
x = zero;
53-
y = 1.0f;
54-
EXPECT_FP_EQ(__llvm_libc::remquof(x, y, &exponent), zero);
55-
56-
x = negZero;
57-
y = 1.0f;
58-
EXPECT_FP_EQ(__llvm_libc::remquof(x, y, &exponent), negZero);
59-
}
60-
61-
TEST(RemquofTest, SubnormalRange) {
62-
constexpr UIntType count = 1000001;
63-
constexpr UIntType step =
64-
(FPBits::maxSubnormal - FPBits::minSubnormal) / count;
65-
for (UIntType v = FPBits::minSubnormal, w = FPBits::maxSubnormal;
66-
v <= FPBits::maxSubnormal && w >= FPBits::minSubnormal;
67-
v += step, w -= step) {
68-
float x = FPBits(v), y = FPBits(w);
69-
mpfr::BinaryOutput<float> result;
70-
mpfr::BinaryInput<float> input{x, y};
71-
result.f = __llvm_libc::remquof(x, y, &result.i);
72-
ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
73-
}
74-
}
11+
#include "src/math/remquof.h"
7512

76-
TEST(RemquofTest, NormalRange) {
77-
constexpr UIntType count = 1000001;
78-
constexpr UIntType step = (FPBits::maxNormal - FPBits::minNormal) / count;
79-
for (UIntType v = FPBits::minNormal, w = FPBits::maxNormal;
80-
v <= FPBits::maxNormal && w >= FPBits::minNormal; v += step, w -= step) {
81-
float x = FPBits(v), y = FPBits(w);
82-
mpfr::BinaryOutput<float> result;
83-
mpfr::BinaryInput<float> input{x, y};
84-
result.f = __llvm_libc::remquof(x, y, &result.i);
85-
ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
86-
}
87-
}
13+
LIST_REMQUO_TESTS(float, __llvm_libc::remquof)

0 commit comments

Comments
 (0)