Skip to content

Commit 6f60d2b

Browse files
author
Job Henandez Lara
authored
[libc] Add mpfr tests for fmul. (#97376)
Fixes #94834
1 parent 410de0c commit 6f60d2b

File tree

5 files changed

+172
-7
lines changed

5 files changed

+172
-7
lines changed

libc/test/src/math/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1823,6 +1823,18 @@ add_fp_unittest(
18231823
libc.src.__support.FPUtil.fp_bits
18241824
)
18251825

1826+
add_fp_unittest(
1827+
fmul_test
1828+
NEED_MPFR
1829+
SUITE
1830+
libc-math-unittests
1831+
SRCS
1832+
fmul_test.cpp
1833+
HDRS
1834+
FMulTest.h
1835+
DEPENDS
1836+
libc.src.math.fmul
1837+
)
18261838
add_fp_unittest(
18271839
asinhf_test
18281840
NEED_MPFR

libc/test/src/math/FMulTest.h

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//===-- Utility class to test fmul[f|l] -------------------------*- 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_FMULTEST_H
10+
#define LLVM_LIBC_TEST_SRC_MATH_FMULTEST_H
11+
12+
#include "src/__support/FPUtil/FPBits.h"
13+
#include "test/UnitTest/FEnvSafeTest.h"
14+
#include "test/UnitTest/FPMatcher.h"
15+
#include "test/UnitTest/Test.h"
16+
#include "utils/MPFRWrapper/MPFRUtils.h"
17+
18+
namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
19+
20+
template <typename OutType, typename InType>
21+
class FmulMPFRTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
22+
23+
DECLARE_SPECIAL_CONSTANTS(InType)
24+
25+
public:
26+
typedef OutType (*FMulFunc)(InType, InType);
27+
28+
void testFMulMPFR(FMulFunc func) {
29+
constexpr int N = 10;
30+
mpfr::BinaryInput<InType> INPUTS[N] = {
31+
{3.0, 5.0},
32+
{0x1.0p1, 0x1.0p-131},
33+
{0x1.0p2, 0x1.0p-129},
34+
{1.0, 1.0},
35+
{-0.0, -0.0},
36+
{-0.0, 0.0},
37+
{0.0, -0.0},
38+
{0x1.0p100, 0x1.0p100},
39+
{1.0, 1.0 + 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150},
40+
{1.0, 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150}};
41+
42+
for (int i = 0; i < N; ++i) {
43+
InType x = INPUTS[i].x;
44+
InType y = INPUTS[i].y;
45+
ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Fmul, INPUTS[i],
46+
func(x, y), 0.5);
47+
}
48+
}
49+
50+
void testSpecialInputsMPFR(FMulFunc func) {
51+
constexpr int N = 27;
52+
mpfr::BinaryInput<InType> INPUTS[N] = {{inf, 0x1.0p-129},
53+
{0x1.0p-129, inf},
54+
{inf, 2.0},
55+
{3.0, inf},
56+
{0.0, 0.0},
57+
{neg_inf, aNaN},
58+
{aNaN, neg_inf},
59+
{neg_inf, neg_inf},
60+
{0.0, neg_inf},
61+
{neg_inf, 0.0},
62+
{neg_inf, 1.0},
63+
{1.0, neg_inf},
64+
{neg_inf, 0x1.0p-129},
65+
{0x1.0p-129, neg_inf},
66+
{0.0, 0x1.0p-129},
67+
{inf, 0.0},
68+
{0.0, inf},
69+
{0.0, aNaN},
70+
{2.0, aNaN},
71+
{0x1.0p-129, aNaN},
72+
{inf, aNaN},
73+
{aNaN, aNaN},
74+
{0.0, sNaN},
75+
{2.0, sNaN},
76+
{0x1.0p-129, sNaN},
77+
{inf, sNaN},
78+
{sNaN, sNaN}};
79+
80+
for (int i = 0; i < N; ++i) {
81+
InType x = INPUTS[i].x;
82+
InType y = INPUTS[i].y;
83+
ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Fmul, INPUTS[i],
84+
func(x, y), 0.5);
85+
}
86+
}
87+
88+
void testNormalRange(FMulFunc func) {
89+
using FPBits = LIBC_NAMESPACE::fputil::FPBits<InType>;
90+
using StorageType = typename FPBits::StorageType;
91+
static constexpr StorageType MAX_NORMAL = FPBits::max_normal().uintval();
92+
static constexpr StorageType MIN_NORMAL = FPBits::min_normal().uintval();
93+
94+
constexpr StorageType COUNT = 10'001;
95+
constexpr StorageType STEP = (MAX_NORMAL - MIN_NORMAL) / COUNT;
96+
for (int signs = 0; signs < 4; ++signs) {
97+
for (StorageType v = MIN_NORMAL, w = MAX_NORMAL;
98+
v <= MAX_NORMAL && w >= MIN_NORMAL; v += STEP, w -= STEP) {
99+
InType x = FPBits(v).get_val(), y = FPBits(w).get_val();
100+
if (signs % 2 == 1) {
101+
x = -x;
102+
}
103+
if (signs >= 2) {
104+
y = -y;
105+
}
106+
107+
mpfr::BinaryInput<InType> input{x, y};
108+
ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Fmul, input, func(x, y),
109+
0.5);
110+
}
111+
}
112+
}
113+
};
114+
115+
#define LIST_FMUL_MPFR_TESTS(OutType, InType, func) \
116+
using LlvmLibcFmulTest = FmulMPFRTest<OutType, InType>; \
117+
TEST_F(LlvmLibcFmulTest, MulMpfr) { testFMulMPFR(&func); } \
118+
TEST_F(LlvmLibcFmulTest, NanInfMpfr) { testSpecialInputsMPFR(&func); } \
119+
TEST_F(LlvmLibcFmulTest, NormalRange) { testNormalRange(&func); }
120+
121+
#endif // LLVM_LIBC_TEST_SRC_MATH_FMULTEST_H

