From 202767a608fa49134d348d8ab4e5391aeadf0bf0d2a42fd8098b8385669e9a21 Mon Sep 17 00:00:00 2001 From: ArchZer0 Date: Sun, 16 Aug 2026 19:23:09 +0800 Subject: [PATCH] =?UTF-8?q?=E9=AB=98=E7=B2=BE=E5=BA=A6=E6=94=B9=E4=B8=BAve?= =?UTF-8?q?ctor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/bstl/big_integer.hpp | 17 +- src/big_integer.cpp | 316 +++++++++++++++++++++-------------- 2 files changed, 196 insertions(+), 137 deletions(-) diff --git a/include/bstl/big_integer.hpp b/include/bstl/big_integer.hpp index 5ea6e69..1db695a 100644 --- a/include/bstl/big_integer.hpp +++ b/include/bstl/big_integer.hpp @@ -2,6 +2,7 @@ #define BETTERSTL_BIG_INTEGER_HPP #include +#include #include namespace bstl { @@ -55,15 +56,15 @@ public: BigInteger operator/(const BigInteger& other) const; private: - std::string m_digits; // 无符号数字,从高位到低位 - int m_sign; // -1, 0, 1 + std::vector m_digits; // 无符号数字,低位在前 + int m_sign; // -1, 0, 1 - static std::string m_trimLeadingZeros(const std::string& value); - static int m_compareAbs(const std::string& a, const std::string& b); - static std::string m_addAbs(const std::string& a, const std::string& b); - static std::string m_subAbs(const std::string& a, const std::string& b); - static std::string m_mulAbs(const std::string& a, const std::string& b); - static std::string divAbs(const std::string& a, const std::string& b); + static std::vector m_trimLeadingZeros(const std::vector& value); + static int m_compareAbs(const std::vector& a, const std::vector& b); + static std::vector m_addAbs(const std::vector& a, const std::vector& b); + static std::vector m_subAbs(const std::vector& a, const std::vector& b); + static std::vector m_mulAbs(const std::vector& a, const std::vector& b); + static std::vector m_divAbs(const std::vector& a, const std::vector& b); }; // 流运算符重载 diff --git a/src/big_integer.cpp b/src/big_integer.cpp index 29576e0..b7166d6 100644 --- a/src/big_integer.cpp +++ b/src/big_integer.cpp @@ -7,52 +7,81 @@ namespace bstl { -std::string BigInteger::m_trimLeadingZeros(const std::string& value) { - size_t pos = 0; - while (pos < value.size() - 1 && value[pos] == '0') { - pos++; +namespace { +std::vector toDigits(unsigned long long value) { + std::vector digits; + while (value > 0) { + digits.push_back(static_cast(value % 10)); + value /= 10; } - return value.substr(pos); + return digits; } +} // namespace -int BigInteger::m_compareAbs(const std::string& a, const std::string& b) { - std::string ta = m_trimLeadingZeros(a); - std::string tb = m_trimLeadingZeros(b); - if (ta.size() != tb.size()) { - return ta.size() < tb.size() ? -1 : 1; - } - return ta.compare(tb) < 0 ? -1 : (ta.compare(tb) > 0 ? 1 : 0); -} - -std::string BigInteger::m_addAbs(const std::string& a, const std::string& b) { - std::string result; - int carry = 0; - int i = static_cast(a.size()) - 1; - int j = static_cast(b.size()) - 1; - while (i >= 0 || j >= 0 || carry) { - int sum = carry; - if (i >= 0) sum += a[i--] - '0'; - if (j >= 0) sum += b[j--] - '0'; - result.insert(result.begin(), static_cast('0' + sum % 10)); - carry = sum / 10; +std::vector BigInteger::m_trimLeadingZeros(const std::vector& value) { + size_t end = value.size(); + while (end > 0 && value[end - 1] == 0) { + --end; } + std::vector result(value); + result.resize(end); return result; } -std::string BigInteger::m_subAbs(const std::string& a, const std::string& b) { - std::string ta = m_trimLeadingZeros(a); - std::string tb = m_trimLeadingZeros(b); +int BigInteger::m_compareAbs(const std::vector& a, const std::vector& b) { + std::vector ta = m_trimLeadingZeros(a); + std::vector tb = m_trimLeadingZeros(b); + if (ta.size() != tb.size()) { + return ta.size() < tb.size() ? -1 : 1; + } + for (size_t i = ta.size(); i > 0; --i) { + if (ta[i - 1] != tb[i - 1]) { + return ta[i - 1] < tb[i - 1] ? -1 : 1; + } + } + return 0; +} + +std::vector BigInteger::m_addAbs(const std::vector& a, const std::vector& b) { + std::vector ta = m_trimLeadingZeros(a); + std::vector tb = m_trimLeadingZeros(b); + std::vector result; + result.reserve(std::max(ta.size(), tb.size()) + 1); + + int carry = 0; + const size_t n = std::max(ta.size(), tb.size()); + for (size_t i = 0; i < n; ++i) { + int sum = carry; + if (i < ta.size()) { + sum += ta[i]; + } + if (i < tb.size()) { + sum += tb[i]; + } + result.push_back(sum % 10); + carry = sum / 10; + } + if (carry != 0) { + result.push_back(carry); + } + return m_trimLeadingZeros(result); +} + +std::vector BigInteger::m_subAbs(const std::vector& a, const std::vector& b) { + std::vector ta = m_trimLeadingZeros(a); + std::vector tb = m_trimLeadingZeros(b); if (m_compareAbs(ta, tb) < 0) { return m_subAbs(tb, ta); } - std::string result; + + std::vector result; + result.reserve(ta.size()); + int borrow = 0; - int i = static_cast(ta.size()) - 1; - int j = static_cast(tb.size()) - 1; - while (i >= 0) { - int diff = (ta[i--] - '0') - borrow; - if (j >= 0) { - diff -= (tb[j--] - '0'); + for (size_t i = 0; i < ta.size(); ++i) { + int diff = ta[i] - borrow; + if (i < tb.size()) { + diff -= tb[i]; } if (diff < 0) { diff += 10; @@ -60,122 +89,113 @@ std::string BigInteger::m_subAbs(const std::string& a, const std::string& b) { } else { borrow = 0; } - result.insert(result.begin(), static_cast('0' + diff)); + result.push_back(diff); } return m_trimLeadingZeros(result); } -std::string BigInteger::m_mulAbs(const std::string& a, const std::string& b) { - std::string ta = m_trimLeadingZeros(a); - std::string tb = m_trimLeadingZeros(b); - if (ta == "0" || tb == "0") return "0"; +std::vector BigInteger::m_mulAbs(const std::vector& a, const std::vector& b) { + std::vector ta = m_trimLeadingZeros(a); + std::vector tb = m_trimLeadingZeros(b); + if (ta.empty() || tb.empty()) { + return {}; + } std::vector product(ta.size() + tb.size(), 0); - for (size_t i = 0; i < ta.size(); i++) { - for (size_t j = 0; j < tb.size(); j++) { - int mul = (ta[ta.size() - 1 - i] - '0') * (tb[tb.size() - 1 - j] - '0'); - product[i + j] += mul; + for (size_t i = 0; i < ta.size(); ++i) { + for (size_t j = 0; j < tb.size(); ++j) { + product[i + j] += ta[i] * tb[j]; } } int carry = 0; - for (int & i : product) { - int sum = i + carry; - i = sum % 10; + for (int& digit : product) { + const int sum = digit + carry; + digit = sum % 10; carry = sum / 10; } - std::string result; - for (int i = static_cast(product.size()) - 1; i >= 0; i--) { - result += char('0' + product[i]); - } - return m_trimLeadingZeros(result); + return m_trimLeadingZeros(product); } -std::string BigInteger::divAbs(const std::string& a, const std::string& b) { - std::string tb = m_trimLeadingZeros(b); - if (tb == "0") { +std::vector BigInteger::m_divAbs(const std::vector& a, const std::vector& b) { + std::vector tb = m_trimLeadingZeros(b); + if (tb.empty()) { throw std::invalid_argument("division by zero"); } - std::string ta = m_trimLeadingZeros(a); + + std::vector ta = m_trimLeadingZeros(a); if (m_compareAbs(ta, tb) < 0) { - return "0"; + return {}; } - std::string quotient; - std::string current; - for (char digit : ta) { - current += digit; + std::vector quotientHigh; + std::vector current; + current.reserve(ta.size()); + + for (size_t i = ta.size(); i > 0; --i) { + current.insert(current.begin(), ta[i - 1]); current = m_trimLeadingZeros(current); int count = 0; while (m_compareAbs(current, tb) >= 0) { current = m_subAbs(current, tb); - count++; + ++count; } - quotient += char('0' + count); + quotientHigh.push_back(count); } - return m_trimLeadingZeros(quotient); + + std::reverse(quotientHigh.begin(), quotientHigh.end()); + return m_trimLeadingZeros(quotientHigh); } -BigInteger::BigInteger() : m_digits("0"), m_sign(0) {} +BigInteger::BigInteger() : m_sign(0) {} -BigInteger::BigInteger(int value) : m_digits("0"), m_sign(1) { +BigInteger::BigInteger(int value) : m_sign(0) { if (value == 0) { - m_digits = "0"; - m_sign = 0; return; } + + auto v = static_cast(value); + if (v < 0) { + m_sign = -1; + v = -v; + } else { + m_sign = 1; + } + m_digits = toDigits(static_cast(v)); +} + +BigInteger::BigInteger(long long value) : m_sign(0) { + if (value == 0) { + return; + } + + unsigned long long magnitude = 0; if (value < 0) { m_sign = -1; - value = -value; - } - m_digits.clear(); - while (value > 0) { - m_digits = char('0' + value % 10) + m_digits; - value /= 10; + magnitude = static_cast(-(value + 1)) + 1ULL; + } else { + m_sign = 1; + magnitude = static_cast(value); } + m_digits = toDigits(magnitude); } -BigInteger::BigInteger(long long value) : m_digits("0"), m_sign(1) { +BigInteger::BigInteger(unsigned long long value) : m_sign(0) { if (value == 0) { - m_digits = "0"; - m_sign = 0; return; } - if (value < 0) { - m_sign = -1; - value = -value; - } - m_digits.clear(); - while (value > 0) { - m_digits = char('0' + value % 10) + m_digits; - value /= 10; - } + m_sign = 1; + m_digits = toDigits(value); } -BigInteger::BigInteger(unsigned long long value) : m_digits("0"), m_sign(1) { - if (value == 0) { - m_digits = "0"; - m_sign = 0; - return; - } - m_digits.clear(); - while (value > 0) { - m_digits = char('0' + value % 10) + m_digits; - value /= 10; - } -} - -BigInteger::BigInteger(const std::string& value) : m_digits("0"), m_sign(1) { +BigInteger::BigInteger(const std::string& value) : m_sign(0) { if (value.empty()) { - m_digits = "0"; - m_sign = 0; return; } std::string text = value; m_sign = 1; - if (text[0] == '-') { m_sign = -1; text = text.substr(1); @@ -184,7 +204,6 @@ BigInteger::BigInteger(const std::string& value) : m_digits("0"), m_sign(1) { } if (text.empty()) { - m_digits = "0"; m_sign = 0; return; } @@ -195,8 +214,13 @@ BigInteger::BigInteger(const std::string& value) : m_digits("0"), m_sign(1) { } } - m_digits = m_trimLeadingZeros(text); - if (m_digits == "0") { + m_digits.clear(); + m_digits.reserve(text.size()); + for (auto it = text.rbegin(); it != text.rend(); ++it) { + m_digits.push_back(*it - '0'); + } + m_digits = m_trimLeadingZeros(m_digits); + if (m_digits.empty()) { m_sign = 0; } } @@ -205,20 +229,33 @@ BigInteger::BigInteger(const char* value) : BigInteger(value == nullptr ? std::string("0") : std::string(value)) {} bool BigInteger::isZero() const { - return m_sign == 0 || m_digits == "0"; + return m_sign == 0; } int BigInteger::sign() const { - return isZero() ? 0 : m_sign; + return m_sign; } std::string BigInteger::toString() const { - if (isZero()) return "0"; - return (m_sign < 0 ? "-" : "") + m_digits; + if (isZero()) { + return "0"; + } + + std::string result; + result.reserve(m_digits.size() + (m_sign < 0 ? 1U : 0U)); + if (m_sign < 0) { + result.push_back('-'); + } + for (auto it = m_digits.rbegin(); it != m_digits.rend(); ++it) { + result.push_back(static_cast('0' + *it)); + } + return result; } bool BigInteger::operator==(const BigInteger& other) const { - if (isZero() && other.isZero()) return true; + if (isZero() && other.isZero()) { + return true; + } return m_sign == other.m_sign && m_digits == other.m_digits; } @@ -227,9 +264,13 @@ bool BigInteger::operator!=(const BigInteger& other) const { } bool BigInteger::operator<(const BigInteger& other) const { - if (m_sign != other.m_sign) return m_sign < other.m_sign; - if (m_sign == 0) return false; - int cmp = m_compareAbs(m_digits, other.m_digits); + if (m_sign != other.m_sign) { + return m_sign < other.m_sign; + } + if (m_sign == 0) { + return false; + } + const int cmp = m_compareAbs(m_digits, other.m_digits); return m_sign > 0 ? cmp < 0 : cmp > 0; } @@ -298,7 +339,9 @@ BigInteger BigInteger::operator+() const { } BigInteger BigInteger::operator-() const { - if (isZero()) return {0}; + if (isZero()) { + return {0}; + } BigInteger result(*this); result.m_sign = -result.m_sign; return result; @@ -325,17 +368,21 @@ BigInteger& BigInteger::operator/=(const BigInteger& other) { } BigInteger BigInteger::operator+(const BigInteger& other) const { - if (isZero()) return other; - if (other.isZero()) return *this; + if (isZero()) { + return other; + } + if (other.isZero()) { + return *this; + } BigInteger result; if (m_sign == other.m_sign) { result.m_digits = m_addAbs(m_digits, other.m_digits); result.m_sign = m_sign; } else { - int cmp = m_compareAbs(m_digits, other.m_digits); + const int cmp = m_compareAbs(m_digits, other.m_digits); if (cmp == 0) { - result.m_digits = "0"; + result.m_digits.clear(); result.m_sign = 0; } else if (cmp > 0) { result.m_digits = m_subAbs(m_digits, other.m_digits); @@ -345,7 +392,9 @@ BigInteger BigInteger::operator+(const BigInteger& other) const { result.m_sign = other.m_sign; } } - if (result.m_digits == "0") result.m_sign = 0; + if (result.m_digits.empty()) { + result.m_sign = 0; + } return result; } @@ -354,11 +403,16 @@ BigInteger BigInteger::operator-(const BigInteger& other) const { } BigInteger BigInteger::operator*(const BigInteger& other) const { - if (isZero() || other.isZero()) return {0}; + if (isZero() || other.isZero()) { + return {0}; + } + BigInteger result; result.m_digits = m_mulAbs(m_digits, other.m_digits); - result.m_sign = (m_sign * other.m_sign); - if (result.m_digits == "0") result.m_sign = 0; + result.m_sign = m_sign * other.m_sign; + if (result.m_digits.empty()) { + result.m_sign = 0; + } return result; } @@ -366,11 +420,16 @@ BigInteger BigInteger::operator/(const BigInteger& other) const { if (other.isZero()) { throw std::invalid_argument("division by zero"); } - if (isZero()) return {0}; + if (isZero()) { + return {0}; + } + BigInteger result; - result.m_digits = divAbs(m_digits, other.m_digits); - result.m_sign = (m_sign * other.m_sign); - if (result.m_digits == "0") result.m_sign = 0; + result.m_digits = m_divAbs(m_digits, other.m_digits); + result.m_sign = m_sign * other.m_sign; + if (result.m_digits.empty()) { + result.m_sign = 0; + } return result; } @@ -385,5 +444,4 @@ std::istream& operator>>(std::istream& is, BigInteger& bi) { return is; } -} // namespace bstl - +} // namespace bstl