Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
mpreal_extensions.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "mpreal.hpp"
4
5namespace uni20
6{
7namespace detail
8{
9// Rational values of sin(pi*x) occur on this grid. Reduce exactly, including
10// for numerators too large for any native floating-point format.
11inline mpreal rational_sinpi(exact_rational const& x)
12{
13 auto sixths = x * exact_rational{6};
14 auto q = sixths.native_handle();
15 if (mpz_cmp_ui(mpq_denref(q), 1) == 0)
16 {
17 switch (mpz_fdiv_ui(mpq_numref(q), 12))
18 {
19 case 0:
20 case 6:
21 return mpreal{};
22 case 1:
23 case 5:
24 return mpreal(exact_rational{1} / exact_rational{2});
25 case 3:
26 return mpreal{1};
27 case 7:
28 case 11:
29 return mpreal(exact_rational{-1} / exact_rational{2});
30 case 9:
31 return mpreal{-1};
32 }
33 }
34 throw std::logic_error("sinpi requires finite precision for an irrational result");
35}
36inline mpreal rational_asinpi(exact_rational const& x)
37{
38 if (x == 0) return mpreal{};
39 if (x == 1 || x == -1) return mpreal(x / exact_rational{2});
40 if (x * exact_rational{2} == 1 || x * exact_rational{2} == -1) return mpreal(x / exact_rational{3});
41 throw std::logic_error("asinpi requires finite precision for this input");
42}
43
44template <auto Operation> mpreal extended_unary(mpreal const& x)
45{
46 auto p = x.precision();
47 if (p.is_exact())
48 {
49 auto const& q = x.exact_value();
50 if constexpr (same_function_v<Operation, mpfr_exp10>)
51 return mpreal(uni20::pow(exact_rational{10}, q));
52 else if constexpr (same_function_v<Operation, mpfr_exp2m1> || same_function_v<Operation, mpfr_exp10m1>)
53 return mpreal(uni20::pow(exact_rational{same_function_v<Operation, mpfr_exp2m1> ? 2 : 10}, q) -
54 exact_rational{1});
55 else if constexpr (same_function_v<Operation, mpfr_log2p1> || same_function_v<Operation, mpfr_log10p1>)
56 return mpreal_access::exact_logarithm(q + exact_rational{1}, same_function_v<Operation, mpfr_log2p1> ? 2 : 10);
57 else if constexpr (same_function_v<Operation, mpfr_sinpi>)
58 return rational_sinpi(q);
59 else if constexpr (same_function_v<Operation, mpfr_cospi>)
60 return rational_sinpi(q + exact_rational{1} / exact_rational{2});
61 else if constexpr (same_function_v<Operation, mpfr_tanpi>)
62 {
63 auto quarters = q * exact_rational{4};
64 auto value = quarters.native_handle();
65 if (mpz_cmp_ui(mpq_denref(value), 1) == 0)
66 {
67 switch (mpz_fdiv_ui(mpq_numref(value), 4))
68 {
69 case 0:
70 return mpreal{};
71 case 1:
72 return mpreal{1};
73 case 3:
74 return mpreal{-1};
75 case 2:
76 throw std::domain_error("exact tanpi is undefined at half-integers");
77 }
78 }
79 }
80 else if constexpr (same_function_v<Operation, mpfr_asinpi>)
81 return rational_asinpi(q);
82 else if constexpr (same_function_v<Operation, mpfr_acospi>)
83 return mpreal(exact_rational{1} / exact_rational{2} - rational_asinpi(q).exact_value());
84 else if constexpr (same_function_v<Operation, mpfr_atanpi>)
85 {
86 if (q == 0) return mpreal{};
87 if (q == 1 || q == -1) return mpreal(q / exact_rational{4});
88 }
89 else if constexpr (same_function_v<Operation, mpfr_sec> || same_function_v<Operation, mpfr_sech>)
90 {
91 if (q == 0) return mpreal{1};
92 }
93 throw std::logic_error("extended elementary function requires finite working precision");
94 }
95 return mpreal_access::finite_result(p, [&](mpfr_ptr out) { Operation(out, x.native_handle(), MPFR_RNDN); });
96}
97template <auto Operation> mpreal extended_unary(mpreal const& x, Precision p)
98{
99 (void)p.bit_count();
100 return extended_unary<Operation>(x.at(p));
101}
102} // namespace detail
103
105inline mpreal exp10(mpreal const& x) { return detail::extended_unary<mpfr_exp10>(x); }
107inline mpreal exp10(mpreal const& x, Precision p) { return detail::extended_unary<mpfr_exp10>(x, p); }
108
110inline mpreal exp2m1(mpreal const& x) { return detail::extended_unary<mpfr_exp2m1>(x); }
112inline mpreal exp2m1(mpreal const& x, Precision p) { return detail::extended_unary<mpfr_exp2m1>(x, p); }
113
115inline mpreal exp10m1(mpreal const& x) { return detail::extended_unary<mpfr_exp10m1>(x); }
117inline mpreal exp10m1(mpreal const& x, Precision p) { return detail::extended_unary<mpfr_exp10m1>(x, p); }
118
120inline mpreal log2p1(mpreal const& x) { return detail::extended_unary<mpfr_log2p1>(x); }
122inline mpreal log2p1(mpreal const& x, Precision p) { return detail::extended_unary<mpfr_log2p1>(x, p); }
123
125inline mpreal log10p1(mpreal const& x) { return detail::extended_unary<mpfr_log10p1>(x); }
127inline mpreal log10p1(mpreal const& x, Precision p) { return detail::extended_unary<mpfr_log10p1>(x, p); }
128
130inline mpreal sinpi(mpreal const& x) { return detail::extended_unary<mpfr_sinpi>(x); }
132inline mpreal sinpi(mpreal const& x, Precision p) { return detail::extended_unary<mpfr_sinpi>(x, p); }
133
135inline mpreal cospi(mpreal const& x) { return detail::extended_unary<mpfr_cospi>(x); }
137inline mpreal cospi(mpreal const& x, Precision p) { return detail::extended_unary<mpfr_cospi>(x, p); }
138
140inline mpreal tanpi(mpreal const& x) { return detail::extended_unary<mpfr_tanpi>(x); }
142inline mpreal tanpi(mpreal const& x, Precision p) { return detail::extended_unary<mpfr_tanpi>(x, p); }
143
145inline mpreal asinpi(mpreal const& x) { return detail::extended_unary<mpfr_asinpi>(x); }
147inline mpreal asinpi(mpreal const& x, Precision p) { return detail::extended_unary<mpfr_asinpi>(x, p); }
148
150inline mpreal acospi(mpreal const& x) { return detail::extended_unary<mpfr_acospi>(x); }
152inline mpreal acospi(mpreal const& x, Precision p) { return detail::extended_unary<mpfr_acospi>(x, p); }
153
155inline mpreal atanpi(mpreal const& x) { return detail::extended_unary<mpfr_atanpi>(x); }
157inline mpreal atanpi(mpreal const& x, Precision p) { return detail::extended_unary<mpfr_atanpi>(x, p); }
158
160inline mpreal sec(mpreal const& x) { return detail::extended_unary<mpfr_sec>(x); }
162inline mpreal sec(mpreal const& x, Precision p) { return detail::extended_unary<mpfr_sec>(x, p); }
163
165inline mpreal csc(mpreal const& x) { return detail::extended_unary<mpfr_csc>(x); }
167inline mpreal csc(mpreal const& x, Precision p) { return detail::extended_unary<mpfr_csc>(x, p); }
168
170inline mpreal cot(mpreal const& x) { return detail::extended_unary<mpfr_cot>(x); }
172inline mpreal cot(mpreal const& x, Precision p) { return detail::extended_unary<mpfr_cot>(x, p); }
173
175inline mpreal sech(mpreal const& x) { return detail::extended_unary<mpfr_sech>(x); }
177inline mpreal sech(mpreal const& x, Precision p) { return detail::extended_unary<mpfr_sech>(x, p); }
178
180inline mpreal csch(mpreal const& x) { return detail::extended_unary<mpfr_csch>(x); }
182inline mpreal csch(mpreal const& x, Precision p) { return detail::extended_unary<mpfr_csch>(x, p); }
183
185inline mpreal coth(mpreal const& x) { return detail::extended_unary<mpfr_coth>(x); }
187inline mpreal coth(mpreal const& x, Precision p) { return detail::extended_unary<mpfr_coth>(x, p); }
188
192inline mpreal atan2pi(mpreal const& y, mpreal const& x)
193{
194 auto p = common_precision(y.precision(), x.precision());
195 if (p.is_exact())
196 {
197 if (y == 0)
198 {
199 if (x == 0) throw std::domain_error("exact atan2pi needs a nonzero direction");
200 return mpreal{x < 0 ? 1 : 0};
201 }
202 int sign = y < 0 ? -1 : 1;
203 if (x == 0) return mpreal(exact_rational{sign} / exact_rational{2});
204 if (abs(x) == abs(y)) return mpreal(exact_rational{sign * (x < 0 ? 3 : 1)} / exact_rational{4});
205 throw std::logic_error("atan2pi requires finite precision for this direction");
206 }
207 auto yv = y.at(p), xv = x.at(p);
208 return detail::mpreal_access::finite_result(
209 p, [&](mpfr_ptr out) { mpfr_atan2pi(out, yv.native_handle(), xv.native_handle(), MPFR_RNDN); });
210}
212inline mpreal atan2pi(mpreal const& y, mpreal const& x, Precision p)
213{
214 (void)p.bit_count();
215 return atan2pi(y.at(p), x.at(p));
216}
217
218} // namespace uni20
Exact arithmetic or an explicit binary working precision.
Definition core/precision.hpp:13
Owning arbitrary-size rational with exact, eager arithmetic.
Definition exact_rational.hpp:161
Owning exact rational or finite-precision MPFR real, with eager arithmetic.
Definition mpreal.hpp:74
mpreal at(Precision p) const
Definition mpreal.hpp:206
mpfr_srcptr native_handle() const
Borrow an approximate MPFR value; exact and unset states require explicit materialization first.
Definition mpreal.hpp:184
Precision precision() const
Return exact state or the working precision stored by MPFR.
Definition mpreal.hpp:178
exact_rational const & exact_value() const
Borrow the exact rational; valid while this object retains its state.
Definition mpreal.hpp:191
locale_t value
Definition data_table.cpp:49
Definition data_table.cpp:8
Definition async/async.hpp:26
mpreal asinpi(mpreal const &x)
Principal arcsine divided by pi.
Definition mpreal_extensions.hpp:145
mpreal coth(mpreal const &x)
Reciprocal hyperbolic tangent, evaluated directly by MPFR.
Definition mpreal_extensions.hpp:185
constexpr auto abs(basic_half_int< T > value) -> basic_half_int< T >
Return the absolute value of a half-integer.
Definition half_int.hpp:431
mpreal sec(mpreal const &x)
Reciprocal cosine, evaluated directly by MPFR.
Definition mpreal_extensions.hpp:160
mpreal csc(mpreal const &x)
Reciprocal sine, evaluated directly by MPFR.
Definition mpreal_extensions.hpp:165
mpreal cot(mpreal const &x)
Reciprocal tangent, evaluated directly by MPFR.
Definition mpreal_extensions.hpp:170
mpreal exp10m1(mpreal const &x)
Ten to the power x minus one, using the cancellation-safe provider.
Definition mpreal_extensions.hpp:115
mpreal log2p1(mpreal const &x)
Base-two logarithm of one plus x, without rounding the sum first.
Definition mpreal_extensions.hpp:120
mpreal atan2pi(mpreal const &y, mpreal const &x)
Quadrant-aware arctangent of y/x, divided by pi.
Definition mpreal_extensions.hpp:192
mpreal exp10(mpreal const &x)
Base-ten exponential.
Definition mpreal_extensions.hpp:105
constexpr Precision common_precision(Precision a, Precision b)
Combine precisions, treating exact values as neutral and rejecting unequal finite precisions.
Definition core/precision.hpp:57
mpreal cospi(mpreal const &x)
Cosine of pi times x, with provider argument reduction.
Definition mpreal_extensions.hpp:135
mpreal sech(mpreal const &x)
Reciprocal hyperbolic cosine, evaluated directly by MPFR.
Definition mpreal_extensions.hpp:175
exact_rational pow(X const &base, Y const &power)
Evaluate a rational power exactly when its real result is rational.
Definition exact_rational.hpp:337
mpreal acospi(mpreal const &x)
Principal arccosine divided by pi.
Definition mpreal_extensions.hpp:150
mpreal atanpi(mpreal const &x)
Principal arctangent divided by pi.
Definition mpreal_extensions.hpp:155
mpreal csch(mpreal const &x)
Reciprocal hyperbolic sine, evaluated directly by MPFR.
Definition mpreal_extensions.hpp:180
mpreal tanpi(mpreal const &x)
Tangent of pi times x, with provider argument reduction.
Definition mpreal_extensions.hpp:140
mpreal exp2m1(mpreal const &x)
Two to the power x minus one, using the cancellation-safe provider.
Definition mpreal_extensions.hpp:110
mpreal sinpi(mpreal const &x)
Sine of pi times x, with provider argument reduction.
Definition mpreal_extensions.hpp:130
mpreal log10p1(mpreal const &x)
Base-ten logarithm of one plus x, without rounding the sum first.
Definition mpreal_extensions.hpp:125