13using scaled_exponent = __int128_t;
17 exact_rational coefficient;
18 scaled_exponent exponent = 0;
21inline scaled_rational
operator*(scaled_rational
const& a, scaled_rational
const& b)
23 return {a.coefficient * b.coefficient, a.exponent + b.exponent};
25inline scaled_rational
operator-(scaled_rational
const& a) {
return {-a.coefficient, a.exponent}; }
31template <std::
size_t N>
32int scaled_sum_sign(std::array<mpz_srcptr, N>
const& coefficients, std::array<scaled_exponent, N>
const& exponents)
34 static_assert(N <= 4);
35 std::array<std::size_t, N> order{};
36 std::size_t
count = 0;
37 for (std::size_t i = 0; i < N; ++i)
38 if (mpz_sgn(coefficients[i]) != 0) order[count++] = i;
39 if (count == 0)
return 0;
40 std::sort(order.begin(), order.begin() + count, [&](
auto a,
auto b) { return exponents[a] > exponents[b]; });
41 mp_integer accumulator;
42 mpz_set(accumulator.value, coefficients[order[0]]);
43 auto exponent = exponents[order[0]];
44 for (std::size_t j = 1; j <
count; ++j)
47 if (mpz_sgn(accumulator.value) == 0)
48 mpz_set(accumulator.value, coefficients[next]);
51 auto top = exponents[next] + mpz_sizeinbase(coefficients[next], 2);
52 for (std::size_t k = j + 1; k <
count; ++k)
53 top = std::max(top, exponents[order[k]] + mpz_sizeinbase(coefficients[order[k]], 2));
54 auto lower_bound = exponent + mpz_sizeinbase(accumulator.value, 2) - 1;
55 if (lower_bound >= top + 2)
return mpz_sgn(accumulator.value);
56 mpz_mul_2exp(accumulator.value, accumulator.value,
static_cast<mp_bitcnt_t
>(exponent - exponents[next]));
57 mpz_add(accumulator.value, accumulator.value, coefficients[next]);
59 exponent = exponents[next];
61 return mpz_sgn(accumulator.value);
68class scaled_rational_ratio {
70 explicit scaled_rational_ratio(std::array<scaled_rational, 4>
const& terms)
72 mp_integer denominator, factor;
73 mpz_set_ui(denominator.value, 1);
74 for (
auto const& term : terms)
75 mpz_lcm(denominator.
value, denominator.
value, mpq_denref(term.coefficient.native_handle()));
76 for (std::size_t i = 0; i < 4; ++i)
78 auto q = terms[i].coefficient.native_handle();
79 mpz_divexact(factor.value, denominator.value, mpq_denref(q));
80 mpz_mul(coefficients_[i].
value, mpq_numref(q), factor.value);
81 exponents_[i] = terms[i].exponent;
84 scaled_sum_sign<2>({coefficients_[0].value, coefficients_[1].value}, {exponents_[0], exponents_[1]});
85 int denominator_sign =
86 scaled_sum_sign<2>({coefficients_[2].value, coefficients_[3].value}, {exponents_[2], exponents_[3]});
87 if (denominator_sign == 0)
throw std::domain_error(
"scaled rational: zero denominator");
88 sign_ = numerator_sign * denominator_sign;
89 for (std::size_t i = 0; i < 4; ++i)
90 if ((i < 2 ? numerator_sign : denominator_sign) < 0) mpz_neg(coefficients_[i].
value, coefficients_[i].
value);
93 void round_to(mpfr_ptr out)
const
97 mpfr_set_zero(out, 1);
100 mp_integer mantissa, midpoint;
101 mpz_set_ui(mantissa.value, 1);
102 auto const emin = mpfr_get_emin(), emax = mpfr_get_emax();
103 auto const precision = mpfr_get_prec(out);
104 if (this->compare(mantissa.value, emax) >= 0)
106 mpfr_set_ui_2exp(out, 1, emax, MPFR_RNDN);
107 if (sign_ < 0) mpfr_neg(out, out, MPFR_RNDN);
110 if (this->compare(mantissa.value, scaled_exponent(emin) - 1) < 0)
113 if (this->compare(mantissa.value, scaled_exponent(emin) - 2) <= 0)
114 mpfr_set_zero(out, sign_);
116 mpfr_set_si_2exp(out, sign_, emin - 1, MPFR_RNDN);
118 mpz_mul_2exp(midpoint.value, mantissa.value, precision + 1);
119 mpz_sub_ui(midpoint.value, midpoint.value, 1);
120 if (this->compare(midpoint.value, scaled_exponent(emin) - precision - 2) < 0) mpfr_set_underflow();
126 scaled_exponent lo = scaled_exponent(emin) - 1, hi = emax;
129 auto mid = lo + (hi - lo) / 2;
130 if (this->compare(mantissa.value, mid) >= 0)
135 auto exponent = lo - precision + 1;
136 mpz_mul_2exp(mantissa.value, mantissa.value, precision - 1);
137 for (mpfr_prec_t bit = precision - 1; bit-- > 0;)
139 mpz_setbit(mantissa.value, bit);
140 if (this->compare(mantissa.value, exponent) < 0) mpz_clrbit(mantissa.value, bit);
142 bool const inexact = this->compare(mantissa.value, exponent) != 0;
145 mpz_mul_2exp(midpoint.value, mantissa.value, 1);
146 mpz_add_ui(midpoint.value, midpoint.value, 1);
147 int comparison = this->compare(midpoint.value, exponent - 1);
148 if (comparison > 0 || (comparison == 0 && mpz_odd_p(mantissa.value)))
149 mpz_add_ui(mantissa.value, mantissa.value, 1);
151 if (sign_ < 0) mpz_neg(mantissa.value, mantissa.value);
152 mpfr_set_z_2exp(out, mantissa.value,
static_cast<mpfr_exp_t
>(exponent), MPFR_RNDN);
153 if (inexact) mpfr_set_inexflag();
158 int compare(mpz_srcptr candidate, scaled_exponent exponent)
const
161 mpz_mul(
c.value, coefficients_[2].value, candidate);
162 mpz_mul(d.value, coefficients_[3].value, candidate);
163 mpz_neg(
c.value,
c.value);
164 mpz_neg(d.value, d.value);
165 return scaled_sum_sign<4>({coefficients_[0].value, coefficients_[1].value,
c.value, d.value},
166 {exponents_[0], exponents_[1], exponents_[2] + exponent, exponents_[3] + exponent});
168 std::array<mp_integer, 4> coefficients_;
169 std::array<scaled_exponent, 4> exponents_{};
locale_t value
Definition data_table.cpp:49
auto operator-(Async< T > const &x)
Unary negation overload for Async values.
Definition async_ops.hpp:477
Var< T > operator*(T x, Var< T > y)
Computes x * y with reverse-mode gradient propagation.
Definition var_toys.hpp:176