1 //===-- Utils which wrap MPC ----------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
11 #include "src/__support/CPP/array.h"
12 #include "src/__support/CPP/stringstream.h"
13 #include "utils/MPFRWrapper/MPCommon.h"
19 template <typename T
> using FPBits
= LIBC_NAMESPACE::fputil::FPBits
<T
>;
21 namespace LIBC_NAMESPACE_DECL
{
25 static inline cpp::string
str(RoundingMode mode
) {
27 case RoundingMode::Upward
:
29 case RoundingMode::Downward
:
31 case RoundingMode::TowardZero
:
33 case RoundingMode::Nearest
:
40 unsigned int precision
;
42 mpc_rnd_t mpc_rounding
;
45 explicit MPCNumber(unsigned int p
) : precision(p
), mpc_rounding(MPC_RNDNN
) {
46 mpc_init2(value
, precision
);
49 MPCNumber() : precision(256), mpc_rounding(MPC_RNDNN
) {
50 mpc_init2(value
, 256);
53 MPCNumber(unsigned int p
, mpc_rnd_t rnd
) : precision(p
), mpc_rounding(rnd
) {
54 mpc_init2(value
, precision
);
57 template <typename XType
,
58 cpp::enable_if_t
<cpp::is_same_v
<_Complex
float, XType
>, bool> = 0>
60 unsigned int precision
= mpfr::ExtraPrecision
<float>::VALUE
,
61 RoundingMode rnd
= RoundingMode::Nearest
)
62 : precision(precision
),
63 mpc_rounding(MPC_RND(mpfr::get_mpfr_rounding_mode(rnd
),
64 mpfr::get_mpfr_rounding_mode(rnd
))) {
65 mpc_init2(value
, precision
);
66 Complex
<float> x_c
= cpp::bit_cast
<Complex
<float>>(x
);
68 mpfr_init2(real
, precision
);
69 mpfr_init2(imag
, precision
);
70 mpfr_set_flt(real
, x_c
.real
, mpfr::get_mpfr_rounding_mode(rnd
));
71 mpfr_set_flt(imag
, x_c
.imag
, mpfr::get_mpfr_rounding_mode(rnd
));
72 mpc_set_fr_fr(value
, real
, imag
, mpc_rounding
);
77 template <typename XType
,
78 cpp::enable_if_t
<cpp::is_same_v
<_Complex
double, XType
>, bool> = 0>
80 unsigned int precision
= mpfr::ExtraPrecision
<double>::VALUE
,
81 RoundingMode rnd
= RoundingMode::Nearest
)
82 : precision(precision
),
83 mpc_rounding(MPC_RND(mpfr::get_mpfr_rounding_mode(rnd
),
84 mpfr::get_mpfr_rounding_mode(rnd
))) {
85 mpc_init2(value
, precision
);
86 Complex
<double> x_c
= cpp::bit_cast
<Complex
<double>>(x
);
87 mpc_set_d_d(value
, x_c
.real
, x_c
.imag
, mpc_rounding
);
90 MPCNumber(const MPCNumber
&other
)
91 : precision(other
.precision
), mpc_rounding(other
.mpc_rounding
) {
92 mpc_init2(value
, precision
);
93 mpc_set(value
, other
.value
, mpc_rounding
);
96 ~MPCNumber() { mpc_clear(value
); }
98 MPCNumber
&operator=(const MPCNumber
&rhs
) {
99 precision
= rhs
.precision
;
100 mpc_rounding
= rhs
.mpc_rounding
;
101 mpc_init2(value
, precision
);
102 mpc_set(value
, rhs
.value
, mpc_rounding
);
106 void setValue(mpc_t val
) const { mpc_set(val
, value
, mpc_rounding
); }
108 mpc_t
&getValue() { return value
; }
110 MPCNumber
carg() const {
112 MPCNumber
result(precision
, mpc_rounding
);
114 mpfr_init2(res
, precision
);
116 mpc_arg(res
, value
, MPC_RND_RE(mpc_rounding
));
117 mpc_set_fr(result
.value
, res
, mpc_rounding
);
124 MPCNumber
cproj() const {
125 MPCNumber
result(precision
, mpc_rounding
);
126 mpc_proj(result
.value
, value
, mpc_rounding
);
133 template <typename InputType
>
134 cpp::enable_if_t
<cpp::is_complex_v
<InputType
>, MPCNumber
>
135 unary_operation(Operation op
, InputType input
, unsigned int precision
,
136 RoundingMode rounding
) {
137 MPCNumber
mpcInput(input
, precision
, rounding
);
139 case Operation::Carg
:
140 return mpcInput
.carg();
141 case Operation::Cproj
:
142 return mpcInput
.cproj();
144 __builtin_unreachable();
148 template <typename InputType
, typename OutputType
>
149 bool compare_unary_operation_single_output_same_type(Operation op
,
151 OutputType libc_result
,
152 double ulp_tolerance
,
153 RoundingMode rounding
) {
155 unsigned int precision
=
156 mpfr::get_precision
<make_real_t
<InputType
>>(ulp_tolerance
);
158 MPCNumber mpc_result
;
159 mpc_result
= unary_operation(op
, input
, precision
, rounding
);
161 mpc_t mpc_result_val
;
162 mpc_init2(mpc_result_val
, precision
);
163 mpc_result
.setValue(mpc_result_val
);
166 mpfr_init2(real
, precision
);
167 mpfr_init2(imag
, precision
);
168 mpc_real(real
, mpc_result_val
, mpfr::get_mpfr_rounding_mode(rounding
));
169 mpc_imag(imag
, mpc_result_val
, mpfr::get_mpfr_rounding_mode(rounding
));
171 mpfr::MPFRNumber
mpfr_real(real
, precision
, rounding
);
172 mpfr::MPFRNumber
mpfr_imag(imag
, precision
, rounding
);
174 double ulp_real
= mpfr_real
.ulp(
175 (cpp::bit_cast
<Complex
<make_real_t
<InputType
>>>(libc_result
)).real
);
176 double ulp_imag
= mpfr_imag
.ulp(
177 (cpp::bit_cast
<Complex
<make_real_t
<InputType
>>>(libc_result
)).imag
);
178 mpc_clear(mpc_result_val
);
181 return (ulp_real
<= ulp_tolerance
) && (ulp_imag
<= ulp_tolerance
);
184 template bool compare_unary_operation_single_output_same_type(
185 Operation
, _Complex
float, _Complex
float, double, RoundingMode
);
186 template bool compare_unary_operation_single_output_same_type(
187 Operation
, _Complex
double, _Complex
double, double, RoundingMode
);
189 template <typename InputType
, typename OutputType
>
190 bool compare_unary_operation_single_output_different_type(
191 Operation op
, InputType input
, OutputType libc_result
, double ulp_tolerance
,
192 RoundingMode rounding
) {
194 unsigned int precision
=
195 mpfr::get_precision
<make_real_t
<InputType
>>(ulp_tolerance
);
197 MPCNumber mpc_result
;
198 mpc_result
= unary_operation(op
, input
, precision
, rounding
);
200 mpc_t mpc_result_val
;
201 mpc_init2(mpc_result_val
, precision
);
202 mpc_result
.setValue(mpc_result_val
);
205 mpfr_init2(real
, precision
);
206 mpc_real(real
, mpc_result_val
, mpfr::get_mpfr_rounding_mode(rounding
));
208 mpfr::MPFRNumber
mpfr_real(real
, precision
, rounding
);
210 double ulp_real
= mpfr_real
.ulp(libc_result
);
211 mpc_clear(mpc_result_val
);
213 return (ulp_real
<= ulp_tolerance
);
216 template bool compare_unary_operation_single_output_different_type(
217 Operation
, _Complex
float, float, double, RoundingMode
);
218 template bool compare_unary_operation_single_output_different_type(
219 Operation
, _Complex
double, double, double, RoundingMode
);
221 template <typename InputType
, typename OutputType
>
222 void explain_unary_operation_single_output_different_type_error(
223 Operation op
, InputType input
, OutputType libc_result
, double ulp_tolerance
,
224 RoundingMode rounding
) {
226 unsigned int precision
=
227 mpfr::get_precision
<make_real_t
<InputType
>>(ulp_tolerance
);
229 MPCNumber mpc_result
;
230 mpc_result
= unary_operation(op
, input
, precision
, rounding
);
232 mpc_t mpc_result_val
;
233 mpc_init2(mpc_result_val
, precision
);
234 mpc_result
.setValue(mpc_result_val
);
237 mpfr_init2(real
, precision
);
238 mpc_real(real
, mpc_result_val
, mpfr::get_mpfr_rounding_mode(rounding
));
240 mpfr::MPFRNumber
mpfr_result(real
, precision
, rounding
);
241 mpfr::MPFRNumber
mpfrLibcResult(libc_result
, precision
, rounding
);
242 mpfr::MPFRNumber
mpfrInputReal(
243 cpp::bit_cast
<Complex
<make_real_t
<InputType
>>>(input
).real
, precision
,
245 mpfr::MPFRNumber
mpfrInputImag(
246 cpp::bit_cast
<Complex
<make_real_t
<InputType
>>>(input
).imag
, precision
,
249 cpp::array
<char, 2048> msg_buf
;
250 cpp::StringStream
msg(msg_buf
);
251 msg
<< "Match value not within tolerance value of MPFR result:\n"
252 << " Input: " << mpfrInputReal
.str() << " + " << mpfrInputImag
.str()
254 << " Rounding mode: " << str(rounding
) << '\n'
255 << " Libc: " << mpfrLibcResult
.str() << '\n'
256 << " MPC: " << mpfr_result
.str() << '\n'
258 << " ULP error: " << mpfr_result
.ulp_as_mpfr_number(libc_result
).str()
261 mpc_clear(mpc_result_val
);
265 template void explain_unary_operation_single_output_different_type_error(
266 Operation
, _Complex
float, float, double, RoundingMode
);
267 template void explain_unary_operation_single_output_different_type_error(
268 Operation
, _Complex
double, double, double, RoundingMode
);
270 template <typename InputType
, typename OutputType
>
271 void explain_unary_operation_single_output_same_type_error(
272 Operation op
, InputType input
, OutputType libc_result
, double ulp_tolerance
,
273 RoundingMode rounding
) {
275 unsigned int precision
=
276 mpfr::get_precision
<make_real_t
<InputType
>>(ulp_tolerance
);
278 MPCNumber mpc_result
;
279 mpc_result
= unary_operation(op
, input
, precision
, rounding
);
281 mpc_t mpc_result_val
;
282 mpc_init2(mpc_result_val
, precision
);
283 mpc_result
.setValue(mpc_result_val
);
286 mpfr_init2(real
, precision
);
287 mpfr_init2(imag
, precision
);
288 mpc_real(real
, mpc_result_val
, mpfr::get_mpfr_rounding_mode(rounding
));
289 mpc_imag(imag
, mpc_result_val
, mpfr::get_mpfr_rounding_mode(rounding
));
291 mpfr::MPFRNumber
mpfr_real(real
, precision
, rounding
);
292 mpfr::MPFRNumber
mpfr_imag(imag
, precision
, rounding
);
293 mpfr::MPFRNumber
mpfrLibcResultReal(
294 cpp::bit_cast
<Complex
<make_real_t
<InputType
>>>(libc_result
).real
,
295 precision
, rounding
);
296 mpfr::MPFRNumber
mpfrLibcResultImag(
297 cpp::bit_cast
<Complex
<make_real_t
<InputType
>>>(libc_result
).imag
,
298 precision
, rounding
);
299 mpfr::MPFRNumber
mpfrInputReal(
300 cpp::bit_cast
<Complex
<make_real_t
<InputType
>>>(input
).real
, precision
,
302 mpfr::MPFRNumber
mpfrInputImag(
303 cpp::bit_cast
<Complex
<make_real_t
<InputType
>>>(input
).imag
, precision
,
306 cpp::array
<char, 2048> msg_buf
;
307 cpp::StringStream
msg(msg_buf
);
308 msg
<< "Match value not within tolerance value of MPFR result:\n"
309 << " Input: " << mpfrInputReal
.str() << " + " << mpfrInputImag
.str()
311 << " Rounding mode: " << str(rounding
) << " , " << str(rounding
) << '\n'
312 << " Libc: " << mpfrLibcResultReal
.str() << " + "
313 << mpfrLibcResultImag
.str() << "i\n"
314 << " MPC: " << mpfr_real
.str() << " + " << mpfr_imag
.str() << "i\n"
319 cpp::bit_cast
<Complex
<make_real_t
<InputType
>>>(libc_result
)
325 cpp::bit_cast
<Complex
<make_real_t
<InputType
>>>(libc_result
)
330 mpc_clear(mpc_result_val
);
335 template void explain_unary_operation_single_output_same_type_error(
336 Operation
, _Complex
float, _Complex
float, double, RoundingMode
);
337 template void explain_unary_operation_single_output_same_type_error(
338 Operation
, _Complex
double, _Complex
double, double, RoundingMode
);
340 } // namespace internal
343 } // namespace testing
344 } // namespace LIBC_NAMESPACE_DECL