12 const bool negative = scaled < BigInt(0);
14 scaled = scaled * BigInt(-1);
16 std::string text = scaled.to_string();
17 if (text.size() <= digits) {
18 text.insert(0, digits - text.size() + 1,
'0');
20 text.insert(text.size() - digits, 1,
'.');
21 while (text.back() ==
'0') {
24 if (text.back() ==
'.') {
28 text.insert(text.begin(),
'-');
35BigInt Rational::pow10(std::size_t
exponent) {
37 throw std::length_error(
"Rational decimal scale exceeds safety limit");
40 return BigInt(10).power(
static_cast<unsigned long>(
exponent));
43std::size_t Rational::decimal_scale(std::int64_t
exponent) {
44 constexpr auto limit =
static_cast<std::int64_t
>(max_decimal_scale);
46 throw std::length_error(
"Rational decimal scale exceeds safety limit");
52 if (!std::isfinite(
value)) {
53 throw std::invalid_argument(
"Cannot construct Rational from NaN or infinity");
60 const auto mantissa =
static_cast<std::int64_t
>(std::ldexp(fraction, 53));
61 const int binary_exponent =
exponent - 53;
65 if (binary_exponent >= 0) {
68 den <<= static_cast<mp_size_t>(-binary_exponent);
73std::size_t Rational::hash()
const {
74 std::size_t seed = numerator.hash();
76 seed ^= d_hash + 0x9e3779b9 + (seed << 6) + (seed >> 2);
80std::string Rational::to_string()
const {
82 return numerator.to_string();
84 return numerator.to_string() +
"/" +
denominator.to_string();
87std::string Rational::to_float_string() {
92 if ((numerator < zero) ^ (
denominator < zero)) re +=
'-';
94 re += (
num / den).to_string();
98 std::map<BigInt, std::size_t> num_index;
100 while (
num != zero && num_index.find(
num) == num_index.end()) {
101 num_index[
num] = re.size();
109 if (num_index.find(
num) != num_index.end()) {
110 re.insert(num_index[
num], 1,
'(');
117std::string Rational::to_float_string(std::int64_t n)
const{
124 const std::size_t digits = decimal_scale(n);
125 const BigInt pow10n = pow10(digits);
129 std::string re = (numerator / (
denominator * pow10n)).to_string();
130 if (re.size() == 1 && re[0] ==
'0') {
133 re.append(digits,
'0');
137void Rational::floor(
const std::int64_t& n) {
138 floor_without_sim(n);
142void Rational::floor_without_sim(
const std::int64_t& n) {
148 const BigInt pow10n = pow10(decimal_scale(n));
161BigInt Rational::to_bigint()
const {
163 throw std::runtime_error(
"Cannot convert non-integer fraction to BigInt");
168lmmc_real_t Rational::to_double()
const {
170 const std::string num_text = numerator.abs().to_string();
171 const std::string den_text =
denominator.to_string();
172 const std::size_t num_digits = std::min<std::size_t>(18, num_text.size());
173 const std::size_t den_digits = std::min<std::size_t>(18, den_text.size());
174 const long double num_head = std::stold(num_text.substr(0, num_digits));
175 const long double den_head = std::stold(den_text.substr(0, den_digits));
176 const std::size_t num_tail = num_text.size() - num_digits;
177 const std::size_t den_tail = den_text.size() - den_digits;
178 const bool negative_shift = num_tail < den_tail;
179 const std::size_t shift = negative_shift ? den_tail - num_tail : num_tail - den_tail;
180 if (shift >
static_cast<std::uint64_t
>(std::numeric_limits<std::int64_t>::max())) {
181 if (negative_shift) {
182 throw std::underflow_error(
"Rational underflow during double conversion");
184 throw std::overflow_error(
"Rational cannot be represented as a finite double");
186 const std::int64_t decimal_shift = negative_shift ?
187 -
static_cast<std::int64_t
>(shift) : static_cast<std::int64_t>(shift);
188 long double value = (num_head / den_head) *
189 std::pow(10.0L,
static_cast<long double>(decimal_shift));
191 const lmmc_real_t converted =
static_cast<lmmc_real_t
>(
value);
192 if (!std::isfinite(converted)) {
198 const BigInt max_finite_integer =
199 (BigInt(1) << 1024) - (BigInt(1) << 971);
200 const BigInt finite_rounding_limit =
201 max_finite_integer + (BigInt(1) << 970);
202 if (numerator.abs() <
204 return std::copysign(
205 std::numeric_limits<lmmc_real_t>::max(),
206 numerator.is_negative() ? -1.0 : 1.0);
208 throw std::overflow_error(
209 "Rational cannot be represented as a finite double");
211 if (converted == 0.0) {
212 throw std::underflow_error(
"Rational underflow during double conversion");
bool is_zero(const SymbolicExpr &expression)
std::string format_scaled_decimal(BigInt scaled, std::size_t digits)
std::shared_ptr< SymbolicExpr > num(int value)
@ Rational
Rational numbers
ExprResult simplify(const ExprPtr &expression, ComputationContext &context)
const std::string const ExprPtr & value
const ExprPtr & denominator
精确有理数 Rational,基于 BigInt 分子/分母表示,自动约分。