xref: /llvm-project/libc/utils/MPCWrapper/MPCUtils.cpp (revision 7f37b34d31914120a5bb6bd341e7616773df7613)
1*7f37b34dSShourya Goel //===-- Utils which wrap MPC ----------------------------------------------===//
2*7f37b34dSShourya Goel //
3*7f37b34dSShourya Goel // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*7f37b34dSShourya Goel // See https://llvm.org/LICENSE.txt for license information.
5*7f37b34dSShourya Goel // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*7f37b34dSShourya Goel //
7*7f37b34dSShourya Goel //===----------------------------------------------------------------------===//
8*7f37b34dSShourya Goel 
9*7f37b34dSShourya Goel #include "MPCUtils.h"
10*7f37b34dSShourya Goel 
11*7f37b34dSShourya Goel #include "src/__support/CPP/array.h"
12*7f37b34dSShourya Goel #include "src/__support/CPP/stringstream.h"
13*7f37b34dSShourya Goel #include "utils/MPFRWrapper/MPCommon.h"
14*7f37b34dSShourya Goel 
15*7f37b34dSShourya Goel #include <stdint.h>
16*7f37b34dSShourya Goel 
17*7f37b34dSShourya Goel #include "mpc.h"
18*7f37b34dSShourya Goel 
19*7f37b34dSShourya Goel template <typename T> using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
20*7f37b34dSShourya Goel 
21*7f37b34dSShourya Goel namespace LIBC_NAMESPACE_DECL {
22*7f37b34dSShourya Goel namespace testing {
23*7f37b34dSShourya Goel namespace mpc {
24*7f37b34dSShourya Goel 
25*7f37b34dSShourya Goel static inline cpp::string str(RoundingMode mode) {
26*7f37b34dSShourya Goel   switch (mode) {
27*7f37b34dSShourya Goel   case RoundingMode::Upward:
28*7f37b34dSShourya Goel     return "MPFR_RNDU";
29*7f37b34dSShourya Goel   case RoundingMode::Downward:
30*7f37b34dSShourya Goel     return "MPFR_RNDD";
31*7f37b34dSShourya Goel   case RoundingMode::TowardZero:
32*7f37b34dSShourya Goel     return "MPFR_RNDZ";
33*7f37b34dSShourya Goel   case RoundingMode::Nearest:
34*7f37b34dSShourya Goel     return "MPFR_RNDN";
35*7f37b34dSShourya Goel   }
36*7f37b34dSShourya Goel }
37*7f37b34dSShourya Goel 
38*7f37b34dSShourya Goel class MPCNumber {
39*7f37b34dSShourya Goel private:
40*7f37b34dSShourya Goel   unsigned int precision;
41*7f37b34dSShourya Goel   mpc_t value;
42*7f37b34dSShourya Goel   mpc_rnd_t mpc_rounding;
43*7f37b34dSShourya Goel 
44*7f37b34dSShourya Goel public:
45*7f37b34dSShourya Goel   explicit MPCNumber(unsigned int p) : precision(p), mpc_rounding(MPC_RNDNN) {
46*7f37b34dSShourya Goel     mpc_init2(value, precision);
47*7f37b34dSShourya Goel   }
48*7f37b34dSShourya Goel 
49*7f37b34dSShourya Goel   MPCNumber() : precision(256), mpc_rounding(MPC_RNDNN) {
50*7f37b34dSShourya Goel     mpc_init2(value, 256);
51*7f37b34dSShourya Goel   }
52*7f37b34dSShourya Goel 
53*7f37b34dSShourya Goel   MPCNumber(unsigned int p, mpc_rnd_t rnd) : precision(p), mpc_rounding(rnd) {
54*7f37b34dSShourya Goel     mpc_init2(value, precision);
55*7f37b34dSShourya Goel   }
56*7f37b34dSShourya Goel 
57*7f37b34dSShourya Goel   template <typename XType,
58*7f37b34dSShourya Goel             cpp::enable_if_t<cpp::is_same_v<_Complex float, XType>, bool> = 0>
59*7f37b34dSShourya Goel   MPCNumber(XType x,
60*7f37b34dSShourya Goel             unsigned int precision = mpfr::ExtraPrecision<float>::VALUE,
61*7f37b34dSShourya Goel             RoundingMode rnd = RoundingMode::Nearest)
62*7f37b34dSShourya Goel       : precision(precision),
63*7f37b34dSShourya Goel         mpc_rounding(MPC_RND(mpfr::get_mpfr_rounding_mode(rnd),
64*7f37b34dSShourya Goel                              mpfr::get_mpfr_rounding_mode(rnd))) {
65*7f37b34dSShourya Goel     mpc_init2(value, precision);
66*7f37b34dSShourya Goel     Complex<float> x_c = cpp::bit_cast<Complex<float>>(x);
67*7f37b34dSShourya Goel     mpfr_t real, imag;
68*7f37b34dSShourya Goel     mpfr_init2(real, precision);
69*7f37b34dSShourya Goel     mpfr_init2(imag, precision);
70*7f37b34dSShourya Goel     mpfr_set_flt(real, x_c.real, mpfr::get_mpfr_rounding_mode(rnd));
71*7f37b34dSShourya Goel     mpfr_set_flt(imag, x_c.imag, mpfr::get_mpfr_rounding_mode(rnd));
72*7f37b34dSShourya Goel     mpc_set_fr_fr(value, real, imag, mpc_rounding);
73*7f37b34dSShourya Goel     mpfr_clear(real);
74*7f37b34dSShourya Goel     mpfr_clear(imag);
75*7f37b34dSShourya Goel   }
76*7f37b34dSShourya Goel 
77*7f37b34dSShourya Goel   template <typename XType,
78*7f37b34dSShourya Goel             cpp::enable_if_t<cpp::is_same_v<_Complex double, XType>, bool> = 0>
79*7f37b34dSShourya Goel   MPCNumber(XType x,
80*7f37b34dSShourya Goel             unsigned int precision = mpfr::ExtraPrecision<double>::VALUE,
81*7f37b34dSShourya Goel             RoundingMode rnd = RoundingMode::Nearest)
82*7f37b34dSShourya Goel       : precision(precision),
83*7f37b34dSShourya Goel         mpc_rounding(MPC_RND(mpfr::get_mpfr_rounding_mode(rnd),
84*7f37b34dSShourya Goel                              mpfr::get_mpfr_rounding_mode(rnd))) {
85*7f37b34dSShourya Goel     mpc_init2(value, precision);
86*7f37b34dSShourya Goel     Complex<double> x_c = cpp::bit_cast<Complex<double>>(x);
87*7f37b34dSShourya Goel     mpc_set_d_d(value, x_c.real, x_c.imag, mpc_rounding);
88*7f37b34dSShourya Goel   }
89*7f37b34dSShourya Goel 
90*7f37b34dSShourya Goel   MPCNumber(const MPCNumber &other)
91*7f37b34dSShourya Goel       : precision(other.precision), mpc_rounding(other.mpc_rounding) {
92*7f37b34dSShourya Goel     mpc_init2(value, precision);
93*7f37b34dSShourya Goel     mpc_set(value, other.value, mpc_rounding);
94*7f37b34dSShourya Goel   }
95*7f37b34dSShourya Goel 
96*7f37b34dSShourya Goel   ~MPCNumber() { mpc_clear(value); }
97*7f37b34dSShourya Goel 
98*7f37b34dSShourya Goel   MPCNumber &operator=(const MPCNumber &rhs) {
99*7f37b34dSShourya Goel     precision = rhs.precision;
100*7f37b34dSShourya Goel     mpc_rounding = rhs.mpc_rounding;
101*7f37b34dSShourya Goel     mpc_init2(value, precision);
102*7f37b34dSShourya Goel     mpc_set(value, rhs.value, mpc_rounding);
103*7f37b34dSShourya Goel     return *this;
104*7f37b34dSShourya Goel   }
105*7f37b34dSShourya Goel 
106*7f37b34dSShourya Goel   void setValue(mpc_t val) const { mpc_set(val, value, mpc_rounding); }
107*7f37b34dSShourya Goel 
108*7f37b34dSShourya Goel   mpc_t &getValue() { return value; }
109*7f37b34dSShourya Goel 
110*7f37b34dSShourya Goel   MPCNumber carg() const {
111*7f37b34dSShourya Goel     mpfr_t res;
112*7f37b34dSShourya Goel     MPCNumber result(precision, mpc_rounding);
113*7f37b34dSShourya Goel 
114*7f37b34dSShourya Goel     mpfr_init2(res, precision);
115*7f37b34dSShourya Goel 
116*7f37b34dSShourya Goel     mpc_arg(res, value, MPC_RND_RE(mpc_rounding));
117*7f37b34dSShourya Goel     mpc_set_fr(result.value, res, mpc_rounding);
118*7f37b34dSShourya Goel 
119*7f37b34dSShourya Goel     mpfr_clear(res);
120*7f37b34dSShourya Goel 
121*7f37b34dSShourya Goel     return result;
122*7f37b34dSShourya Goel   }
123*7f37b34dSShourya Goel 
124*7f37b34dSShourya Goel   MPCNumber cproj() const {
125*7f37b34dSShourya Goel     MPCNumber result(precision, mpc_rounding);
126*7f37b34dSShourya Goel     mpc_proj(result.value, value, mpc_rounding);
127*7f37b34dSShourya Goel     return result;
128*7f37b34dSShourya Goel   }
129*7f37b34dSShourya Goel };
130*7f37b34dSShourya Goel 
131*7f37b34dSShourya Goel namespace internal {
132*7f37b34dSShourya Goel 
133*7f37b34dSShourya Goel template <typename InputType>
134*7f37b34dSShourya Goel cpp::enable_if_t<cpp::is_complex_v<InputType>, MPCNumber>
135*7f37b34dSShourya Goel unary_operation(Operation op, InputType input, unsigned int precision,
136*7f37b34dSShourya Goel                 RoundingMode rounding) {
137*7f37b34dSShourya Goel   MPCNumber mpcInput(input, precision, rounding);
138*7f37b34dSShourya Goel   switch (op) {
139*7f37b34dSShourya Goel   case Operation::Carg:
140*7f37b34dSShourya Goel     return mpcInput.carg();
141*7f37b34dSShourya Goel   case Operation::Cproj:
142*7f37b34dSShourya Goel     return mpcInput.cproj();
143*7f37b34dSShourya Goel   default:
144*7f37b34dSShourya Goel     __builtin_unreachable();
145*7f37b34dSShourya Goel   }
146*7f37b34dSShourya Goel }
147*7f37b34dSShourya Goel 
148*7f37b34dSShourya Goel template <typename InputType, typename OutputType>
149*7f37b34dSShourya Goel bool compare_unary_operation_single_output_same_type(Operation op,
150*7f37b34dSShourya Goel                                                      InputType input,
151*7f37b34dSShourya Goel                                                      OutputType libc_result,
152*7f37b34dSShourya Goel                                                      double ulp_tolerance,
153*7f37b34dSShourya Goel                                                      RoundingMode rounding) {
154*7f37b34dSShourya Goel 
155*7f37b34dSShourya Goel   unsigned int precision =
156*7f37b34dSShourya Goel       mpfr::get_precision<make_real_t<InputType>>(ulp_tolerance);
157*7f37b34dSShourya Goel 
158*7f37b34dSShourya Goel   MPCNumber mpc_result;
159*7f37b34dSShourya Goel   mpc_result = unary_operation(op, input, precision, rounding);
160*7f37b34dSShourya Goel 
161*7f37b34dSShourya Goel   mpc_t mpc_result_val;
162*7f37b34dSShourya Goel   mpc_init2(mpc_result_val, precision);
163*7f37b34dSShourya Goel   mpc_result.setValue(mpc_result_val);
164*7f37b34dSShourya Goel 
165*7f37b34dSShourya Goel   mpfr_t real, imag;
166*7f37b34dSShourya Goel   mpfr_init2(real, precision);
167*7f37b34dSShourya Goel   mpfr_init2(imag, precision);
168*7f37b34dSShourya Goel   mpc_real(real, mpc_result_val, mpfr::get_mpfr_rounding_mode(rounding));
169*7f37b34dSShourya Goel   mpc_imag(imag, mpc_result_val, mpfr::get_mpfr_rounding_mode(rounding));
170*7f37b34dSShourya Goel 
171*7f37b34dSShourya Goel   mpfr::MPFRNumber mpfr_real(real, precision, rounding);
172*7f37b34dSShourya Goel   mpfr::MPFRNumber mpfr_imag(imag, precision, rounding);
173*7f37b34dSShourya Goel 
174*7f37b34dSShourya Goel   double ulp_real = mpfr_real.ulp(
175*7f37b34dSShourya Goel       (cpp::bit_cast<Complex<make_real_t<InputType>>>(libc_result)).real);
176*7f37b34dSShourya Goel   double ulp_imag = mpfr_imag.ulp(
177*7f37b34dSShourya Goel       (cpp::bit_cast<Complex<make_real_t<InputType>>>(libc_result)).imag);
178*7f37b34dSShourya Goel   mpc_clear(mpc_result_val);
179*7f37b34dSShourya Goel   mpfr_clear(real);
180*7f37b34dSShourya Goel   mpfr_clear(imag);
181*7f37b34dSShourya Goel   return (ulp_real <= ulp_tolerance) && (ulp_imag <= ulp_tolerance);
182*7f37b34dSShourya Goel }
183*7f37b34dSShourya Goel 
184*7f37b34dSShourya Goel template bool compare_unary_operation_single_output_same_type(
185*7f37b34dSShourya Goel     Operation, _Complex float, _Complex float, double, RoundingMode);
186*7f37b34dSShourya Goel template bool compare_unary_operation_single_output_same_type(
187*7f37b34dSShourya Goel     Operation, _Complex double, _Complex double, double, RoundingMode);
188*7f37b34dSShourya Goel 
189*7f37b34dSShourya Goel template <typename InputType, typename OutputType>
190*7f37b34dSShourya Goel bool compare_unary_operation_single_output_different_type(
191*7f37b34dSShourya Goel     Operation op, InputType input, OutputType libc_result, double ulp_tolerance,
192*7f37b34dSShourya Goel     RoundingMode rounding) {
193*7f37b34dSShourya Goel 
194*7f37b34dSShourya Goel   unsigned int precision =
195*7f37b34dSShourya Goel       mpfr::get_precision<make_real_t<InputType>>(ulp_tolerance);
196*7f37b34dSShourya Goel 
197*7f37b34dSShourya Goel   MPCNumber mpc_result;
198*7f37b34dSShourya Goel   mpc_result = unary_operation(op, input, precision, rounding);
199*7f37b34dSShourya Goel 
200*7f37b34dSShourya Goel   mpc_t mpc_result_val;
201*7f37b34dSShourya Goel   mpc_init2(mpc_result_val, precision);
202*7f37b34dSShourya Goel   mpc_result.setValue(mpc_result_val);
203*7f37b34dSShourya Goel 
204*7f37b34dSShourya Goel   mpfr_t real;
205*7f37b34dSShourya Goel   mpfr_init2(real, precision);
206*7f37b34dSShourya Goel   mpc_real(real, mpc_result_val, mpfr::get_mpfr_rounding_mode(rounding));
207*7f37b34dSShourya Goel 
208*7f37b34dSShourya Goel   mpfr::MPFRNumber mpfr_real(real, precision, rounding);
209*7f37b34dSShourya Goel 
210*7f37b34dSShourya Goel   double ulp_real = mpfr_real.ulp(libc_result);
211*7f37b34dSShourya Goel   mpc_clear(mpc_result_val);
212*7f37b34dSShourya Goel   mpfr_clear(real);
213*7f37b34dSShourya Goel   return (ulp_real <= ulp_tolerance);
214*7f37b34dSShourya Goel }
215*7f37b34dSShourya Goel 
216*7f37b34dSShourya Goel template bool compare_unary_operation_single_output_different_type(
217*7f37b34dSShourya Goel     Operation, _Complex float, float, double, RoundingMode);
218*7f37b34dSShourya Goel template bool compare_unary_operation_single_output_different_type(
219*7f37b34dSShourya Goel     Operation, _Complex double, double, double, RoundingMode);
220*7f37b34dSShourya Goel 
221*7f37b34dSShourya Goel template <typename InputType, typename OutputType>
222*7f37b34dSShourya Goel void explain_unary_operation_single_output_different_type_error(
223*7f37b34dSShourya Goel     Operation op, InputType input, OutputType libc_result, double ulp_tolerance,
224*7f37b34dSShourya Goel     RoundingMode rounding) {
225*7f37b34dSShourya Goel 
226*7f37b34dSShourya Goel   unsigned int precision =
227*7f37b34dSShourya Goel       mpfr::get_precision<make_real_t<InputType>>(ulp_tolerance);
228*7f37b34dSShourya Goel 
229*7f37b34dSShourya Goel   MPCNumber mpc_result;
230*7f37b34dSShourya Goel   mpc_result = unary_operation(op, input, precision, rounding);
231*7f37b34dSShourya Goel 
232*7f37b34dSShourya Goel   mpc_t mpc_result_val;
233*7f37b34dSShourya Goel   mpc_init2(mpc_result_val, precision);
234*7f37b34dSShourya Goel   mpc_result.setValue(mpc_result_val);
235*7f37b34dSShourya Goel 
236*7f37b34dSShourya Goel   mpfr_t real;
237*7f37b34dSShourya Goel   mpfr_init2(real, precision);
238*7f37b34dSShourya Goel   mpc_real(real, mpc_result_val, mpfr::get_mpfr_rounding_mode(rounding));
239*7f37b34dSShourya Goel 
240*7f37b34dSShourya Goel   mpfr::MPFRNumber mpfr_result(real, precision, rounding);
241*7f37b34dSShourya Goel   mpfr::MPFRNumber mpfrLibcResult(libc_result, precision, rounding);
242*7f37b34dSShourya Goel   mpfr::MPFRNumber mpfrInputReal(
243*7f37b34dSShourya Goel       cpp::bit_cast<Complex<make_real_t<InputType>>>(input).real, precision,
244*7f37b34dSShourya Goel       rounding);
245*7f37b34dSShourya Goel   mpfr::MPFRNumber mpfrInputImag(
246*7f37b34dSShourya Goel       cpp::bit_cast<Complex<make_real_t<InputType>>>(input).imag, precision,
247*7f37b34dSShourya Goel       rounding);
248*7f37b34dSShourya Goel 
249*7f37b34dSShourya Goel   cpp::array<char, 2048> msg_buf;
250*7f37b34dSShourya Goel   cpp::StringStream msg(msg_buf);
251*7f37b34dSShourya Goel   msg << "Match value not within tolerance value of MPFR result:\n"
252*7f37b34dSShourya Goel       << "  Input: " << mpfrInputReal.str() << " + " << mpfrInputImag.str()
253*7f37b34dSShourya Goel       << "i\n"
254*7f37b34dSShourya Goel       << "  Rounding mode: " << str(rounding) << '\n'
255*7f37b34dSShourya Goel       << "    Libc: " << mpfrLibcResult.str() << '\n'
256*7f37b34dSShourya Goel       << "    MPC: " << mpfr_result.str() << '\n'
257*7f37b34dSShourya Goel       << '\n'
258*7f37b34dSShourya Goel       << "  ULP error: " << mpfr_result.ulp_as_mpfr_number(libc_result).str()
259*7f37b34dSShourya Goel       << '\n';
260*7f37b34dSShourya Goel   tlog << msg.str();
261*7f37b34dSShourya Goel   mpc_clear(mpc_result_val);
262*7f37b34dSShourya Goel   mpfr_clear(real);
263*7f37b34dSShourya Goel }
264*7f37b34dSShourya Goel 
265*7f37b34dSShourya Goel template void explain_unary_operation_single_output_different_type_error(
266*7f37b34dSShourya Goel     Operation, _Complex float, float, double, RoundingMode);
267*7f37b34dSShourya Goel template void explain_unary_operation_single_output_different_type_error(
268*7f37b34dSShourya Goel     Operation, _Complex double, double, double, RoundingMode);
269*7f37b34dSShourya Goel 
270*7f37b34dSShourya Goel template <typename InputType, typename OutputType>
271*7f37b34dSShourya Goel void explain_unary_operation_single_output_same_type_error(
272*7f37b34dSShourya Goel     Operation op, InputType input, OutputType libc_result, double ulp_tolerance,
273*7f37b34dSShourya Goel     RoundingMode rounding) {
274*7f37b34dSShourya Goel 
275*7f37b34dSShourya Goel   unsigned int precision =
276*7f37b34dSShourya Goel       mpfr::get_precision<make_real_t<InputType>>(ulp_tolerance);
277*7f37b34dSShourya Goel 
278*7f37b34dSShourya Goel   MPCNumber mpc_result;
279*7f37b34dSShourya Goel   mpc_result = unary_operation(op, input, precision, rounding);
280*7f37b34dSShourya Goel 
281*7f37b34dSShourya Goel   mpc_t mpc_result_val;
282*7f37b34dSShourya Goel   mpc_init2(mpc_result_val, precision);
283*7f37b34dSShourya Goel   mpc_result.setValue(mpc_result_val);
284*7f37b34dSShourya Goel 
285*7f37b34dSShourya Goel   mpfr_t real, imag;
286*7f37b34dSShourya Goel   mpfr_init2(real, precision);
287*7f37b34dSShourya Goel   mpfr_init2(imag, precision);
288*7f37b34dSShourya Goel   mpc_real(real, mpc_result_val, mpfr::get_mpfr_rounding_mode(rounding));
289*7f37b34dSShourya Goel   mpc_imag(imag, mpc_result_val, mpfr::get_mpfr_rounding_mode(rounding));
290*7f37b34dSShourya Goel 
291*7f37b34dSShourya Goel   mpfr::MPFRNumber mpfr_real(real, precision, rounding);
292*7f37b34dSShourya Goel   mpfr::MPFRNumber mpfr_imag(imag, precision, rounding);
293*7f37b34dSShourya Goel   mpfr::MPFRNumber mpfrLibcResultReal(
294*7f37b34dSShourya Goel       cpp::bit_cast<Complex<make_real_t<InputType>>>(libc_result).real,
295*7f37b34dSShourya Goel       precision, rounding);
296*7f37b34dSShourya Goel   mpfr::MPFRNumber mpfrLibcResultImag(
297*7f37b34dSShourya Goel       cpp::bit_cast<Complex<make_real_t<InputType>>>(libc_result).imag,
298*7f37b34dSShourya Goel       precision, rounding);
299*7f37b34dSShourya Goel   mpfr::MPFRNumber mpfrInputReal(
300*7f37b34dSShourya Goel       cpp::bit_cast<Complex<make_real_t<InputType>>>(input).real, precision,
301*7f37b34dSShourya Goel       rounding);
302*7f37b34dSShourya Goel   mpfr::MPFRNumber mpfrInputImag(
303*7f37b34dSShourya Goel       cpp::bit_cast<Complex<make_real_t<InputType>>>(input).imag, precision,
304*7f37b34dSShourya Goel       rounding);
305*7f37b34dSShourya Goel 
306*7f37b34dSShourya Goel   cpp::array<char, 2048> msg_buf;
307*7f37b34dSShourya Goel   cpp::StringStream msg(msg_buf);
308*7f37b34dSShourya Goel   msg << "Match value not within tolerance value of MPFR result:\n"
309*7f37b34dSShourya Goel       << "  Input: " << mpfrInputReal.str() << " + " << mpfrInputImag.str()
310*7f37b34dSShourya Goel       << "i\n"
311*7f37b34dSShourya Goel       << "  Rounding mode: " << str(rounding) << " , " << str(rounding) << '\n'
312*7f37b34dSShourya Goel       << "    Libc: " << mpfrLibcResultReal.str() << " + "
313*7f37b34dSShourya Goel       << mpfrLibcResultImag.str() << "i\n"
314*7f37b34dSShourya Goel       << "    MPC: " << mpfr_real.str() << " + " << mpfr_imag.str() << "i\n"
315*7f37b34dSShourya Goel       << '\n'
316*7f37b34dSShourya Goel       << "  ULP error: "
317*7f37b34dSShourya Goel       << mpfr_real
318*7f37b34dSShourya Goel              .ulp_as_mpfr_number(
319*7f37b34dSShourya Goel                  cpp::bit_cast<Complex<make_real_t<InputType>>>(libc_result)
320*7f37b34dSShourya Goel                      .real)
321*7f37b34dSShourya Goel              .str()
322*7f37b34dSShourya Goel       << " , "
323*7f37b34dSShourya Goel       << mpfr_imag
324*7f37b34dSShourya Goel              .ulp_as_mpfr_number(
325*7f37b34dSShourya Goel                  cpp::bit_cast<Complex<make_real_t<InputType>>>(libc_result)
326*7f37b34dSShourya Goel                      .imag)
327*7f37b34dSShourya Goel              .str()
328*7f37b34dSShourya Goel       << '\n';
329*7f37b34dSShourya Goel   tlog << msg.str();
330*7f37b34dSShourya Goel   mpc_clear(mpc_result_val);
331*7f37b34dSShourya Goel   mpfr_clear(real);
332*7f37b34dSShourya Goel   mpfr_clear(imag);
333*7f37b34dSShourya Goel }
334*7f37b34dSShourya Goel 
335*7f37b34dSShourya Goel template void explain_unary_operation_single_output_same_type_error(
336*7f37b34dSShourya Goel     Operation, _Complex float, _Complex float, double, RoundingMode);
337*7f37b34dSShourya Goel template void explain_unary_operation_single_output_same_type_error(
338*7f37b34dSShourya Goel     Operation, _Complex double, _Complex double, double, RoundingMode);
339*7f37b34dSShourya Goel 
340*7f37b34dSShourya Goel } // namespace internal
341*7f37b34dSShourya Goel 
342*7f37b34dSShourya Goel } // namespace mpc
343*7f37b34dSShourya Goel } // namespace testing
344*7f37b34dSShourya Goel } // namespace LIBC_NAMESPACE_DECL
345