LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
bigint.cpp
浏览该文件的文档.
1#include "bigint.hpp"
3
4#include <algorithm>
5#include <cmath>
6#include <cstring>
7#include <iomanip>
8#include <limits>
9#include <stdexcept>
10
11namespace LMCAS {
12
13
14void BigInt::realloc_to(mp_size_t new_alloc) {
15 if (new_alloc <= capacity_) return;
16 const std::size_t requested = static_cast<std::size_t>(new_alloc);
17 if (requested > std::numeric_limits<std::size_t>::max() - 3) {
18 throw std::length_error("BigInt allocation size overflow");
19 }
20 const std::size_t rounded = (requested + 3) & ~std::size_t(3);
21 if (rounded > std::numeric_limits<std::size_t>::max() / sizeof(mp_limb_t) ||
22 rounded > static_cast<std::size_t>(std::numeric_limits<mp_size_t>::max())) {
23 throw std::length_error("BigInt allocation byte size overflow");
24 }
25
26 mp_ptr new_data =
27 static_cast<mp_ptr>(::operator new[](rounded * sizeof(mp_limb_t)));
28
29 if (size_ > 0 && data_) {
30 std::memcpy(new_data, data_, size_ * sizeof(mp_limb_t));
31 }
32 if (data_) ::operator delete[](data_);
33 data_ = new_data;
34 capacity_ = static_cast<mp_size_t>(rounded);
35 }
36
37void BigInt::normalize() {
38 if (size_ > 0 && !data_) {
39 throw std::logic_error("BigInt invariant violated: nonzero size without storage");
40 }
41 while (size_ > 0 && data_[size_ - 1] == 0) {
42 size_--;
43 }
44 if (size_ == 0) {
45 sign_ = ZERO;
46 } else if (sign_ == ZERO) {
47 sign_ = POSITIVE;
48 }
49 }
50
51void BigInt::zero() {
52 size_ = 0;
53 sign_ = ZERO;
54 }
55
56BigInt::BigInt() = default;
57
58BigInt::~BigInt() {
59 if (data_) ::operator delete[](data_);
60 }
61
62BigInt::BigInt(const BigInt& other) {
63 if (other.size_ > 0) {
64 realloc_to(other.size_);
65 std::memcpy(data_, other.data_, other.size_ * sizeof(mp_limb_t));
66 size_ = other.size_;
67 sign_ = other.sign_;
68 } else {
69 zero();
70 }
71 }
72
73BigInt::BigInt(BigInt&& other) noexcept
74 : data_(other.data_), size_(other.size_), capacity_(other.capacity_), sign_(other.sign_) {
75 other.data_ = nullptr;
76 other.size_ = 0;
77 other.capacity_ = 0;
78 other.sign_ = ZERO;
79 }
80
81BigInt& BigInt::operator=(const BigInt& other) {
82 if (this != &other) {
83 if (other.size_ > capacity_) {
84 realloc_to(other.size_);
85 }
86 if (other.size_ > 0)
87 std::memcpy(data_, other.data_, other.size_ * sizeof(mp_limb_t));
88 size_ = other.size_;
89 sign_ = other.sign_;
90 }
91 return *this;
92 }
93
94BigInt& BigInt::operator=(BigInt&& other) noexcept {
95 if (this != &other) {
96 if (data_) ::operator delete[](data_);
97 data_ = other.data_;
98 size_ = other.size_;
99 capacity_ = other.capacity_;
100 sign_ = other.sign_;
101
102 other.data_ = nullptr;
103 other.capacity_ = 0;
104 other.zero();
105 }
106 return *this;
107 }
108
109void BigInt::import_unsigned(std::uint64_t magnitude) {
110 zero();
111 if (magnitude == 0) {
112 return;
113 }
114 constexpr auto limb_bits = std::numeric_limits<mp_limb_t>::digits;
115 constexpr auto value_bits = std::numeric_limits<std::uint64_t>::digits;
116 realloc_to((value_bits + limb_bits - 1) / limb_bits);
117 do {
118 data_[size_++] = static_cast<mp_limb_t>(magnitude);
119 if constexpr (limb_bits < value_bits) {
120 magnitude >>= limb_bits % value_bits;
121 } else {
122 magnitude = 0;
123 }
124 } while (magnitude != 0);
125 sign_ = POSITIVE;
126}
127
128BigInt::BigInt(std::int64_t value) {
129 const auto bits = static_cast<std::uint64_t>(value);
130 import_unsigned(value < 0 ? std::uint64_t{0} - bits : bits);
131 if (value < 0) {
132 sign_ = NEGATIVE;
133 }
134}
135
136BigInt::BigInt(std::uint64_t value) {
137 import_unsigned(value);
138}
139
140BigInt::BigInt(int value) : BigInt(static_cast<std::int64_t>(value)) {}
141
142BigInt::BigInt(unsigned int value) : BigInt(static_cast<std::uint64_t>(value)) {}
143
144BigInt::BigInt(const std::string& str) {
145 if (str.empty()) {
146 throw std::invalid_argument("BigInt: decimal string must contain digits");
147 }
148 size_t start = 0;
149 int sign = POSITIVE;
150 if (str[0] == '-') {
151 sign = NEGATIVE;
152 start = 1;
153 } else if (str[0] == '+') {
154 start = 1;
155 }
156
157 if (start == str.length()) {
158 throw std::invalid_argument("BigInt: sign must be followed by digits");
159 }
160
161 size_t len = str.length() - start;
162
163 std::vector<mp_byte_t> digit_buf(len);
164 for (size_t i = 0; i < len; ++i) {
165 char c = str[start + i];
166 if (c < '0' || c > '9') {
167 throw std::invalid_argument(
168 "BigInt: invalid character '" + std::string(1, c) +
169 "' at position " + std::to_string(start + i) +
170 " in input \"" + str + "\"");
171 }
172 uint8_t d = static_cast<uint8_t>(c - '0');
173
174 digit_buf[len - 1 - i] = d;
175 }
176
177 mp_size_t needed = len / 19 + 2;
178 realloc_to(needed);
180
181 size_ = lmmp_from_str_(data_, digit_buf.data(), len, 10);
182
183 if (size_ == 0) {
184 zero();
185 } else {
186 sign_ = sign;
187 }
188 normalize();
189 }
190
191std::string BigInt::to_string() const {
193 if (size_ == 0) return "0";
194
195 size_t len_needed = size_ * 20 + 5;
196 std::vector<mp_byte_t> buf(len_needed);
197
198 mp_size_t str_len = lmmp_to_str_((mp_byte_t*)buf.data(), data_, size_, 10);
199
200 if (str_len == 0) return "0";
201
202 std::string res;
203 res.reserve(str_len + 2);
204 if (sign_ == NEGATIVE) res += '-';
205
206 for(mp_size_t i = str_len; i > 0; --i) {
207 res += (char)(buf[i - 1] + '0');
208 }
209 return res;
210 }
211
212
213std::size_t BigInt::bit_length() const noexcept {
214 if (size_ == 0) {
215 return 0;
216 }
217 std::size_t top_bits = 0;
218 for (mp_limb_t top = data_[size_ - 1]; top != 0; top >>= 1) {
219 ++top_bits;
220 }
221 constexpr auto limb_bits = std::numeric_limits<mp_limb_t>::digits;
222 return (static_cast<std::size_t>(size_) - 1) * limb_bits + top_bits;
223}
224
225std::optional<std::uint64_t> BigInt::magnitude_uint64() const noexcept {
226 constexpr auto value_bits = std::numeric_limits<std::uint64_t>::digits;
227 constexpr auto limb_bits = std::numeric_limits<mp_limb_t>::digits;
228 if (bit_length() > value_bits) {
229 return std::nullopt;
230 }
231 std::uint64_t magnitude = 0;
232 for (mp_size_t i = size_; i > 0; --i) {
233 if constexpr (limb_bits < value_bits) {
234 magnitude <<= limb_bits % value_bits;
235 }
236 magnitude |= static_cast<std::uint64_t>(data_[i - 1]);
237 }
238 return magnitude;
239}
240
241std::optional<std::uint64_t> BigInt::try_to_uint64() const noexcept {
242 if (sign_ == NEGATIVE) {
243 return std::nullopt;
244 }
245 return magnitude_uint64();
246}
247
248std::optional<std::int64_t> BigInt::try_to_int64() const noexcept {
249 const auto magnitude = magnitude_uint64();
250 if (!magnitude) {
251 return std::nullopt;
252 }
253 constexpr auto maximum =
254 static_cast<std::uint64_t>(std::numeric_limits<std::int64_t>::max());
255 if (sign_ == NEGATIVE) {
256 if (*magnitude > maximum + std::uint64_t{1}) {
257 return std::nullopt;
258 }
259 if (*magnitude == maximum + std::uint64_t{1}) {
260 return std::numeric_limits<std::int64_t>::min();
261 }
262 return -static_cast<std::int64_t>(*magnitude);
263 }
264 if (*magnitude > maximum) {
265 return std::nullopt;
266 }
267 return static_cast<std::int64_t>(*magnitude);
268}
269
270int BigInt::to_int() const {
271 const auto value = try_to_int64();
272 if (!value) {
273 return sign_ == NEGATIVE ? std::numeric_limits<int>::min()
274 : std::numeric_limits<int>::max();
275 }
276 if (*value < std::numeric_limits<int>::min()) {
277 return std::numeric_limits<int>::min();
278 }
279 if (*value > std::numeric_limits<int>::max()) {
280 return std::numeric_limits<int>::max();
281 }
282 return static_cast<int>(*value);
283}
284
285lmmc_real_t BigInt::to_double() const {
286 if (size_ == 0) return 0.0;
287 lmmc_real_t res = 0.0;
288 const lmmc_real_t base_mul =
289 std::ldexp(lmmc_real_t{1}, std::numeric_limits<mp_limb_t>::digits);
290
291 for (mp_size_t i = size_; i > 0; --i) {
292 LMMC_REAL_MUL(&res, &res, &base_mul);
293 lmmc_real_t val = (lmmc_real_t)data_[i-1];
294 LMMC_REAL_ADD(&res, &res, &val);
295 }
296 if (sign_ == NEGATIVE) {
297 lmmc_real_t zero = 0.0;
298 LMMC_REAL_SUB(&res, &zero, &res);
299 }
300 return res;
301 }
302
303int BigInt::cmp_abs(const BigInt& a, const BigInt& b) {
304 if (a.size_ != b.size_) {
305 return a.size_ > b.size_ ? 1 : -1;
306 }
307 if (a.size_ == 0) {
308 return 0;
309 }
310 for (mp_size_t i = a.size_; i > 0; --i) {
311 if (a.data_[i - 1] != b.data_[i - 1]) {
312 return a.data_[i - 1] > b.data_[i - 1] ? 1 : -1;
313 }
314 }
315 return 0;
316 }
317
318bool BigInt::operator==(const BigInt& other) const {
319 return sign_ == other.sign_ && cmp_abs(*this, other) == 0;
320 }
321
322bool BigInt::operator!=(const BigInt& other) const { return !(*this == other); }
323
324bool BigInt::operator<(const BigInt& other) const {
325 if (sign_ != other.sign_) return sign_ < other.sign_;
326 if (sign_ == ZERO) return false;
327 int cmp = cmp_abs(*this, other);
328 return sign_ == POSITIVE ? cmp < 0 : cmp > 0;
329 }
330
331bool BigInt::operator>(const BigInt& other) const { return other < *this; }
332
333bool BigInt::operator<=(const BigInt& other) const { return !(*this > other); }
334
335bool BigInt::operator>=(const BigInt& other) const { return !(*this < other); }
336
337bool BigInt::operator!() const { return size_ == 0; }
338
339BigInt::operator bool() const { return size_ != 0; }
340
341bool BigInt::is_zero() const { return size_ == 0; }
342
343std::vector<uint64_t> BigInt::get_digits() const {
344 std::vector<uint64_t> d;
345 d.reserve(size_);
346 for(mp_size_t i = 0; i < size_; ++i) {
347 d.push_back(data_[i]);
348 }
349 return d;
350 }
351
352std::size_t BigInt::hash() const {
353 std::size_t seed = 0;
354 for (mp_size_t i = 0; i < size_; ++i) {
355 seed ^= std::hash<uint64_t>{}(data_[i]) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
356 }
357 if (sign_ == NEGATIVE) { seed ^= std::hash<int>{}(-1) + 0x9e3779b9 + (seed << 6) + (seed >> 2); }
358 return seed;
359 }
360
361BigInt BigInt::abs() const {
362 BigInt ret = *this;
363 if (ret.size_ > 0) {
364 ret.sign_ = POSITIVE;
365 }
366 return ret;
367 }
368
369bool BigInt::is_negative() const { return sign_ == NEGATIVE; }
370
371BigInt BigInt::negate() const {
372 BigInt ret = *this;
373 if (ret.size_ > 0) {
374 ret.sign_ = (ret.sign_ == POSITIVE) ? NEGATIVE : POSITIVE;
375 }
376 return ret;
377 }
378
379BigInt BigInt::operator-() const { return negate(); }
380
381} // namespace LMCAS
任意精度整数 BigInt,底层调用 LMMP 实现高性能大数运算。
ExpressionResult normalize(const Node &value, ComputationContext &context)
void ensure_lmmc_lifecycle() noexcept
const VectorField const VectorField & c
const MultiPoly & b
__attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string const std::shared_ptr< SymbolicExpr > & a
const std::string const ExprPtr & value