LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
rational_parsing.cpp
浏览该文件的文档.
1#include "rational.hpp"
2#include <cctype>
3#include <stdexcept>
4
5namespace LMCAS {
6namespace {
7
9public:
10 std::string integer_digits;
11 std::string fractional_digits;
12 std::string repeating_digits;
13 bool negative = false;
14 std::int64_t exponent = 0;
15
16 RationalLiteral(const std::string& text, std::size_t max_bytes,
17 std::size_t max_scale) : text_(text) {
18 if (text.empty()) throw std::invalid_argument("Rational literal is empty");
19 if (text.size() > max_bytes) {
20 throw std::length_error("Rational literal exceeds safety limit");
21 }
23 if (pos_ == text.size()) {
24 throw std::invalid_argument("Rational literal has no digits");
25 }
27 const bool has_decimal_point = pos_ < text.size() && text[pos_] == '.';
28 if (has_decimal_point) {
29 ++pos_;
31 }
32 read_repeating_digits(has_decimal_point);
33 if (integer_digits.empty() && fractional_digits.empty()) {
34 throw std::invalid_argument("Rational literal has no digits");
35 }
36 exponent = read_exponent(max_scale);
37 if (pos_ != text.size()) {
38 throw std::invalid_argument("Invalid character in Rational literal");
39 }
40 if (integer_digits.empty()) integer_digits = "0";
41 }
42
43private:
44 const std::string& text_;
45 std::size_t pos_ = 0;
46
47 bool read_sign() {
48 if (pos_ == text_.size() || (text_[pos_] != '+' && text_[pos_] != '-')) {
49 return false;
50 }
51 return text_[pos_++] == '-';
52 }
53
54 void read_digits(std::string& output) {
55 while (pos_ < text_.size() &&
56 std::isdigit(static_cast<unsigned char>(text_[pos_]))) {
57 output.push_back(text_[pos_++]);
58 }
59 }
60
61 void read_repeating_digits(bool has_decimal_point) {
62 if (pos_ == text_.size() || text_[pos_] != '(') return;
63 if (!has_decimal_point) {
64 throw std::invalid_argument("Repeating decimal section requires a decimal point");
65 }
66 ++pos_;
68 if (repeating_digits.empty() || pos_ >= text_.size() || text_[pos_] != ')') {
69 throw std::invalid_argument("Invalid repeating decimal section");
70 }
71 ++pos_;
72 }
73
74 std::int64_t read_exponent(std::size_t max_scale) {
75 if (pos_ == text_.size() || (text_[pos_] != 'e' && text_[pos_] != 'E')) {
76 return 0;
77 }
78 ++pos_;
79 const bool exponent_negative = read_sign();
80 if (pos_ == text_.size() ||
81 !std::isdigit(static_cast<unsigned char>(text_[pos_]))) {
82 throw std::invalid_argument("Rational exponent has no digits");
83 }
84 const std::int64_t value = read_exponent_magnitude(max_scale);
85 return exponent_negative ? -value : value;
86 }
87
88 std::int64_t read_exponent_magnitude(std::size_t max_scale) {
89 std::int64_t value = 0;
90 while (pos_ < text_.size() &&
91 std::isdigit(static_cast<unsigned char>(text_[pos_]))) {
92 const int digit = text_[pos_++] - '0';
93 if (value > static_cast<std::int64_t>(max_scale / 10) ||
94 value * 10 + digit > static_cast<std::int64_t>(max_scale)) {
95 throw std::length_error("Rational exponent exceeds safety limit");
96 }
97 value = value * 10 + digit;
98 }
99 return value;
100 }
101};
102
103}
104
105Rational::Rational(const std::string& num) : Rational() {
106 const RationalLiteral literal(num, max_literal_bytes, max_decimal_scale);
107 const std::string non_repeating = literal.integer_digits + literal.fractional_digits;
108 numerator = BigInt(non_repeating);
109 denominator = pow10(literal.fractional_digits.size());
110
111 if (!literal.repeating_digits.empty()) {
112 const BigInt repeat_scale = pow10(literal.repeating_digits.size());
113 const BigInt repeat_factor = repeat_scale - BigInt(1);
114 numerator = numerator * repeat_factor + BigInt(literal.repeating_digits);
115 denominator *= repeat_factor;
116 }
117
118 if (literal.exponent > 0) {
119 numerator *= pow10(static_cast<std::size_t>(literal.exponent));
120 } else if (literal.exponent < 0) {
121 denominator *= pow10(static_cast<std::size_t>(-literal.exponent));
122 }
123 if (literal.negative) numerator = -numerator;
124 simplify();
125}
126
127}
RationalLiteral(const std::string &text, std::size_t max_bytes, std::size_t max_scale)
std::shared_ptr< SymbolicExpr > num(int value)
ExprResult simplify(const ExprPtr &expression, ComputationContext &context)
const std::string const ExprPtr & value
const ExprPtr & denominator
精确有理数 Rational,基于 BigInt 分子/分母表示,自动约分。