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