12enum class integer_rounding
21inline exact_rational round_rational(exact_rational
const& x, integer_rounding mode)
23 return mpreal_access::rational_result([&](mpq_ptr result) {
24 auto q = x.native_handle();
25 auto numerator = mpq_numref(q), denominator = mpq_denref(q);
26 auto integer = mpq_numref(result);
27 if (mode == integer_rounding::down)
28 mpz_fdiv_q(integer, numerator, denominator);
29 else if (mode == integer_rounding::up)
30 mpz_cdiv_q(integer, numerator, denominator);
34 mpz_tdiv_qr(integer,
remainder.value, numerator, denominator);
35 if (mode == integer_rounding::toward_zero)
return;
38 int comparison = mpz_cmp(
remainder.value, denominator);
39 if (comparison > 0 || (comparison == 0 && (mode == integer_rounding::away_ties || mpz_odd_p(integer))))
41 if (mpz_sgn(numerator) < 0)
42 mpz_sub_ui(integer, integer, 1);
44 mpz_add_ui(integer, integer, 1);
50template <
integer_rounding Mode, auto Operation> mpreal round_integer(mpreal
const& x, Precision
p)
53 if (x.is_exact())
return mpreal(round_rational(x.exact_value(), Mode),
p);
54 return mpreal_access::finite_result(
p, [&](mpfr_ptr result) { Operation(result, x.native_handle(), MPFR_RNDN); });
61 return detail::round_integer<detail::integer_rounding::down, mpfr_rint_floor>(x, x.
precision());
68 return detail::round_integer<detail::integer_rounding::down, mpfr_rint_floor>(x,
p);
74 return detail::round_integer<detail::integer_rounding::up, mpfr_rint_ceil>(x, x.
precision());
81 return detail::round_integer<detail::integer_rounding::up, mpfr_rint_ceil>(x,
p);
87 return detail::round_integer<detail::integer_rounding::toward_zero, mpfr_rint_trunc>(x, x.
precision());
94 return detail::round_integer<detail::integer_rounding::toward_zero, mpfr_rint_trunc>(x,
p);
100 return detail::round_integer<detail::integer_rounding::away_ties, mpfr_rint_round>(x, x.
precision());
107 return detail::round_integer<detail::integer_rounding::away_ties, mpfr_rint_round>(x,
p);
113 return detail::round_integer<detail::integer_rounding::even_ties, mpfr_rint_roundeven>(x, x.
precision());
120 return detail::round_integer<detail::integer_rounding::even_ties, mpfr_rint_roundeven>(x,
p);
125inline mpreal fused_product_sum(mpreal
const& a, mpreal
const& b, mpreal
const&
c, Precision
p)
130 if (
p.is_exact())
return mpreal(a.exact_value() * b.exact_value() +
c.exact_value());
131 if (!a.is_exact() && !b.is_exact() && !
c.is_exact())
132 return mpreal_access::finite_result(
p, [&](mpfr_ptr result) {
133 mpfr_fma(result, a.native_handle(), b.native_handle(),
c.native_handle(), MPFR_RNDN);
139 auto marker = [
p](mpreal
const& x) {
140 return x.is_exact() ? mpreal(mpq_sgn(x.exact_value().native_handle()),
p) : x;
142 auto av = marker(a), bv = marker(b), cv = marker(
c);
143 return mpreal_access::finite_result(
p, [&](mpfr_ptr result) {
144 mpfr_fma(result, av.native_handle(), bv.native_handle(), cv.native_handle(), MPFR_RNDN);
147 return mpreal_access::finite_result(
p, [&](mpfr_ptr result) {
148 if ((a == 0 || b == 0) &&
c == 0)
151 mpfr_set_zero(result, negative ? -1 : 1);
154 scaled_rational_ratio({mpreal_access::stored_scaled(a) * mpreal_access::stored_scaled(b),
155 mpreal_access::stored_scaled(
c),
156 {exact_rational{1}, 0},
162inline mpreal binary_scale(mpreal
const& x, std::int64_t exponent, Precision
p)
167 return mpreal(mpreal_access::rational_result([&](mpq_ptr q) {
168 mpq_set(q, x.exact_value().native_handle());
169 if (mpq_sgn(q) == 0)
return;
171 mpq_mul_2exp(q, q,
static_cast<mp_bitcnt_t
>(exponent));
173 mpq_div_2exp(q, q,
static_cast<mp_bitcnt_t
>(std::uint64_t(0) - std::uint64_t(exponent)));
176 return mpreal_access::finite_result(
p, [&](mpfr_ptr result) {
179 scaled_rational_ratio({scaled_rational{x.exact_value(), exponent}, {}, {exact_rational{1}, 0}, {}})
184 static_assert(
sizeof(long) >=
sizeof(std::int64_t));
185 mpfr_mul_2si(result, x.native_handle(),
static_cast<long>(exponent), MPFR_RNDN);
194 return detail::fused_product_sum(a, b,
c,
201 return detail::fused_product_sum(a, b,
c,
p);
205template <detail::MathInteger I>
inline mpreal ldexp(
mpreal const& x, I exponent)
207 return detail::binary_scale(x, detail::math_integer(exponent), x.
precision());
213 return detail::binary_scale(x, detail::math_integer(exponent),
p);
216template <detail::MathInteger I>
inline mpreal scalbn(
mpreal const& x, I exponent) {
return ldexp(x, exponent); }
220 return ldexp(x, exponent,
p);
226 auto p = magnitude.precision();
227 bool negative = signbit(sign);
230 auto q = magnitude.exact_value();
231 if ((q < 0) != negative) q = -q;
234 return detail::mpreal_access::finite_result(
235 p, [&](mpfr_ptr result) { mpfr_setsign(result, magnitude.native_handle(), negative, MPFR_RNDN); });
241 return copysign(magnitude.at(
p), sign);
246inline mpreal select_extreme(mpreal
const& a, mpreal
const& b, Precision
p,
bool maximum)
250 if (isnan(a))
return b.at(
p);
251 if (isnan(b))
return a.at(
p);
252 if (a == 0 && b == 0 && !
p.is_exact())
253 return mpreal_access::finite_result(
p, [&](mpfr_ptr result) {
254 bool negative = maximum ? signbit(a) && signbit(b) : signbit(a) || signbit(b);
255 mpfr_set_zero(result, negative ? -1 : 1);
257 return ((maximum ? a > b : a < b) ? a : b).at(
p);
269 return detail::select_extreme(a, b,
p,
false);
280 return detail::select_extreme(a, b,
p,
true);
284inline mpreal positive_difference(mpreal
const& a, mpreal
const& b, Precision
p)
288 if (isnan(a) || isnan(b))
return mpreal(
"nan",
p);
289 if (a <= b)
return mpreal(
p);
290 return fused_product_sum(a, mpreal{1}, -b,
p);
302 return detail::positive_difference(a, b,
p);
308 return detail::mpreal_access::finite_result(x.
precision(), [&](mpfr_ptr result) {
309 mpfr_set(result, x.native_handle(), MPFR_RNDN);
310 mpfr_nextabove(result);
317 return next_up(x.
at(
p));
322 return detail::mpreal_access::finite_result(x.
precision(), [&](mpfr_ptr result) {
323 mpfr_set(result, x.native_handle(), MPFR_RNDN);
324 mpfr_nextbelow(result);
331 return next_down(x.
at(
p));
340 if (isnan(x) || isnan(direction))
return mpreal(
"nan",
p);
341 if (x == direction)
return copysign(x, direction);
342 return x < direction ? next_up(x) : next_down(x);
348 return nextafter(x.
at(
p), direction);
353inline std::int64_t rational_binary_exponent(exact_rational
const& x)
355 auto q = x.native_handle();
356 if (mpq_sgn(q) == 0)
return 0;
357 mp_integer numerator, denominator;
358 mpz_abs(numerator.value, mpq_numref(q));
359 mpz_set(denominator.value, mpq_denref(q));
360 auto exponent =
static_cast<std::int64_t
>(mpz_sizeinbase(numerator.value, 2)) -
361 static_cast<std::int64_t
>(mpz_sizeinbase(denominator.value, 2));
363 mpz_mul_2exp(denominator.value, denominator.value, exponent);
365 mpz_mul_2exp(numerator.value, numerator.value, -exponent);
366 return exponent + (mpz_cmp(numerator.value, denominator.value) >= 0 ? 1 : 0);
368inline frexp_result<mpreal> decompose_binary(mpreal
const& x, Precision
p)
373 auto exponent = rational_binary_exponent(x.exact_value());
374 auto fraction = binary_scale(x, -exponent,
p);
376 if (!
p.is_exact() &&
abs(fraction) == 1)
378 fraction = binary_scale(fraction, -1,
p);
381 return {std::move(fraction), exponent};
384 mpfr_exp_t exponent = 0;
385 auto fraction = mpreal_access::finite_result(
386 p, [&](mpfr_ptr result) { mpfr_frexp(&exponent, result, x.native_handle(), MPFR_RNDN); });
387 return {std::move(fraction), exponent};
389inline modf_result<mpreal> decompose_fraction(mpreal
const& x, Precision
p)
394 auto integer = round_rational(x.exact_value(), integer_rounding::toward_zero);
395 return {mpreal(x.exact_value() - integer,
p), mpreal(integer,
p)};
397 mpreal fraction(uninitialized);
398 auto integer = mpreal_access::finite_result(
p, [&](mpfr_ptr whole) {
400 mpreal_access::finite_result(
p, [&](mpfr_ptr part) { mpfr_modf(whole, part, x.native_handle(), MPFR_RNDN); });
402 return {std::move(fraction), std::move(integer)};
405struct scaled_remainder
407 scaled_rational
value;
412inline scaled_remainder rational_remainder(scaled_rational
const& a, scaled_rational
const& b,
bool nearest)
414 auto aq = a.coefficient.native_handle(), bq = b.coefficient.native_handle();
415 if (mpq_sgn(bq) == 0)
throw std::domain_error(
"exact remainder: zero divisor");
416 mp_integer numerator, divisor,
remainder, quotient, modulus, factor;
417 mpz_mul(numerator.value, mpq_numref(aq), mpq_denref(bq));
418 mpz_abs(numerator.value, numerator.value);
419 mpz_mul(divisor.value, mpq_numref(bq), mpq_denref(aq));
420 mpz_abs(divisor.value, divisor.value);
421 auto difference = a.exponent - b.exponent;
422 auto exponent = b.exponent;
425 mpz_mul_ui(modulus.value, divisor.value, 8);
426 mpz_set_ui(factor.value, 2);
427 mpz_powm_ui(factor.value, factor.value,
static_cast<unsigned long>(difference), modulus.value);
428 mpz_mul(numerator.value, numerator.value, factor.value);
429 mpz_mod(numerator.value, numerator.value, modulus.value);
433 exponent = a.exponent;
434 mpz_neg(factor.value, divisor.value);
435 if (nearest) mpz_mul_2exp(numerator.value, numerator.value, 1);
436 int comparison = scaled_sum_sign<2>({numerator.value, factor.value}, {0, -difference});
437 if (nearest) mpz_tdiv_q_2exp(numerator.value, numerator.value, 1);
438 if (comparison < 0 || (nearest && comparison == 0))
return {a, 0};
440 mpz_mul_2exp(divisor.value, divisor.value,
static_cast<mp_bitcnt_t
>(-difference));
442 mpz_tdiv_qr(quotient.value,
remainder.value, numerator.value, divisor.value);
443 auto quotient_bits =
static_cast<int>(mpz_fdiv_ui(quotient.value, 8));
446 mpz_mul_2exp(factor.value,
remainder.value, 1);
447 int comparison = mpz_cmp(factor.value, divisor.value);
448 if (comparison > 0 || (comparison == 0 && (quotient_bits & 1)))
451 quotient_bits = (quotient_bits + 1) % 8;
455 if ((mpq_sgn(aq) < 0) != (mpq_sgn(bq) < 0)) quotient_bits = -quotient_bits;
456 auto coefficient = mpreal_access::rational_result([&](mpq_ptr q) {
458 mpz_mul(mpq_denref(q), mpq_denref(aq), mpq_denref(bq));
460 return {{std::move(coefficient), exponent}, quotient_bits};
462inline remquo_result<mpreal> remainder_value(mpreal
const& a, mpreal
const& b, Precision
p,
bool nearest)
468 auto result = rational_remainder(mpreal_access::stored_scaled(a), mpreal_access::stored_scaled(b), nearest);
469 return {mpreal(result.value.coefficient), result.quotient};
471 if (!
isfinite(a) ||
isnan(b) || b == 0)
return {mpreal(
"nan",
p), 0};
472 if (
isinf(b))
return {a.at(
p), 0};
473 if (!a.is_exact() && !b.is_exact())
476 auto result = mpreal_access::finite_result(
p, [&](mpfr_ptr out) {
478 mpfr_remquo(out, "ient, a.native_handle(), b.native_handle(), MPFR_RNDN);
480 mpfr_fmodquo(out, "ient, a.native_handle(), b.native_handle(), MPFR_RNDN);
482 return {std::move(result),
static_cast<int>(quotient % 8)};
484 auto result = rational_remainder(mpreal_access::stored_scaled(a), mpreal_access::stored_scaled(b), nearest);
485 auto value = mpreal_access::finite_result(
p, [&](mpfr_ptr out) {
486 if (result.value.coefficient == 0)
487 mpfr_set_zero(out,
signbit(a) ? -1 : 1);
489 scaled_rational_ratio({result.value, {}, {exact_rational{1}, 0}, {}}).round_to(out);
491 return {std::move(
value), result.quotient};
503 return detail::decompose_binary(x,
p);
511 return detail::decompose_fraction(x,
p);
515inline std::int64_t ilogb(
mpreal const& x)
517 if (!isfinite(x) || x == 0)
throw std::domain_error(
"ilogb requires a finite nonzero value");
530 return detail::remainder_value(a, b,
p,
false).remainder;
542 return detail::remainder_value(a, b,
p,
true).remainder;
554 return detail::remainder_value(a, b,
p,
true);
559template <
bool Hyperbolic>
auto paired_functions(mpreal
const& x)
561 using result_type = std::conditional_t<Hyperbolic, sinhcosh_result<mpreal>, sincos_result<mpreal>>;
562 auto p = x.precision();
565 if constexpr (Hyperbolic)
566 return result_type{sinh(x), cosh(x)};
568 return result_type{
sin(x),
cos(x)};
570 mpreal cosine(uninitialized);
571 auto sine = mpreal_access::finite_result(
p, [&](mpfr_ptr s) {
572 cosine = mpreal_access::finite_result(
p, [&](mpfr_ptr
c) {
573 if constexpr (Hyperbolic)
574 mpfr_sinh_cosh(s,
c, x.native_handle(), MPFR_RNDN);
576 mpfr_sin_cos(s,
c, x.native_handle(), MPFR_RNDN);
579 return result_type{std::move(sine), std::move(cosine)};
588 return sincos(x.
at(
p));
596 return sinhcosh(x.
at(
p));
604template <
class F> mpreal rational_monotone(exact_rational
const& positive, Precision
p,
bool decreasing, F operation)
606 auto bits = std::max<mpfr_prec_t>(64,
p.bit_count());
609 auto work = Precision::bits(bits);
610 mpfr_value lower(work), upper(work);
611 mpfr_set_q(lower.value, positive.native_handle(), MPFR_RNDD);
612 mpfr_set_q(upper.value, positive.native_handle(), MPFR_RNDU);
613 if (mpfr_zero_p(lower.value) || mpfr_inf_p(upper.value))
614 throw std::overflow_error(
"rational power/root input exceeds the MPFR exponent range");
615 if (decreasing) mpfr_swap(lower.value, upper.value);
616 operation(lower.value, lower.value, MPFR_RNDD);
617 operation(upper.value, upper.value, MPFR_RNDU);
618 auto lo = mpreal_access::finite_result(
p, [&](mpfr_ptr out) { mpfr_set(out, lower.value, MPFR_RNDN); });
619 auto hi = mpreal_access::finite_result(
p, [&](mpfr_ptr out) { mpfr_set(out, upper.value, MPFR_RNDN); });
620 if (lo == hi)
return lo;
621 if (bits > MPFR_PREC_MAX / 2)
throw std::overflow_error(
"rational power/root needs unsupported working precision");
625inline mpreal integer_power_value(mpreal
const& x, std::int64_t exponent, Precision
p)
628 if (
p.is_exact())
return mpreal(
uni20::pow(x.exact_value(), exact_rational(exponent)));
631 auto n = exact_rational(exponent);
632 return mpreal_access::finite_result(
633 p, [&](mpfr_ptr out) { mpfr_pow_z(out, x.native_handle(), mpq_numref(n.native_handle()), MPFR_RNDN); });
635 if (exponent == 0)
return mpreal(1,
p);
636 if (x == 0)
return exponent < 0 ? mpreal(
"inf",
p) : mpreal(0,
p);
637 auto q = x.exact_value();
638 if (exponent < 0) q = exact_rational{1} / q;
639 bool negative = q < 0 && exponent % 2 != 0;
641 auto magnitude = exponent < 0 ? std::uint64_t(0) - std::uint64_t(exponent) :
std::uint64_t(exponent);
642 auto n = exact_rational(magnitude);
643 auto operation = [&](mpfr_ptr
out, mpfr_srcptr in, mpfr_rnd_t rounding) {
644 mpfr_pow_z(out, in, mpq_numref(n.native_handle()), rounding);
646 mpreal result(uninitialized);
647 if (mpz_popcount(mpq_denref(q.native_handle())) == 1)
651 auto bits = std::max<mpfr_prec_t>(MPFR_PREC_MIN, mpz_sizeinbase(mpq_numref(q.native_handle()), 2));
652 auto input = mpreal(q, Precision::bits(bits));
653 if (!
isfinite(input) || input == 0)
throw std::overflow_error(
"power input exceeds the MPFR exponent range");
654 result = mpreal_access::finite_result(
p, [&](mpfr_ptr out) { operation(out, input.native_handle(), MPFR_RNDN); });
657 result = rational_monotone(q,
p,
false, operation);
658 return negative ? -result : result;
660inline mpreal integer_root_value(mpreal
const& x, std::int64_t degree, Precision
p)
665 if (
p.is_exact())
throw std::domain_error(
"exact root: zeroth root");
666 return mpreal(
"nan",
p);
668 static_assert(
sizeof(long) >=
sizeof(std::int64_t));
670 return mpreal_access::finite_result(
671 p, [&](mpfr_ptr out) { mpfr_rootn_si(out, x.native_handle(),
static_cast<long>(degree), MPFR_RNDN); });
673 if (
auto root =
rational_root(x.exact_value(),
static_cast<unsigned long>(magnitude)))
677 if (*root == 0 && !
p.is_exact())
return mpreal(
"inf",
p);
678 *root = exact_rational{1} / *root;
680 return mpreal(*root,
p);
682 if (
p.is_exact())
throw std::logic_error(
"rootn requires finite working precision for an irrational result");
683 auto q = x.exact_value();
684 bool negative = q < 0;
685 if (negative && degree % 2 == 0)
return mpreal(
"nan",
p);
686 if (negative) q = -q;
687 auto result = rational_monotone(q,
p, degree < 0, [&](mpfr_ptr out, mpfr_srcptr in, mpfr_rnd_t rounding) {
688 mpfr_rootn_si(out, in,
static_cast<long>(degree), rounding);
690 return negative ? -result : result;
695template <detail::MathInteger I>
inline mpreal pown(
mpreal const& x, I exponent)
697 return detail::integer_power_value(x, detail::math_integer(exponent), x.
precision());
703 return detail::integer_power_value(x, detail::math_integer(exponent),
p);
708template <detail::MathInteger I>
inline mpreal rootn(
mpreal const& x, I degree)
710 return detail::integer_root_value(x, detail::math_integer(
degree), x.
precision());
716 return detail::integer_root_value(x, detail::math_integer(
degree),
p);
721inline mpreal compound_value(mpreal
const& x, std::int64_t n, Precision
p)
728 if (
p.is_exact())
throw std::domain_error(
"compound requires x >= -1");
729 return mpreal(
"nan",
p);
731 return integer_power_value(mpreal(x.exact_value() + exact_rational{1}), n,
p);
733 static_assert(
sizeof(long) >=
sizeof(std::int64_t));
734 return mpreal_access::finite_result(
735 p, [&](mpfr_ptr out) { mpfr_compound_si(out, x.native_handle(),
static_cast<long>(n), MPFR_RNDN); });
741template <detail::MathInteger I>
inline mpreal compound(
mpreal const& x, I n)
743 return detail::compound_value(x, detail::math_integer(n), x.
precision());
749 return detail::compound_value(x, detail::math_integer(n),
p);
Exact arithmetic or an explicit binary working precision.
Definition core/precision.hpp:13
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
bool is_exact() const noexcept
Whether the active payload is an exact rational.
Definition mpreal.hpp:176
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
constexpr bool isfinite(I const &x) noexcept
Returns whether an integer scalar is finite.
Definition math.hpp:121
DiagnosticMagnitude< R > magnitude(R const &value)
Definition gmres_diagnostics.hpp:98
constexpr detail::scalar_math::isfinite_fn isfinite
Whether a real scalar is finite.
Definition math.hpp:519
constexpr detail::scalar_math::cos_fn cos
Cosine with scalar-specific precision handling.
Definition math.hpp:473
constexpr detail::scalar_math::signbit_fn signbit
Inspect the sign, including approximate negative zero.
Definition math.hpp:525
constexpr detail::scalar_math::sin_fn sin
Sine with scalar-specific precision handling.
Definition math.hpp:471
constexpr detail::scalar_math::abs_fn abs
Absolute value or complex magnitude, preserving the selected scalar implementation.
Definition math.hpp:459
constexpr detail::scalar_math::isnan_fn isnan
Whether a real scalar is NaN.
Definition math.hpp:521
constexpr detail::scalar_math::remainder_fn remainder
Remainder using the nearest-even integer quotient.
Definition math.hpp:565
constexpr detail::scalar_math::isinf_fn isinf
Whether a real scalar is infinite.
Definition math.hpp:523
Definition data_table.cpp:8
Definition async/async.hpp:26
mpreal round_even(mpreal const &x)
Round to nearest integer, with ties to even; exact inputs produce exact integers.
Definition mpreal_functions.hpp:111
auto degree(QNum const &q) -> int
Return the integral degree of a quantum number.
Definition qnum.hpp:270
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
std::optional< exact_rational > rational_root(exact_rational const &x, unsigned long degree)
Return a rational nth root when it exists, without choosing a precision.
Definition exact_rational.hpp:296
bool signbit(mpreal const &x)
Definition mpreal.hpp:642
mpreal round(mpreal const &x)
Round to nearest integer, with ties away from zero; exact inputs produce exact integers.
Definition mpreal_functions.hpp:98
mpreal trunc(mpreal const &x)
Round toward zero; exact inputs produce exact integers.
Definition mpreal_functions.hpp:85
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 ceil(mpreal const &x)
Round toward positive infinity; exact inputs produce exact integers.
Definition mpreal_functions.hpp:72
mpreal remainder(mpreal const &a, mpreal const &b)
Nearest-even-quotient remainder; exact operands retain exact rational results.
Definition mpreal_functions.hpp:534
mpreal floor(mpreal const &x)
Round toward negative infinity; exact inputs produce exact integers.
Definition mpreal_functions.hpp:59
A binary significand and exponent: value = fraction * 2^exponent.
Definition math_results.hpp:8
Signed fractional and integral parts of a real value.
Definition math_results.hpp:15
Nearest-even remainder and the signed low three bits of its quotient.
Definition math_results.hpp:22
Sine and cosine evaluated at one input and precision.
Definition math_results.hpp:29
Hyperbolic sine and cosine evaluated at one input and precision.
Definition math_results.hpp:36