libc/test/src/math/fmul_test.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//===-- Unittests for fmul-------------------------------------------------===//
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+
#include "FMulTest.h"
10+
11+
#include "src/math/fmul.h"
12+
13+
LIST_FMUL_MPFR_TESTS(float, double, LIBC_NAMESPACE::fmul)

libc/utils/MPFRWrapper/MPFRUtils.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,12 @@ class MPFRNumber {
487487
return result;
488488
}
489489

490+
MPFRNumber fmul(const MPFRNumber &b) {
491+
MPFRNumber result(*this);
492+
mpfr_mul(result.value, value, b.value, mpfr_rounding);
493+
return result;
494+
}
495+
490496
cpp::string str() const {
491497
// 200 bytes should be more than sufficient to hold a 100-digit number
492498
// plus additional bytes for the decimal point, '-' sign etc.
@@ -738,6 +744,8 @@ binary_operation_one_output(Operation op, InputType x, InputType y,
738744
return inputX.hypot(inputY);
739745
case Operation::Pow:
740746
return inputX.pow(inputY);
747+
case Operation::Fmul:
748+
return inputX.fmul(inputY);
741749
default:
742750
__builtin_unreachable();
743751
}
@@ -951,6 +959,9 @@ template void
951959
explain_binary_operation_one_output_error(Operation,
952960
const BinaryInput<long double> &,
953961
long double, double, RoundingMode);
962+
963+
template void explain_binary_operation_one_output_error(
964+
Operation, const BinaryInput<double> &, float, double, RoundingMode);
954965
#ifdef LIBC_TYPES_HAS_FLOAT16
955966
template void explain_binary_operation_one_output_error(
956967
Operation, const BinaryInput<float16> &, float16, double, RoundingMode);
@@ -1126,6 +1137,10 @@ template bool compare_binary_operation_one_output(Operation,
11261137
template bool
11271138
compare_binary_operation_one_output(Operation, const BinaryInput<long double> &,
11281139
long double, double, RoundingMode);
1140+
1141+
template bool compare_binary_operation_one_output(Operation,
1142+
const BinaryInput<double> &,
1143+
float, double, RoundingMode);
11291144
#ifdef LIBC_TYPES_HAS_FLOAT16
11301145
template bool compare_binary_operation_one_output(Operation,
11311146
const BinaryInput<float16> &,

libc/utils/MPFRWrapper/MPFRUtils.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ enum class Operation : int {
7676
Fmod,
7777
Hypot,
7878
Pow,
79+
Fmul,
7980
EndBinaryOperationsSingleOutput,
8081

8182
// Operations which take two floating point numbers of the same type as
@@ -237,7 +238,8 @@ class MPFRMatcher : public testing::Matcher<OutputType> {
237238
bool is_silent() const override { return silent; }
238239

239240
private:
240-
template <typename T, typename U> bool match(T in, U out) {
241+
template <typename InType, typename OutType>
242+
bool match(InType in, OutType out) {
241243
return compare_unary_operation_single_output(op, in, out, ulp_tolerance,
242244
rounding);
243245
}
@@ -259,13 +261,14 @@ class MPFRMatcher : public testing::Matcher<OutputType> {
259261
rounding);
260262
}
261263

262-
template <typename T, typename U>
263-
bool match(const TernaryInput<T> &in, U out) {
264+
template <typename InType, typename OutType>
265+
bool match(const TernaryInput<InType> &in, OutType out) {
264266
return compare_ternary_operation_one_output(op, in, out, ulp_tolerance,
265267
rounding);
266268
}
267269

268-
template <typename T, typename U> void explain_error(T in, U out) {
270+
template <typename InType, typename OutType>
271+
void explain_error(InType in, OutType out) {
269272
explain_unary_operation_single_output_error(op, in, out, ulp_tolerance,
270273
rounding);
271274
}
@@ -287,8 +290,8 @@ class MPFRMatcher : public testing::Matcher<OutputType> {
287290
rounding);
288291
}
289292

290-
template <typename T, typename U>
291-
void explain_error(const TernaryInput<T> &in, U out) {
293+
template <typename InType, typename OutType>
294+
void explain_error(const TernaryInput<InType> &in, OutType out) {
292295
explain_ternary_operation_one_output_error(op, in, out, ulp_tolerance,
293296
rounding);
294297
}
@@ -304,7 +307,8 @@ constexpr bool is_valid_operation() {
304307
(op == Operation::Sqrt && cpp::is_floating_point_v<InputType> &&
305308
cpp::is_floating_point_v<OutputType> &&
306309
sizeof(OutputType) <= sizeof(InputType)) ||
307-
(op == Operation::Div && internal::IsBinaryInput<InputType>::VALUE &&
310+
((op == Operation::Div || op == Operation::Fmul) &&
311+
internal::IsBinaryInput<InputType>::VALUE &&
308312
cpp::is_floating_point_v<
309313
typename internal::MakeScalarInput<InputType>::type> &&
310314
cpp::is_floating_point_v<OutputType>) ||

0 commit comments

Comments
 (0)