1 | //===-- Utils used by both MPCWrapper and MPFRWrapper----------------------===// |
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 "MPCommon.h" |
10 | |
11 | #include "src/__support/CPP/string_view.h" |
12 | #include "src/__support/FPUtil/cast.h" |
13 | #include "src/__support/macros/config.h" |
14 | #include "src/__support/macros/properties/types.h" |
15 | |
16 | namespace LIBC_NAMESPACE_DECL { |
17 | namespace testing { |
18 | namespace mpfr { |
19 | |
20 | MPFRNumber::MPFRNumber() : mpfr_precision(256), mpfr_rounding(MPFR_RNDN) { |
21 | mpfr_init2(value, mpfr_precision); |
22 | } |
23 | |
24 | MPFRNumber::MPFRNumber(const MPFRNumber &other) |
25 | : mpfr_precision(other.mpfr_precision), mpfr_rounding(other.mpfr_rounding) { |
26 | mpfr_init2(value, mpfr_precision); |
27 | mpfr_set(value, other.value, mpfr_rounding); |
28 | } |
29 | |
30 | MPFRNumber::MPFRNumber(const MPFRNumber &other, unsigned int precision) |
31 | : mpfr_precision(precision), mpfr_rounding(other.mpfr_rounding) { |
32 | mpfr_init2(value, mpfr_precision); |
33 | mpfr_set(value, other.value, mpfr_rounding); |
34 | } |
35 | |
36 | MPFRNumber::MPFRNumber(const mpfr_t x, unsigned int precision, |
37 | RoundingMode rounding) |
38 | : mpfr_precision(precision), |
39 | mpfr_rounding(get_mpfr_rounding_mode(rounding)) { |
40 | mpfr_init2(value, mpfr_precision); |
41 | mpfr_set(value, x, mpfr_rounding); |
42 | } |
43 | |
44 | MPFRNumber::~MPFRNumber() { mpfr_clear(value); } |
45 | |
46 | MPFRNumber &MPFRNumber::operator=(const MPFRNumber &rhs) { |
47 | mpfr_precision = rhs.mpfr_precision; |
48 | mpfr_rounding = rhs.mpfr_rounding; |
49 | mpfr_set(value, rhs.value, mpfr_rounding); |
50 | return *this; |
51 | } |
52 | |
53 | bool MPFRNumber::is_nan() const { return mpfr_nan_p(value); } |
54 | |
55 | MPFRNumber MPFRNumber::abs() const { |
56 | MPFRNumber result(*this); |
57 | mpfr_abs(result.value, value, mpfr_rounding); |
58 | return result; |
59 | } |
60 | |
61 | MPFRNumber MPFRNumber::acos() const { |
62 | MPFRNumber result(*this); |
63 | mpfr_acos(result.value, value, mpfr_rounding); |
64 | return result; |
65 | } |
66 | |
67 | MPFRNumber MPFRNumber::acosh() const { |
68 | MPFRNumber result(*this); |
69 | mpfr_acosh(result.value, value, mpfr_rounding); |
70 | return result; |
71 | } |
72 | |
73 | MPFRNumber MPFRNumber::acospi() const { |
74 | MPFRNumber result(*this); |
75 | |
76 | #if MPFR_VERSION_MAJOR > 4 || \ |
77 | (MPFR_VERSION_MAJOR == 4 && MPFR_VERSION_MINOR >= 2) |
78 | mpfr_acospi(result.value, value, mpfr_rounding); |
79 | return result; |
80 | #else |
81 | MPFRNumber value_acos(0.0, 1280); |
82 | mpfr_acos(value_acos.value, value, MPFR_RNDN); |
83 | MPFRNumber value_pi(0.0, 1280); |
84 | mpfr_const_pi(value_pi.value, MPFR_RNDN); |
85 | mpfr_div(result.value, value_acos.value, value_pi.value, mpfr_rounding); |
86 | return result; |
87 | #endif |
88 | } |
89 | |
90 | MPFRNumber MPFRNumber::add(const MPFRNumber &b) const { |
91 | MPFRNumber result(*this); |
92 | mpfr_add(result.value, value, b.value, mpfr_rounding); |
93 | return result; |
94 | } |
95 | |
96 | MPFRNumber MPFRNumber::asin() const { |
97 | MPFRNumber result(*this); |
98 | mpfr_asin(result.value, value, mpfr_rounding); |
99 | return result; |
100 | } |
101 | |
102 | MPFRNumber MPFRNumber::asinh() const { |
103 | MPFRNumber result(*this); |
104 | mpfr_asinh(result.value, value, mpfr_rounding); |
105 | return result; |
106 | } |
107 | |
108 | MPFRNumber MPFRNumber::atan() const { |
109 | MPFRNumber result(*this); |
110 | mpfr_atan(result.value, value, mpfr_rounding); |
111 | return result; |
112 | } |
113 | |
114 | MPFRNumber MPFRNumber::atan2(const MPFRNumber &b) { |
115 | MPFRNumber result(*this); |
116 | mpfr_atan2(result.value, value, b.value, mpfr_rounding); |
117 | return result; |
118 | } |
119 | |
120 | MPFRNumber MPFRNumber::atanh() const { |
121 | MPFRNumber result(*this); |
122 | mpfr_atanh(result.value, value, mpfr_rounding); |
123 | return result; |
124 | } |
125 | |
126 | MPFRNumber MPFRNumber::cbrt() const { |
127 | MPFRNumber result(*this); |
128 | mpfr_cbrt(result.value, value, mpfr_rounding); |
129 | return result; |
130 | } |
131 | |
132 | MPFRNumber MPFRNumber::ceil() const { |
133 | MPFRNumber result(*this); |
134 | mpfr_ceil(result.value, value); |
135 | return result; |
136 | } |
137 | |
138 | MPFRNumber MPFRNumber::cos() const { |
139 | MPFRNumber result(*this); |
140 | mpfr_cos(result.value, value, mpfr_rounding); |
141 | return result; |
142 | } |
143 | |
144 | MPFRNumber MPFRNumber::cosh() const { |
145 | MPFRNumber result(*this); |
146 | mpfr_cosh(result.value, value, mpfr_rounding); |
147 | return result; |
148 | } |
149 | |
150 | MPFRNumber MPFRNumber::cospi() const { |
151 | MPFRNumber result(*this); |
152 | |
153 | #if MPFR_VERSION_MAJOR > 4 || \ |
154 | (MPFR_VERSION_MAJOR == 4 && MPFR_VERSION_MINOR >= 2) |
155 | mpfr_cospi(result.value, value, mpfr_rounding); |
156 | return result; |
157 | #else |
158 | if (mpfr_integer_p(value)) { |
159 | mpz_t integer; |
160 | mpz_init(integer); |
161 | mpfr_get_z(z: integer, f: value, mpfr_rounding); |
162 | |
163 | int d = mpz_tstbit(integer, 0); |
164 | mpfr_set_si(result.value, d ? -1 : 1, mpfr_rounding); |
165 | mpz_clear(integer); |
166 | return result; |
167 | } |
168 | |
169 | MPFRNumber value_pi(0.0, 1280); |
170 | mpfr_const_pi(value_pi.value, MPFR_RNDN); |
171 | mpfr_mul(value_pi.value, value_pi.value, value, MPFR_RNDN); |
172 | mpfr_cos(result.value, value_pi.value, mpfr_rounding); |
173 | |
174 | return result; |
175 | #endif |
176 | } |
177 | |
178 | MPFRNumber MPFRNumber::erf() const { |
179 | MPFRNumber result(*this); |
180 | mpfr_erf(result.value, value, mpfr_rounding); |
181 | return result; |
182 | } |
183 | |
184 | MPFRNumber MPFRNumber::exp() const { |
185 | MPFRNumber result(*this); |
186 | mpfr_exp(result.value, value, mpfr_rounding); |
187 | return result; |
188 | } |
189 | |
190 | MPFRNumber MPFRNumber::exp2() const { |
191 | MPFRNumber result(*this); |
192 | mpfr_exp2(result.value, value, mpfr_rounding); |
193 | return result; |
194 | } |
195 | |
196 | MPFRNumber MPFRNumber::exp2m1() const { |
197 | // TODO: Only use mpfr_exp2m1 once CI and buildbots get MPFR >= 4.2.0. |
198 | #if MPFR_VERSION_MAJOR > 4 || \ |
199 | (MPFR_VERSION_MAJOR == 4 && MPFR_VERSION_MINOR >= 2) |
200 | MPFRNumber result(*this); |
201 | mpfr_exp2m1(result.value, value, mpfr_rounding); |
202 | return result; |
203 | #else |
204 | unsigned int prec = mpfr_precision * 3; |
205 | MPFRNumber result(*this, prec); |
206 | |
207 | float f = mpfr_get_flt(abs().value, mpfr_rounding); |
208 | if (f > 0.5f && f < 0x1.0p30f) { |
209 | mpfr_exp2(result.value, value, mpfr_rounding); |
210 | mpfr_sub_ui(result.value, result.value, 1, mpfr_rounding); |
211 | return result; |
212 | } |
213 | |
214 | MPFRNumber ln2(2.0f, prec); |
215 | // log(2) |
216 | mpfr_log(ln2.value, ln2.value, mpfr_rounding); |
217 | // x * log(2) |
218 | mpfr_mul(result.value, value, ln2.value, mpfr_rounding); |
219 | // e^(x * log(2)) - 1 |
220 | int ex = mpfr_expm1(result.value, result.value, mpfr_rounding); |
221 | mpfr_subnormalize(result.value, ex, mpfr_rounding); |
222 | return result; |
223 | #endif |
224 | } |
225 | |
226 | MPFRNumber MPFRNumber::exp10() const { |
227 | MPFRNumber result(*this); |
228 | mpfr_exp10(result.value, value, mpfr_rounding); |
229 | return result; |
230 | } |
231 | |
232 | MPFRNumber MPFRNumber::exp10m1() const { |
233 | // TODO: Only use mpfr_exp10m1 once CI and buildbots get MPFR >= 4.2.0. |
234 | #if MPFR_VERSION_MAJOR > 4 || \ |
235 | (MPFR_VERSION_MAJOR == 4 && MPFR_VERSION_MINOR >= 2) |
236 | MPFRNumber result(*this); |
237 | mpfr_exp10m1(result.value, value, mpfr_rounding); |
238 | return result; |
239 | #else |
240 | unsigned int prec = mpfr_precision * 3; |
241 | MPFRNumber result(*this, prec); |
242 | |
243 | MPFRNumber ln10(10.0f, prec); |
244 | // log(10) |
245 | mpfr_log(ln10.value, ln10.value, mpfr_rounding); |
246 | // x * log(10) |
247 | mpfr_mul(result.value, value, ln10.value, mpfr_rounding); |
248 | // e^(x * log(10)) - 1 |
249 | int ex = mpfr_expm1(result.value, result.value, mpfr_rounding); |
250 | mpfr_subnormalize(result.value, ex, mpfr_rounding); |
251 | return result; |
252 | #endif |
253 | } |
254 | |
255 | MPFRNumber MPFRNumber::expm1() const { |
256 | MPFRNumber result(*this); |
257 | mpfr_expm1(result.value, value, mpfr_rounding); |
258 | return result; |
259 | } |
260 | |
261 | MPFRNumber MPFRNumber::div(const MPFRNumber &b) const { |
262 | MPFRNumber result(*this); |
263 | mpfr_div(result.value, value, b.value, mpfr_rounding); |
264 | return result; |
265 | } |
266 | |
267 | MPFRNumber MPFRNumber::floor() const { |
268 | MPFRNumber result(*this); |
269 | mpfr_floor(result.value, value); |
270 | return result; |
271 | } |
272 | |
273 | MPFRNumber MPFRNumber::fmod(const MPFRNumber &b) { |
274 | MPFRNumber result(*this); |
275 | mpfr_fmod(result.value, value, b.value, mpfr_rounding); |
276 | return result; |
277 | } |
278 | |
279 | MPFRNumber MPFRNumber::frexp(int &exp) { |
280 | MPFRNumber result(*this); |
281 | mpfr_exp_t resultExp; |
282 | mpfr_frexp(&resultExp, result.value, value, mpfr_rounding); |
283 | exp = static_cast<int>(resultExp); |
284 | return result; |
285 | } |
286 | |
287 | MPFRNumber MPFRNumber::hypot(const MPFRNumber &b) { |
288 | MPFRNumber result(*this); |
289 | mpfr_hypot(result.value, value, b.value, mpfr_rounding); |
290 | return result; |
291 | } |
292 | |
293 | MPFRNumber MPFRNumber::log() const { |
294 | MPFRNumber result(*this); |
295 | mpfr_log(result.value, value, mpfr_rounding); |
296 | return result; |
297 | } |
298 | |
299 | MPFRNumber MPFRNumber::log2() const { |
300 | MPFRNumber result(*this); |
301 | mpfr_log2(result.value, value, mpfr_rounding); |
302 | return result; |
303 | } |
304 | |
305 | MPFRNumber MPFRNumber::log10() const { |
306 | MPFRNumber result(*this); |
307 | mpfr_log10(result.value, value, mpfr_rounding); |
308 | return result; |
309 | } |
310 | |
311 | MPFRNumber MPFRNumber::log1p() const { |
312 | MPFRNumber result(*this); |
313 | mpfr_log1p(result.value, value, mpfr_rounding); |
314 | return result; |
315 | } |
316 | |
317 | MPFRNumber MPFRNumber::pow(const MPFRNumber &b) { |
318 | MPFRNumber result(*this); |
319 | mpfr_pow(result.value, value, b.value, mpfr_rounding); |
320 | return result; |
321 | } |
322 | |
323 | MPFRNumber MPFRNumber::remquo(const MPFRNumber &divisor, int "ient) { |
324 | MPFRNumber remainder(*this); |
325 | long q; |
326 | mpfr_remquo(remainder.value, &q, value, divisor.value, mpfr_rounding); |
327 | quotient = static_cast<int>(q); |
328 | return remainder; |
329 | } |
330 | |
331 | MPFRNumber MPFRNumber::round() const { |
332 | MPFRNumber result(*this); |
333 | mpfr_round(result.value, value); |
334 | return result; |
335 | } |
336 | |
337 | MPFRNumber MPFRNumber::roundeven() const { |
338 | MPFRNumber result(*this); |
339 | #if MPFR_VERSION_MAJOR >= 4 |
340 | mpfr_roundeven(result.value, value); |
341 | #else |
342 | mpfr_rint(result.value, value, MPFR_RNDN); |
343 | #endif |
344 | return result; |
345 | } |
346 | |
347 | bool MPFRNumber::round_to_long(long &result) const { |
348 | // We first calculate the rounded value. This way, when converting |
349 | // to long using mpfr_get_si, the rounding direction of MPFR_RNDN |
350 | // (or any other rounding mode), does not have an influence. |
351 | MPFRNumber roundedValue = round(); |
352 | mpfr_clear_erangeflag(); |
353 | result = mpfr_get_si(roundedValue.value, MPFR_RNDN); |
354 | return mpfr_erangeflag_p(); |
355 | } |
356 | |
357 | bool MPFRNumber::round_to_long(mpfr_rnd_t rnd, long &result) const { |
358 | MPFRNumber rint_result(*this); |
359 | mpfr_rint(rint_result.value, value, rnd); |
360 | return rint_result.round_to_long(result); |
361 | } |
362 | |
363 | MPFRNumber MPFRNumber::rint(mpfr_rnd_t rnd) const { |
364 | MPFRNumber result(*this); |
365 | mpfr_rint(result.value, value, rnd); |
366 | return result; |
367 | } |
368 | |
369 | MPFRNumber MPFRNumber::mod_2pi() const { |
370 | MPFRNumber result(0.0, 1280); |
371 | MPFRNumber _2pi(0.0, 1280); |
372 | mpfr_const_pi(_2pi.value, MPFR_RNDN); |
373 | mpfr_mul_si(_2pi.value, _2pi.value, 2, MPFR_RNDN); |
374 | mpfr_fmod(result.value, value, _2pi.value, MPFR_RNDN); |
375 | return result; |
376 | } |
377 | |
378 | MPFRNumber MPFRNumber::mod_pi_over_2() const { |
379 | MPFRNumber result(0.0, 1280); |
380 | MPFRNumber pi_over_2(0.0, 1280); |
381 | mpfr_const_pi(pi_over_2.value, MPFR_RNDN); |
382 | mpfr_mul_d(pi_over_2.value, pi_over_2.value, 0.5, MPFR_RNDN); |
383 | mpfr_fmod(result.value, value, pi_over_2.value, MPFR_RNDN); |
384 | return result; |
385 | } |
386 | |
387 | MPFRNumber MPFRNumber::mod_pi_over_4() const { |
388 | MPFRNumber result(0.0, 1280); |
389 | MPFRNumber pi_over_4(0.0, 1280); |
390 | mpfr_const_pi(pi_over_4.value, MPFR_RNDN); |
391 | mpfr_mul_d(pi_over_4.value, pi_over_4.value, 0.25, MPFR_RNDN); |
392 | mpfr_fmod(result.value, value, pi_over_4.value, MPFR_RNDN); |
393 | return result; |
394 | } |
395 | |
396 | MPFRNumber MPFRNumber::sin() const { |
397 | MPFRNumber result(*this); |
398 | mpfr_sin(result.value, value, mpfr_rounding); |
399 | return result; |
400 | } |
401 | |
402 | MPFRNumber MPFRNumber::sinpi() const { |
403 | MPFRNumber result(*this); |
404 | |
405 | #if MPFR_VERSION_MAJOR > 4 || \ |
406 | (MPFR_VERSION_MAJOR == 4 && MPFR_VERSION_MINOR >= 2) |
407 | |
408 | mpfr_sinpi(result.value, value, mpfr_rounding); |
409 | return result; |
410 | #else |
411 | if (mpfr_integer_p(value)) { |
412 | mpfr_set_si(result.value, 0, mpfr_rounding); |
413 | return result; |
414 | } |
415 | |
416 | MPFRNumber value_mul_two(*this); |
417 | mpfr_mul_si(value_mul_two.value, value, 2, MPFR_RNDN); |
418 | |
419 | if (mpfr_integer_p(value_mul_two.value)) { |
420 | auto d = mpfr_get_si(value, MPFR_RNDD); |
421 | mpfr_set_si(result.value, (d & 1) ? -1 : 1, mpfr_rounding); |
422 | return result; |
423 | } |
424 | |
425 | MPFRNumber value_pi(0.0, 1280); |
426 | mpfr_const_pi(value_pi.value, MPFR_RNDN); |
427 | mpfr_mul(value_pi.value, value_pi.value, value, MPFR_RNDN); |
428 | mpfr_sin(result.value, value_pi.value, mpfr_rounding); |
429 | return result; |
430 | #endif |
431 | } |
432 | |
433 | MPFRNumber MPFRNumber::sinh() const { |
434 | MPFRNumber result(*this); |
435 | mpfr_sinh(result.value, value, mpfr_rounding); |
436 | return result; |
437 | } |
438 | |
439 | MPFRNumber MPFRNumber::sqrt() const { |
440 | MPFRNumber result(*this); |
441 | mpfr_sqrt(result.value, value, mpfr_rounding); |
442 | return result; |
443 | } |
444 | |
445 | MPFRNumber MPFRNumber::sub(const MPFRNumber &b) const { |
446 | MPFRNumber result(*this); |
447 | mpfr_sub(result.value, value, b.value, mpfr_rounding); |
448 | return result; |
449 | } |
450 | |
451 | MPFRNumber MPFRNumber::tan() const { |
452 | MPFRNumber result(*this); |
453 | mpfr_tan(result.value, value, mpfr_rounding); |
454 | return result; |
455 | } |
456 | |
457 | MPFRNumber MPFRNumber::tanh() const { |
458 | MPFRNumber result(*this); |
459 | mpfr_tanh(result.value, value, mpfr_rounding); |
460 | return result; |
461 | } |
462 | |
463 | MPFRNumber MPFRNumber::tanpi() const { |
464 | MPFRNumber result(*this); |
465 | |
466 | #if MPFR_VERSION_MAJOR > 4 || \ |
467 | (MPFR_VERSION_MAJOR == 4 && MPFR_VERSION_MINOR >= 2) |
468 | |
469 | mpfr_tanpi(result.value, value, mpfr_rounding); |
470 | return result; |
471 | #else |
472 | MPFRNumber value_ret_exact(*this); |
473 | MPFRNumber value_one(*this); |
474 | mpfr_set_si(value_one.value, 1, MPFR_RNDN); |
475 | mpfr_fmod(value_ret_exact.value, value, value_one.value, mpfr_rounding); |
476 | mpfr_mul_si(value_ret_exact.value, value_ret_exact.value, 4, MPFR_RNDN); |
477 | |
478 | if (mpfr_integer_p(value_ret_exact.value)) { |
479 | int mod = mpfr_get_si(value_ret_exact.value, MPFR_RNDN); |
480 | mod = (mod < 0 ? -1 * mod : mod); |
481 | |
482 | switch (mod) { |
483 | case 0: |
484 | mpfr_set_si(result.value, 0, mpfr_rounding); |
485 | break; |
486 | case 1: |
487 | mpfr_set_si(result.value, (mpfr_signbit(value) ? -1 : 1), mpfr_rounding); |
488 | break; |
489 | case 2: { |
490 | auto d = mpfr_get_si(value, MPFR_RNDZ); |
491 | d += mpfr_sgn(value) > 0 ? 0 : 1; |
492 | mpfr_set_inf(result.value, (d & 1) ? -1 : 1); |
493 | break; |
494 | } |
495 | case 3: |
496 | mpfr_set_si(result.value, (mpfr_signbit(value) ? 1 : -1), mpfr_rounding); |
497 | break; |
498 | } |
499 | |
500 | return result; |
501 | } |
502 | |
503 | MPFRNumber value_pi(0.0, 1280); |
504 | mpfr_const_pi(value_pi.value, MPFR_RNDN); |
505 | mpfr_mul(value_pi.value, value_pi.value, value, MPFR_RNDN); |
506 | mpfr_tan(result.value, value_pi.value, mpfr_rounding); |
507 | return result; |
508 | #endif |
509 | } |
510 | |
511 | MPFRNumber MPFRNumber::trunc() const { |
512 | MPFRNumber result(*this); |
513 | mpfr_trunc(result.value, value); |
514 | return result; |
515 | } |
516 | |
517 | MPFRNumber MPFRNumber::fma(const MPFRNumber &b, const MPFRNumber &c) { |
518 | MPFRNumber result(*this); |
519 | mpfr_fma(result.value, value, b.value, c.value, mpfr_rounding); |
520 | return result; |
521 | } |
522 | |
523 | MPFRNumber MPFRNumber::mul(const MPFRNumber &b) { |
524 | MPFRNumber result(*this); |
525 | mpfr_mul(result.value, value, b.value, mpfr_rounding); |
526 | return result; |
527 | } |
528 | |
529 | cpp::string MPFRNumber::str() const { |
530 | // 200 bytes should be more than sufficient to hold a 100-digit number |
531 | // plus additional bytes for the decimal point, '-' sign etc. |
532 | constexpr size_t printBufSize = 200; |
533 | char buffer[printBufSize]; |
534 | mpfr_snprintf(buffer, printBufSize, "%100.50Rf" , value); |
535 | cpp::string_view view(buffer); |
536 | // Trim whitespaces |
537 | const char whitespace = ' '; |
538 | while (!view.empty() && view.front() == whitespace) |
539 | view.remove_prefix(1); |
540 | while (!view.empty() && view.back() == whitespace) |
541 | view.remove_suffix(1); |
542 | return cpp::string(view.data()); |
543 | } |
544 | |
545 | void MPFRNumber::dump(const char *msg) const { |
546 | mpfr_printf("%s%.128g\n" , msg, value); |
547 | } |
548 | |
549 | template <> float MPFRNumber::as<float>() const { |
550 | return mpfr_get_flt(value, mpfr_rounding); |
551 | } |
552 | |
553 | template <> double MPFRNumber::as<double>() const { |
554 | return mpfr_get_d(value, mpfr_rounding); |
555 | } |
556 | |
557 | template <> long double MPFRNumber::as<long double>() const { |
558 | return mpfr_get_ld(value, mpfr_rounding); |
559 | } |
560 | |
561 | #ifdef LIBC_TYPES_HAS_FLOAT16 |
562 | template <> float16 MPFRNumber::as<float16>() const { |
563 | // TODO: Either prove that this cast won't cause double-rounding errors, or |
564 | // find a better way to get a float16. |
565 | return fputil::cast<float16>(mpfr_get_d(value, mpfr_rounding)); |
566 | } |
567 | #endif |
568 | |
569 | #ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE |
570 | template <> float128 MPFRNumber::as<float128>() const { |
571 | return mpfr_get_float128(value, mpfr_rounding); |
572 | } |
573 | |
574 | #endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE |
575 | |
576 | } // namespace mpfr |
577 | } // namespace testing |
578 | } // namespace LIBC_NAMESPACE_DECL |
579 | |