Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
mpcomplex.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "mpreal.hpp"
4#if !UNI20_HAS_MPREAL
5#error "uni20/core/mpcomplex.hpp requires UNI20_ENABLE_MPREAL=ON (GMP, MPFR and MPC)"
6#endif
7#include <mpc.h>
8
9namespace uni20
10{
11namespace detail
12{
13struct mpcomplex_access;
14struct exact_complex
15{
16 exact_rational re;
17 exact_rational im;
18};
19struct mpc_value
20{
21 mpc_t value{};
22 bool initialized = false;
23 explicit mpc_value(Precision p)
24 {
25 require_mpfr_tls();
26 mpc_init2(value, mpfr_precision(p));
27 initialized = true;
28 mpc_set_ui(value, 0, MPC_RNDNN);
29 }
30 mpc_value(mpc_value const& other) : mpc_value(Precision::bits(mpc_get_prec(other.value)))
31 {
32 mpc_set(value, other.value, MPC_RNDNN);
33 }
34 mpc_value(mpc_value&& other) noexcept
35 {
36 std::swap(value[0], other.value[0]);
37 std::swap(initialized, other.initialized);
38 }
39 mpc_value& operator=(mpc_value other) noexcept
40 {
41 std::swap(value[0], other.value[0]);
42 std::swap(initialized, other.initialized);
43 return *this;
44 }
45 ~mpc_value()
46 {
47 if (initialized) mpc_clear(value);
48 }
49};
50} // namespace detail
51
57class mpcomplex {
58 public:
61 mpcomplex() : value_(std::in_place_type<detail::exact_complex>) {}
63 explicit mpcomplex(uninitialized_t) noexcept : value_(std::monostate{}) {}
65 {
66 if (p.is_exact())
67 value_.emplace<detail::exact_complex>();
68 else
69 value_.emplace<detail::mpc_value>(p);
70 }
72 mpcomplex(mpreal const& re, mpreal const& im, Precision p) : mpcomplex(p)
73 {
74 if (p.is_exact())
75 {
76 if (!re.precision().is_exact() || !im.precision().is_exact())
77 throw std::invalid_argument("complex<mpreal>: an approximation cannot be reclassified as exact");
78 value_ = detail::exact_complex{re.exact_value(), im.exact_value()};
79 }
80 else
81 {
82 re.copy_to(mpc_realref(this->approximate()));
83 im.copy_to(mpc_imagref(this->approximate()));
84 }
85 }
86 mpcomplex(mpreal const& re, mpreal const& im) : mpcomplex(re, im, common_precision(re.precision(), im.precision()))
87 {}
88 mpcomplex(mpreal const& re) : mpcomplex(re, mpreal{}, re.precision()) {}
89 mpcomplex(mpreal const& re, Precision p) : mpcomplex(re, mpreal{}, p) {}
90 template <std::integral I>
91 requires(!std::same_as<I, bool>)
93 {}
96 template <std::integral I>
97 requires(!std::same_as<I, bool>)
102 mpcomplex(std::string_view re, std::string_view im, Precision p) : mpcomplex(mpreal(re, p), mpreal(im, p)) {}
104 {
105 other.require_value();
106 if (p.is_exact())
107 {
108 if (!other.is_exact())
109 throw std::invalid_argument("complex<mpreal>: an approximation cannot be reclassified as exact");
110 value_ = std::get<detail::exact_complex>(other.value_);
111 }
112 else
113 other.copy_to(this->approximate());
114 }
117 explicit mpcomplex(mpc_srcptr value, Precision p) : mpcomplex(p) { mpc_set(this->approximate(), value, MPC_RNDNN); }
118 mpcomplex(mpcomplex const&) = default;
120 mpcomplex(mpcomplex&& other) noexcept : value_(std::move(other.value_)) { other.value_.emplace<std::monostate>(); }
122 {
123 this->swap(other);
124 return *this;
125 }
126 void swap(mpcomplex& other) noexcept { value_.swap(other.value_); }
128 bool initialized() const noexcept { return !std::holds_alternative<std::monostate>(value_); }
130 bool is_exact() const noexcept { return std::holds_alternative<detail::exact_complex>(value_); }
132 {
133 this->require_value();
134 return this->is_exact() ? Precision::exact() : Precision::bits(mpc_get_prec(this->native_handle()));
135 }
137 mpc_srcptr native_handle() const
138 {
139 this->require_value();
140 if (this->is_exact())
141 throw std::logic_error("complex<mpreal>: exact value needs finite precision before MPC access");
142 return std::get<detail::mpc_value>(value_).value;
143 }
145 void copy_to(mpc_ptr destination) const
146 {
147 this->require_value();
148 if (this->is_exact())
149 {
150 auto const& q = std::get<detail::exact_complex>(value_);
151 mpfr_set_q(mpc_realref(destination), q.re.native_handle(), MPFR_RNDN);
152 mpfr_set_q(mpc_imagref(destination), q.im.native_handle(), MPFR_RNDN);
153 }
154 else
155 mpc_set(destination, this->native_handle(), MPC_RNDNN);
156 }
157 mpcomplex at(Precision p) const { return mpcomplex(*this, p); }
159 mpreal real() const
160 {
161 if (this->is_exact()) return mpreal(std::get<detail::exact_complex>(value_).re);
162 return mpreal(mpc_realref(this->native_handle()), this->precision());
163 }
164 mpreal imag() const
165 {
166 if (this->is_exact()) return mpreal(std::get<detail::exact_complex>(value_).im);
167 return mpreal(mpc_imagref(this->native_handle()), this->precision());
168 }
170 void real(mpreal const& re)
171 {
172 auto p = this->precision();
173 if (p.is_exact())
174 *this = mpcomplex(re, this->imag());
175 else
176 re.copy_to(mpc_realref(this->approximate()));
177 }
178 void imag(mpreal const& im)
179 {
180 auto p = this->precision();
181 if (p.is_exact())
182 *this = mpcomplex(this->real(), im);
183 else
184 im.copy_to(mpc_imagref(this->approximate()));
185 }
186 mpcomplex& operator+=(mpcomplex const& rhs);
187 mpcomplex& operator-=(mpcomplex const& rhs);
188 mpcomplex& operator*=(mpcomplex const& rhs);
189 mpcomplex& operator/=(mpcomplex const& rhs);
194
195 private:
196 friend struct detail::mpcomplex_access;
197 explicit mpcomplex(detail::exact_complex q) : value_(std::move(q)) {}
198 void require_value() const
199 {
200 if (!this->initialized()) throw std::logic_error("complex<mpreal>: numerical use of an unset value");
201 }
202 mpc_ptr approximate()
203 {
204 (void)this->native_handle();
205 return std::get<detail::mpc_value>(value_).value;
206 }
207 std::variant<std::monostate, detail::exact_complex, detail::mpc_value> value_;
208};
209
210namespace detail
211{
212struct mpcomplex_access
213{
214 template <auto Operation> static mpcomplex unary(mpcomplex const& x, Precision p)
215 {
216 (void)p.bit_count();
217 return unary<Operation>(x.at(p));
218 }
219 template <auto Operation> static mpcomplex binary(mpcomplex const& x, mpcomplex const& y, Precision p)
220 {
221 (void)p.bit_count();
222 return binary<Operation>(x.at(p), y.at(p));
223 }
224 template <auto Operation> static mpreal real_result(mpcomplex const& x, Precision p)
225 {
226 (void)p.bit_count();
227 return real_result<Operation>(x.at(p));
228 }
229
230 static mpcomplex exact_sqrt(mpcomplex const& x)
231 {
232 auto const& q = std::get<exact_complex>(x.value_);
233 auto magnitude = uni20::sqrt(q.re * q.re + q.im * q.im);
234 auto re = uni20::sqrt((magnitude + q.re) / 2);
235 auto im = uni20::sqrt((magnitude - q.re) / 2);
236 // Exact zero has no sign: the principal root uses the upper cut side.
237 if (q.im < 0) im = -im;
238 return mpcomplex(exact_complex{std::move(re), std::move(im)});
239 }
240 template <auto Operation> static mpcomplex unary(mpcomplex const& x)
241 {
242 auto p = x.precision();
243 if (p.is_exact())
244 {
245 auto const& q = std::get<exact_complex>(x.value_);
246 if constexpr (same_function_v<Operation, mpc_neg>)
247 return mpcomplex(exact_complex{-q.re, -q.im});
248 else if constexpr (same_function_v<Operation, mpc_conj>)
249 return mpcomplex(exact_complex{q.re, -q.im});
250 else if constexpr (same_function_v<Operation, mpc_sqrt>)
251 return exact_sqrt(x);
252 else
253 {
254 if constexpr (same_function_v<Operation, mpc_exp> || same_function_v<Operation, mpc_cos> ||
255 same_function_v<Operation, mpc_cosh>)
256 {
257 if (q.re == 0 && q.im == 0) return mpcomplex{1};
258 }
259 else if constexpr (same_function_v<Operation, mpc_log> || same_function_v<Operation, mpc_acosh>)
260 {
261 if (q.re == 1 && q.im == 0) return mpcomplex{};
262 }
263 else if constexpr (same_function_v<Operation, mpc_sin> || same_function_v<Operation, mpc_sinh>)
264 {
265 if (q.re == 0 && q.im == 0) return mpcomplex{};
266 }
267 throw std::logic_error("complex<mpreal>: elementary function requires finite working precision");
268 }
269 }
270 mpcomplex out(p);
271 Operation(out.approximate(), x.native_handle(), MPC_RNDNN);
272 return out;
273 }
274 template <auto Operation> static mpcomplex mixed_finite(mpcomplex const& a, mpcomplex const& b, Precision p)
275 {
276 auto ar = a.real(), ai = a.imag(), br = b.real(), bi = b.imag();
277 if constexpr (same_function_v<Operation, mpc_add>)
278 return mpcomplex(ar + br, ai + bi, p);
279 else if constexpr (same_function_v<Operation, mpc_sub>)
280 return mpcomplex(ar - br, ai - bi, p);
281 else
282 {
283 if (!mpreal_access::can_expand_rational(ar) || !mpreal_access::can_expand_rational(ai) ||
284 !mpreal_access::can_expand_rational(br) || !mpreal_access::can_expand_rational(bi))
285 {
286 auto xr = mpreal_access::stored_scaled(ar), xi = mpreal_access::stored_scaled(ai);
287 auto yr = mpreal_access::stored_scaled(br), yi = mpreal_access::stored_scaled(bi);
288 auto rr = xr * yr, ii = xi * yi, ri = xr * yi, ir = xi * yr;
289 mpcomplex result(p);
290 if constexpr (same_function_v<Operation, mpc_mul>)
291 {
292 scaled_rational_ratio({rr, -ii, {exact_rational{1}, 0}, {}}).round_to(mpc_realref(result.approximate()));
293 scaled_rational_ratio({ri, ir, {exact_rational{1}, 0}, {}}).round_to(mpc_imagref(result.approximate()));
294 }
295 else
296 {
297 auto dr = yr * yr, di = yi * yi;
298 scaled_rational_ratio({rr, ii, dr, di}).round_to(mpc_realref(result.approximate()));
299 scaled_rational_ratio({ir, -ri, dr, di}).round_to(mpc_imagref(result.approximate()));
300 }
301 // Cancellation produces +0. Two zero products preserve the same sign
302 // rules as the ordinary rational path; underflow signs stay intact.
303 bool const rr_negative = signbit(ar) != signbit(br), ii_negative = signbit(ai) != signbit(bi);
304 bool const ri_negative = signbit(ar) != signbit(bi), ir_negative = signbit(ai) != signbit(br);
305 if (rr.coefficient == 0 && ii.coefficient == 0)
306 mpfr_set_zero(mpc_realref(result.approximate()),
307 (rr_negative && (same_function_v<Operation, mpc_mul> ? !ii_negative : ii_negative)) ? -1 : 1);
308 if (ri.coefficient == 0 && ir.coefficient == 0)
309 mpfr_set_zero(mpc_imagref(result.approximate()),
310 (ir_negative && (same_function_v<Operation, mpc_mul> ? ri_negative : !ri_negative)) ? -1 : 1);
311 return result;
312 }
313 auto xr = mpreal_access::stored_rational(ar), xi = mpreal_access::stored_rational(ai);
314 auto yr = mpreal_access::stored_rational(br), yi = mpreal_access::stored_rational(bi);
315 // Form each component exactly before its single final rounding. Keep
316 // signed-zero rules from the component products: rational zero alone
317 // does not distinguish the two sides of a complex branch cut.
318 auto rr = xr * yr, ii = xi * yi, ri = xr * yi, ir = xi * yr;
319 bool const rr_negative = signbit(ar) != signbit(br);
320 bool const ii_negative = signbit(ai) != signbit(bi);
321 bool const ri_negative = signbit(ar) != signbit(bi);
322 bool const ir_negative = signbit(ai) != signbit(br);
323 exact_complex value;
324 bool re_negative_zero, im_negative_zero;
325 if constexpr (same_function_v<Operation, mpc_mul>)
326 {
327 value = {rr - ii, ri + ir};
328 re_negative_zero = rr == 0 && ii == 0 && rr_negative && !ii_negative;
329 im_negative_zero = ri == 0 && ir == 0 && ri_negative && ir_negative;
330 }
331 else
332 {
333 auto d = yr * yr + yi * yi;
334 value = {(rr + ii) / d, (ir - ri) / d};
335 re_negative_zero = rr == 0 && ii == 0 && rr_negative && ii_negative;
336 im_negative_zero = ir == 0 && ri == 0 && ir_negative && !ri_negative;
337 }
338 mpcomplex result(value);
339 result = result.at(p);
340 if (value.re == 0) mpfr_set_zero(mpc_realref(result.approximate()), re_negative_zero ? -1 : 1);
341 if (value.im == 0) mpfr_set_zero(mpc_imagref(result.approximate()), im_negative_zero ? -1 : 1);
342 return result;
343 }
344 }
345
346 template <auto Operation> static mpcomplex binary(mpcomplex const& a, mpcomplex const& b)
347 {
348 auto p = common_precision(a.precision(), b.precision());
349 if (p.is_exact())
350 {
351 auto const& x = std::get<exact_complex>(a.value_);
352 auto const& y = std::get<exact_complex>(b.value_);
353 if constexpr (same_function_v<Operation, mpc_add>)
354 return mpcomplex(exact_complex{x.re + y.re, x.im + y.im});
355 else if constexpr (same_function_v<Operation, mpc_sub>)
356 return mpcomplex(exact_complex{x.re - y.re, x.im - y.im});
357 else if constexpr (same_function_v<Operation, mpc_mul>)
358 return mpcomplex(exact_complex{x.re * y.re - x.im * y.im, x.re * y.im + x.im * y.re});
359 else if constexpr (same_function_v<Operation, mpc_div>)
360 {
361 auto d = y.re * y.re + y.im * y.im;
362 return mpcomplex(exact_complex{(x.re * y.re + x.im * y.im) / d, (x.im * y.re - x.re * y.im) / d});
363 }
364 else
365 {
366 if constexpr (same_function_v<Operation, mpc_pow>)
367 {
368 if (y.im == 0)
369 {
370 auto exponent = y.re.native_handle();
371 if (mpz_cmp_ui(mpq_denref(exponent), 1) == 0) return integer_power(a, mpq_numref(exponent));
372 if (mpz_cmp_ui(mpq_denref(exponent), 2) == 0) return integer_power(exact_sqrt(a), mpq_numref(exponent));
373 if (x.im == 0 && x.re >= 0) return mpcomplex(uni20::pow(x.re, y.re));
374 }
375 if (x.re == 1 && x.im == 0) return mpcomplex{1};
376 }
377 throw std::logic_error("complex<mpreal>: elementary function requires finite working precision");
378 }
379 }
380 if constexpr (same_function_v<Operation, mpc_add> || same_function_v<Operation, mpc_sub> ||
381 same_function_v<Operation, mpc_mul> || same_function_v<Operation, mpc_div>)
382 {
383 if (a.is_exact() != b.is_exact())
384 {
385 auto const& approximate = a.is_exact() ? b : a;
386 auto native = approximate.native_handle();
387 bool const finite = mpfr_number_p(mpc_realref(native)) && mpfr_number_p(mpc_imagref(native));
388 if (finite && (!same_function_v<Operation, mpc_div> || b.real() != 0 || b.imag() != 0))
389 return mixed_finite<Operation>(a, b, p);
390 }
391 }
392 mpcomplex av(uninitialized), bv(uninitialized);
393 if (a.is_exact()) av = a.at(p);
394 if (b.is_exact()) bv = b.at(p);
395 mpcomplex out(p);
396 Operation(out.approximate(), a.is_exact() ? av.native_handle() : a.native_handle(),
397 b.is_exact() ? bv.native_handle() : b.native_handle(), MPC_RNDNN);
398 return out;
399 }
400 template <auto Operation> static mpcomplex& assign(mpcomplex& a, mpcomplex const& b)
401 {
402 if (!a.is_exact() && !b.is_exact())
403 {
404 (void)common_precision(a.precision(), b.precision());
405 Operation(a.approximate(), a.native_handle(), b.native_handle(), MPC_RNDNN);
406 }
407 else
408 a = binary<Operation>(a, b);
409 return a;
410 }
411 template <auto Operation> static mpreal real_result(mpcomplex const& x)
412 {
413 auto p = x.precision();
414 if (p.is_exact())
415 {
416 if constexpr (same_function_v<Operation, mpc_norm>)
417 {
418 auto const& q = std::get<exact_complex>(x.value_);
419 return mpreal(q.re * q.re + q.im * q.im);
420 }
421 else
422 {
423 auto const& q = std::get<exact_complex>(x.value_);
424 if constexpr (same_function_v<Operation, mpc_abs>)
425 return mpreal(uni20::sqrt(q.re * q.re + q.im * q.im));
426 else if constexpr (same_function_v<Operation, mpc_arg>)
427 if (q.im == 0 && q.re > 0) return mpreal{};
428 throw std::logic_error("complex<mpreal>: elementary function requires finite working precision");
429 }
430 }
431 mpreal out(p);
432 Operation(out.approximate(), x.native_handle(), MPFR_RNDN);
433 return out;
434 }
435};
436} // namespace detail
437
438inline mpcomplex operator+(mpcomplex const& a, mpcomplex const& b)
439{
440 return detail::mpcomplex_access::binary<mpc_add>(a, b);
441}
442inline mpcomplex operator-(mpcomplex const& a, mpcomplex const& b)
443{
444 return detail::mpcomplex_access::binary<mpc_sub>(a, b);
445}
446inline mpcomplex operator*(mpcomplex const& a, mpcomplex const& b)
447{
448 return detail::mpcomplex_access::binary<mpc_mul>(a, b);
449}
450inline mpcomplex operator/(mpcomplex const& a, mpcomplex const& b)
451{
452 return detail::mpcomplex_access::binary<mpc_div>(a, b);
453}
454inline mpcomplex operator-(mpcomplex const& x) { return detail::mpcomplex_access::unary<mpc_neg>(x); }
455inline mpcomplex operator+(mpcomplex const& x)
456{
457 (void)x.precision();
458 return x;
459}
461{
462 return detail::mpcomplex_access::assign<mpc_add>(*this, rhs);
463}
465{
466 return detail::mpcomplex_access::assign<mpc_sub>(*this, rhs);
467}
469{
470 return detail::mpcomplex_access::assign<mpc_mul>(*this, rhs);
471}
473{
474 return detail::mpcomplex_access::assign<mpc_div>(*this, rhs);
475}
476
477inline mpcomplex operator+(mpcomplex const& a, exact_rational const& b) { return a + mpcomplex(b); }
478inline mpcomplex operator-(mpcomplex const& a, exact_rational const& b) { return a - mpcomplex(b); }
479inline mpcomplex operator*(mpcomplex const& a, exact_rational const& b) { return a * mpcomplex(b); }
480inline mpcomplex operator/(mpcomplex const& a, exact_rational const& b) { return a / mpcomplex(b); }
481inline mpcomplex operator+(exact_rational const& a, mpcomplex const& b) { return mpcomplex(a) + b; }
482inline mpcomplex operator-(exact_rational const& a, mpcomplex const& b) { return mpcomplex(a) - b; }
483inline mpcomplex operator*(exact_rational const& a, mpcomplex const& b) { return mpcomplex(a) * b; }
484inline mpcomplex operator/(exact_rational const& a, mpcomplex const& b) { return mpcomplex(a) / b; }
485inline mpcomplex& mpcomplex::operator+=(exact_rational const& rhs) { return *this += mpcomplex(rhs); }
486inline mpcomplex& mpcomplex::operator-=(exact_rational const& rhs) { return *this -= mpcomplex(rhs); }
487inline mpcomplex& mpcomplex::operator*=(exact_rational const& rhs) { return *this *= mpcomplex(rhs); }
488inline mpcomplex& mpcomplex::operator/=(exact_rational const& rhs) { return *this /= mpcomplex(rhs); }
489
490inline bool operator==(mpcomplex const& a, mpcomplex const& b) { return a.real() == b.real() && a.imag() == b.imag(); }
491inline bool operator==(mpcomplex const& a, exact_rational const& b) { return a.real() == b && a.imag() == 0; }
492inline mpcomplex conj(mpcomplex const& z) { return detail::mpcomplex_access::unary<mpc_conj>(z); }
493inline mpreal abs(mpcomplex const& z) { return detail::mpcomplex_access::real_result<mpc_abs>(z); }
494inline mpreal norm(mpcomplex const& z) { return detail::mpcomplex_access::real_result<mpc_norm>(z); }
495inline mpreal arg(mpcomplex const& z) { return detail::mpcomplex_access::real_result<mpc_arg>(z); }
496inline mpreal real(mpcomplex const& z) { return z.real(); }
497inline mpreal imag(mpcomplex const& z) { return z.imag(); }
498inline bool isfinite(mpcomplex const& z) { return isfinite(z.real()) && isfinite(z.imag()); }
499inline bool isnan(mpcomplex const& z) { return isnan(z.real()) || isnan(z.imag()); }
500inline bool isinf(mpcomplex const& z) { return isinf(z.real()) || isinf(z.imag()); }
502inline mpcomplex sqrt(mpcomplex const& z) { return detail::mpcomplex_access::unary<mpc_sqrt>(z); }
503inline mpcomplex exp(mpcomplex const& z) { return detail::mpcomplex_access::unary<mpc_exp>(z); }
505inline mpcomplex log(mpcomplex const& z) { return detail::mpcomplex_access::unary<mpc_log>(z); }
506inline mpcomplex sin(mpcomplex const& z) { return detail::mpcomplex_access::unary<mpc_sin>(z); }
507inline mpcomplex cos(mpcomplex const& z) { return detail::mpcomplex_access::unary<mpc_cos>(z); }
509inline mpcomplex sinh(mpcomplex const& z) { return detail::mpcomplex_access::unary<mpc_sinh>(z); }
511inline mpcomplex cosh(mpcomplex const& z) { return detail::mpcomplex_access::unary<mpc_cosh>(z); }
514inline mpcomplex acosh(mpcomplex const& z) { return detail::mpcomplex_access::unary<mpc_acosh>(z); }
515inline mpcomplex pow(mpcomplex const& a, mpcomplex const& b) { return detail::mpcomplex_access::binary<mpc_pow>(a, b); }
519inline mpcomplex sqrt(mpcomplex const& z, Precision p) { return detail::mpcomplex_access::unary<mpc_sqrt>(z, p); }
523inline mpcomplex exp(mpcomplex const& z, Precision p) { return detail::mpcomplex_access::unary<mpc_exp>(z, p); }
527inline mpcomplex log(mpcomplex const& z, Precision p) { return detail::mpcomplex_access::unary<mpc_log>(z, p); }
531inline mpcomplex sin(mpcomplex const& z, Precision p) { return detail::mpcomplex_access::unary<mpc_sin>(z, p); }
535inline mpcomplex cos(mpcomplex const& z, Precision p) { return detail::mpcomplex_access::unary<mpc_cos>(z, p); }
539inline mpcomplex sinh(mpcomplex const& z, Precision p) { return detail::mpcomplex_access::unary<mpc_sinh>(z, p); }
543inline mpcomplex cosh(mpcomplex const& z, Precision p) { return detail::mpcomplex_access::unary<mpc_cosh>(z, p); }
547inline mpcomplex acosh(mpcomplex const& z, Precision p) { return detail::mpcomplex_access::unary<mpc_acosh>(z, p); }
551inline mpreal abs(mpcomplex const& z, Precision p) { return detail::mpcomplex_access::real_result<mpc_abs>(z, p); }
555inline mpreal norm(mpcomplex const& z, Precision p) { return detail::mpcomplex_access::real_result<mpc_norm>(z, p); }
559inline mpreal arg(mpcomplex const& z, Precision p) { return detail::mpcomplex_access::real_result<mpc_arg>(z, p); }
562inline mpcomplex pow(mpcomplex const& a, mpcomplex const& b, Precision p)
563{
564 return detail::mpcomplex_access::binary<mpc_pow>(a, b, p);
565}
566
567inline std::ostream& operator<<(std::ostream& out, mpcomplex const& z)
568{
569 return out << '(' << z.real() << ',' << z.imag() << ')';
570}
571} // namespace uni20
Exact arithmetic or an explicit binary working precision.
Definition core/precision.hpp:13
static constexpr Precision bits(bit_count_type count)
Select a positive binary significand size.
Definition core/precision.hpp:21
constexpr bool is_exact() const noexcept
Definition core/precision.hpp:18
static constexpr Precision exact() noexcept
No approximation has been selected; rational arithmetic remains exact.
Definition core/precision.hpp:17
A precisionless decimal spelling produced by the _mp literal operator.
Definition exact_rational.hpp:27
Owning arbitrary-size rational with exact, eager arithmetic.
Definition exact_rational.hpp:161
Exact rational complex value or owning finite-precision MPC approximation.
Definition mpcomplex.hpp:57
void swap(mpcomplex &other) noexcept
Definition mpcomplex.hpp:126
mpcomplex & operator*=(mpcomplex const &rhs)
Definition mpcomplex.hpp:468
mpcomplex(mpcomplex &&other) noexcept
Transfer ownership, leaving the source unset.
Definition mpcomplex.hpp:120
mpcomplex(Precision p)
Definition mpcomplex.hpp:64
mpcomplex at(Precision p) const
Definition mpcomplex.hpp:157
mpcomplex(exact_rational const &value, Precision p)
Definition mpcomplex.hpp:100
mpcomplex & operator/=(mpcomplex const &rhs)
Definition mpcomplex.hpp:472
mpcomplex(mpc_srcptr value, Precision p)
Copy a valid borrowed MPC value at finite component precision.
Definition mpcomplex.hpp:117
mpcomplex & operator=(mpcomplex other) noexcept
Definition mpcomplex.hpp:121
Precision precision() const
Definition mpcomplex.hpp:131
mpcomplex(I value, Precision p)
Definition mpcomplex.hpp:98
mpcomplex & operator-=(mpcomplex const &rhs)
Definition mpcomplex.hpp:464
void imag(mpreal const &im)
Definition mpcomplex.hpp:178
mpcomplex(mpcomplex const &other, Precision p)
Definition mpcomplex.hpp:103
mpc_srcptr native_handle() const
Borrow an approximate MPC value; exact and unset states reject native access.
Definition mpcomplex.hpp:137
bool is_exact() const noexcept
Whether both components are exact rationals.
Definition mpcomplex.hpp:130
mpcomplex(decimal_literal value)
Definition mpcomplex.hpp:95
mpcomplex(std::string_view re, std::string_view im, Precision p)
Definition mpcomplex.hpp:102
mpreal imag() const
Definition mpcomplex.hpp:164
void copy_to(mpc_ptr destination) const
Round into an initialized MPC destination at its existing component precisions.
Definition mpcomplex.hpp:145
mpcomplex(mpreal const &re, mpreal const &im)
Definition mpcomplex.hpp:86
mpcomplex(mpreal const &re, Precision p)
Definition mpcomplex.hpp:89
bool initialized() const noexcept
Whether this object holds exact or approximate numerical components.
Definition mpcomplex.hpp:128
mpcomplex(mpreal const &re, mpreal const &im, Precision p)
Construct components at explicit precision, or retain two exact components.
Definition mpcomplex.hpp:72
mpcomplex(exact_rational const &value)
Definition mpcomplex.hpp:94
mpcomplex(decimal_literal value, Precision p)
Definition mpcomplex.hpp:101
void real(mpreal const &re)
Replace a component, preserving finite precision or adopting the first approximate component's precis...
Definition mpcomplex.hpp:170
mpcomplex(mpcomplex const &)=default
mpcomplex(mpreal const &re)
Definition mpcomplex.hpp:88
mpcomplex(uninitialized_t) noexcept
Construct an unset placeholder for overwrite storage.
Definition mpcomplex.hpp:63
mpcomplex()
Construct exact complex zero.
Definition mpcomplex.hpp:61
mpcomplex & operator+=(mpcomplex const &rhs)
Definition mpcomplex.hpp:460
mpcomplex(I value)
Definition mpcomplex.hpp:92
mpreal real() const
Return an owning component with the same exact/approximate state.
Definition mpcomplex.hpp:159
Owning exact rational or finite-precision MPFR real, with eager arithmetic.
Definition mpreal.hpp:74
void copy_to(mpfr_ptr destination) const
Round into an initialized MPFR destination at its existing precision.
Definition mpreal.hpp:198
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
uni20::complex< T > conj(detail::standard_complex< T > x)
Returns the complex conjugate for complex-valued scalars.
Definition math.hpp:70
constexpr bool isfinite(I const &x) noexcept
Returns whether an integer scalar is finite.
Definition math.hpp:121
Definition qnum.hpp:403
DiagnosticMagnitude< R > magnitude(R const &value)
Definition gmres_diagnostics.hpp:98
Definition data_table.cpp:8
Definition async/async.hpp:26
mpcomplex acosh(mpcomplex const &z)
Principal inverse hyperbolic cosine, with imaginary signed zero selecting the cut side.
Definition mpcomplex.hpp:514
bool isnan(mpcomplex const &z)
Definition mpcomplex.hpp:499
constexpr uninitialized_t uninitialized
Explicit allocation tag for overwrite outputs and scratch space.
Definition common/initialization.hpp:22
constexpr auto operator*(basic_half_int< T > lhs, U rhs) -> basic_half_int< T >
Multiply a half-integer value by an integral scalar.
Definition half_int.hpp:367
auto operator<<(std::ostream &out, basic_half_int< T > value) -> std::ostream &
Stream a half-integer in integer or .5 decimal form.
Definition half_int.hpp:515
mpcomplex sinh(mpcomplex const &z)
Hyperbolic sine at the input precision; exact zero remains exact.
Definition mpcomplex.hpp:509
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
bool operator==(exact_rational const &a, exact_rational const &b)
Definition exact_rational.hpp:284
exact_rational sqrt(X const &value)
Return the nonnegative rational square root, or require finite precision.
Definition exact_rational.hpp:355
mpcomplex log(mpcomplex const &z)
Principal logarithm, with the sign of imaginary zero selecting the cut side.
Definition mpcomplex.hpp:505
bool isinf(mpcomplex const &z)
Definition mpcomplex.hpp:500
constexpr auto operator-(basic_half_int< T > lhs, basic_half_int< T > rhs) -> basic_half_int< T >
Subtract two half-integer values.
Definition half_int.hpp:345
mpcomplex cosh(mpcomplex const &z)
Hyperbolic cosine at the input precision; exact zero returns exact one.
Definition mpcomplex.hpp:511
mpreal norm(mpcomplex const &z)
Definition mpcomplex.hpp:494
constexpr bool is_exact(detail::standard_complex< T > const &x)
A standard complex value is exact only when both components are exact.
Definition math.hpp:50
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
bool signbit(mpreal const &x)
Definition mpreal.hpp:642
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 arg(mpcomplex const &z)
Definition mpcomplex.hpp:495
mpcomplex exp(mpcomplex const &z)
Definition mpcomplex.hpp:503
constexpr auto operator/(basic_half_int< T > lhs, U rhs) -> U
Divide a half-integer value by a floating-point scalar.
Definition half_int.hpp:422
mpcomplex sin(mpcomplex const &z)
Definition mpcomplex.hpp:506
mpcomplex cos(mpcomplex const &z)
Definition mpcomplex.hpp:507
Request storage whose numerical values must be written before being read.
Definition common/initialization.hpp:17