SHA256
Biginteger/decimal
This commit is contained in:
+40
-2
@@ -1,7 +1,45 @@
|
||||
cmake_minimum_required(VERSION 3.10.0)
|
||||
project(BetterSTL VERSION 0.1.0 LANGUAGES C CXX)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
add_library(BetterSTL src/BigInteger.cpp
|
||||
# 定义源文件
|
||||
set(BETTERSTL_SOURCES
|
||||
src/BigInteger.cpp
|
||||
src/BigDecimal.cpp)
|
||||
|
||||
include_directories(include)
|
||||
# 生成静态库 (.a 文件)
|
||||
add_library(BetterSTL_static STATIC ${BETTERSTL_SOURCES})
|
||||
target_include_directories(BetterSTL_static PUBLIC include)
|
||||
set_target_properties(BetterSTL_static PROPERTIES
|
||||
OUTPUT_NAME BetterSTL
|
||||
PREFIX lib)
|
||||
|
||||
# 生成动态库 (.so 文件)
|
||||
add_library(BetterSTL_shared SHARED ${BETTERSTL_SOURCES})
|
||||
target_include_directories(BetterSTL_shared PUBLIC include)
|
||||
set_target_properties(BetterSTL_shared PROPERTIES
|
||||
OUTPUT_NAME BetterSTL
|
||||
PREFIX lib)
|
||||
|
||||
# 默认链接到静态库
|
||||
add_library(BetterSTL ALIAS BetterSTL_static)
|
||||
|
||||
enable_testing()
|
||||
|
||||
add_executable(BigIntegerTests tests/BigIntegerTest.cpp)
|
||||
target_include_directories(BigIntegerTests PRIVATE include)
|
||||
target_link_libraries(BigIntegerTests PRIVATE BetterSTL_static)
|
||||
add_test(NAME BigIntegerTests COMMAND BigIntegerTests)
|
||||
|
||||
add_executable(BigDecimalTests tests/BigDecimalTest.cpp)
|
||||
target_include_directories(BigDecimalTests PRIVATE include)
|
||||
target_link_libraries(BigDecimalTests PRIVATE BetterSTL_static)
|
||||
add_test(NAME BigDecimalTests COMMAND BigDecimalTests)
|
||||
|
||||
# 生成导出信息用于外部使用
|
||||
install(TARGETS BetterSTL_static BetterSTL_shared
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
RUNTIME DESTINATION bin)
|
||||
install(DIRECTORY include/ DESTINATION include)
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "BigInteger.hpp"
|
||||
|
||||
namespace bstl {
|
||||
|
||||
class BigDecimal {
|
||||
public:
|
||||
BigDecimal();
|
||||
BigDecimal(int value);
|
||||
BigDecimal(long long value);
|
||||
BigDecimal(double value);
|
||||
explicit BigDecimal(const std::string& value);
|
||||
explicit BigDecimal(const char* value);
|
||||
BigDecimal(const BigInteger& unscaledValue, int scale);
|
||||
BigDecimal(const BigDecimal& other) = default;
|
||||
BigDecimal& operator=(const BigDecimal& other) = default;
|
||||
|
||||
bool isZero() const;
|
||||
int sign() const;
|
||||
int getScale() const;
|
||||
BigInteger getUnscaledValue() const;
|
||||
std::string toString() const;
|
||||
|
||||
// Comparison operators
|
||||
bool operator==(const BigDecimal& other) const;
|
||||
bool operator!=(const BigDecimal& other) const;
|
||||
bool operator<(const BigDecimal& other) const;
|
||||
bool operator>(const BigDecimal& other) const;
|
||||
bool operator<=(const BigDecimal& other) const;
|
||||
bool operator>=(const BigDecimal& other) const;
|
||||
|
||||
bool operator==(int value) const;
|
||||
bool operator!=(int value) const;
|
||||
bool operator<(int value) const;
|
||||
bool operator>(int value) const;
|
||||
bool operator<=(int value) const;
|
||||
bool operator>=(int value) const;
|
||||
|
||||
bool operator==(double value) const;
|
||||
bool operator!=(double value) const;
|
||||
bool operator<(double value) const;
|
||||
bool operator>(double value) const;
|
||||
bool operator<=(double value) const;
|
||||
bool operator>=(double value) const;
|
||||
|
||||
// Arithmetic operators
|
||||
BigDecimal operator+() const;
|
||||
BigDecimal operator-() const;
|
||||
BigDecimal& operator+=(const BigDecimal& other);
|
||||
BigDecimal& operator-=(const BigDecimal& other);
|
||||
BigDecimal& operator*=(const BigDecimal& other);
|
||||
BigDecimal& operator/=(const BigDecimal& other);
|
||||
|
||||
BigDecimal operator+(const BigDecimal& other) const;
|
||||
BigDecimal operator-(const BigDecimal& other) const;
|
||||
BigDecimal operator*(const BigDecimal& other) const;
|
||||
BigDecimal operator/(const BigDecimal& other) const;
|
||||
|
||||
BigDecimal abs() const;
|
||||
BigDecimal round(int scale) const;
|
||||
|
||||
private:
|
||||
BigInteger unscaledValue_; // 去掉小数点后的值
|
||||
int scale_; // 小数点后的位数
|
||||
|
||||
static void alignScale(BigInteger& lhs, int& lhsScale,
|
||||
BigInteger& rhs, int& rhsScale);
|
||||
};
|
||||
|
||||
} // namespace bstl
|
||||
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace bstl {
|
||||
|
||||
class BigInteger {
|
||||
public:
|
||||
BigInteger();
|
||||
BigInteger(int value);
|
||||
BigInteger(long long value);
|
||||
BigInteger(unsigned long long value);
|
||||
explicit BigInteger(const std::string& value);
|
||||
explicit BigInteger(const char* value);
|
||||
BigInteger(const BigInteger& other) = default;
|
||||
BigInteger& operator=(const BigInteger& other) = default;
|
||||
|
||||
bool isZero() const;
|
||||
int sign() const;
|
||||
std::string toString() const;
|
||||
|
||||
bool operator==(const BigInteger& other) const;
|
||||
bool operator!=(const BigInteger& other) const;
|
||||
bool operator<(const BigInteger& other) const;
|
||||
bool operator>(const BigInteger& other) const;
|
||||
bool operator<=(const BigInteger& other) const;
|
||||
bool operator>=(const BigInteger& other) const;
|
||||
|
||||
bool operator==(int value) const;
|
||||
bool operator!=(int value) const;
|
||||
bool operator<(int value) const;
|
||||
bool operator>(int value) const;
|
||||
bool operator<=(int value) const;
|
||||
bool operator>=(int value) const;
|
||||
|
||||
bool operator==(long long value) const;
|
||||
bool operator!=(long long value) const;
|
||||
bool operator<(long long value) const;
|
||||
bool operator>(long long value) const;
|
||||
bool operator<=(long long value) const;
|
||||
bool operator>=(long long value) const;
|
||||
|
||||
BigInteger operator+() const;
|
||||
BigInteger operator-() const;
|
||||
BigInteger& operator+=(const BigInteger& other);
|
||||
BigInteger& operator-=(const BigInteger& other);
|
||||
BigInteger& operator*=(const BigInteger& other);
|
||||
BigInteger& operator/=(const BigInteger& other);
|
||||
|
||||
BigInteger operator+(const BigInteger& other) const;
|
||||
BigInteger operator-(const BigInteger& other) const;
|
||||
BigInteger operator*(const BigInteger& other) const;
|
||||
BigInteger operator/(const BigInteger& other) const;
|
||||
|
||||
private:
|
||||
std::string digits_; // 无符号数字,从高位到低位
|
||||
int sign_; // -1, 0, 1
|
||||
|
||||
static std::string trimLeadingZeros(const std::string& value);
|
||||
static int compareAbs(const std::string& a, const std::string& b);
|
||||
static std::string addAbs(const std::string& a, const std::string& b);
|
||||
static std::string subAbs(const std::string& a, const std::string& b);
|
||||
static std::string mulAbs(const std::string& a, const std::string& b);
|
||||
static std::string divAbs(const std::string& a, const std::string& b);
|
||||
};
|
||||
|
||||
using BitInteger = BigInteger;
|
||||
|
||||
} // namespace bstl
|
||||
+3
-4
@@ -1,4 +1,3 @@
|
||||
#ifndef BETTERSTL_BSTL_HPP
|
||||
#define BETTERSTL_BSTL_HPP
|
||||
|
||||
#endif //BETTERSTL_BSTL_HPP
|
||||
#pragma once
|
||||
#include<BigDecimal.hpp>
|
||||
#include<BigInteger.hpp>
|
||||
@@ -0,0 +1,341 @@
|
||||
#include "BigDecimal.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include <cmath>
|
||||
|
||||
namespace bstl {
|
||||
|
||||
BigDecimal::BigDecimal() : unscaledValue_(0), scale_(0) {}
|
||||
|
||||
BigDecimal::BigDecimal(int value) : unscaledValue_(value), scale_(0) {}
|
||||
|
||||
BigDecimal::BigDecimal(long long value) : unscaledValue_(value), scale_(0) {}
|
||||
|
||||
BigDecimal::BigDecimal(double value) : scale_(0) {
|
||||
if (value == 0.0) {
|
||||
unscaledValue_ = 0;
|
||||
scale_ = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// 将浮点数转换为字符串,然后解析
|
||||
std::ostringstream oss;
|
||||
oss.precision(15);
|
||||
oss << value;
|
||||
*this = BigDecimal(oss.str());
|
||||
}
|
||||
|
||||
BigDecimal::BigDecimal(const std::string& value) : unscaledValue_(0), scale_(0) {
|
||||
if (value.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string text = value;
|
||||
|
||||
// 去掉前后空格
|
||||
size_t start = 0, end = text.size();
|
||||
while (start < end && text[start] == ' ') start++;
|
||||
while (end > start && text[end - 1] == ' ') end--;
|
||||
text = text.substr(start, end - start);
|
||||
|
||||
if (text.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 查找小数点位置
|
||||
size_t dotPos = text.find('.');
|
||||
if (dotPos != std::string::npos) {
|
||||
scale_ = text.size() - dotPos - 1;
|
||||
std::string digits = text.substr(0, dotPos) + text.substr(dotPos + 1);
|
||||
unscaledValue_ = BigInteger(digits);
|
||||
} else {
|
||||
scale_ = 0;
|
||||
unscaledValue_ = BigInteger(text);
|
||||
}
|
||||
}
|
||||
|
||||
BigDecimal::BigDecimal(const char* value)
|
||||
: BigDecimal(value == nullptr ? std::string("0") : std::string(value)) {}
|
||||
|
||||
BigDecimal::BigDecimal(const BigInteger& unscaledValue, int scale)
|
||||
: unscaledValue_(unscaledValue), scale_(scale) {
|
||||
if (scale < 0) {
|
||||
throw std::invalid_argument("scale cannot be negative");
|
||||
}
|
||||
}
|
||||
|
||||
bool BigDecimal::isZero() const {
|
||||
return unscaledValue_.isZero();
|
||||
}
|
||||
|
||||
int BigDecimal::sign() const {
|
||||
return unscaledValue_.sign();
|
||||
}
|
||||
|
||||
int BigDecimal::getScale() const {
|
||||
return scale_;
|
||||
}
|
||||
|
||||
BigInteger BigDecimal::getUnscaledValue() const {
|
||||
return unscaledValue_;
|
||||
}
|
||||
|
||||
std::string BigDecimal::toString() const {
|
||||
if (isZero()) {
|
||||
return "0";
|
||||
}
|
||||
|
||||
std::string digitStr = unscaledValue_.toString();
|
||||
|
||||
// 处理符号
|
||||
bool negative = false;
|
||||
if (digitStr[0] == '-') {
|
||||
negative = true;
|
||||
digitStr = digitStr.substr(1);
|
||||
}
|
||||
|
||||
// 插入小数点
|
||||
if (scale_ == 0) {
|
||||
return (negative ? "-" : "") + digitStr;
|
||||
}
|
||||
|
||||
if (static_cast<int>(digitStr.size()) <= scale_) {
|
||||
// 需要前置 "0."
|
||||
std::string result = "0.";
|
||||
for (int i = 0; i < scale_ - static_cast<int>(digitStr.size()); i++) {
|
||||
result += "0";
|
||||
}
|
||||
result += digitStr;
|
||||
return (negative ? "-" : "") + result;
|
||||
}
|
||||
|
||||
int dotPos = digitStr.size() - scale_;
|
||||
std::string result = digitStr.substr(0, dotPos) + "." + digitStr.substr(dotPos);
|
||||
return (negative ? "-" : "") + result;
|
||||
}
|
||||
|
||||
void BigDecimal::alignScale(BigInteger& lhs, int& lhsScale,
|
||||
BigInteger& rhs, int& rhsScale) {
|
||||
if (lhsScale < rhsScale) {
|
||||
// 左边需要扩大
|
||||
for (int i = 0; i < rhsScale - lhsScale; i++) {
|
||||
lhs = lhs * BigInteger(10);
|
||||
}
|
||||
lhsScale = rhsScale;
|
||||
} else if (lhsScale > rhsScale) {
|
||||
// 右边需要扩大
|
||||
for (int i = 0; i < lhsScale - rhsScale; i++) {
|
||||
rhs = rhs * BigInteger(10);
|
||||
}
|
||||
rhsScale = lhsScale;
|
||||
}
|
||||
}
|
||||
|
||||
bool BigDecimal::operator==(const BigDecimal& other) const {
|
||||
if (isZero() && other.isZero()) return true;
|
||||
BigInteger lhs = unscaledValue_;
|
||||
BigInteger rhs = other.unscaledValue_;
|
||||
int lhsScale = scale_;
|
||||
int rhsScale = other.scale_;
|
||||
alignScale(lhs, lhsScale, rhs, rhsScale);
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
bool BigDecimal::operator!=(const BigDecimal& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool BigDecimal::operator<(const BigDecimal& other) const {
|
||||
if (unscaledValue_.sign() != other.unscaledValue_.sign()) {
|
||||
return unscaledValue_.sign() < other.unscaledValue_.sign();
|
||||
}
|
||||
|
||||
BigInteger lhs = unscaledValue_;
|
||||
BigInteger rhs = other.unscaledValue_;
|
||||
int lhsScale = scale_;
|
||||
int rhsScale = other.scale_;
|
||||
alignScale(lhs, lhsScale, rhs, rhsScale);
|
||||
|
||||
if (unscaledValue_.sign() >= 0) {
|
||||
return lhs < rhs;
|
||||
} else {
|
||||
return lhs > rhs;
|
||||
}
|
||||
}
|
||||
|
||||
bool BigDecimal::operator>(const BigDecimal& other) const {
|
||||
return other < *this;
|
||||
}
|
||||
|
||||
bool BigDecimal::operator<=(const BigDecimal& other) const {
|
||||
return *this < other || *this == other;
|
||||
}
|
||||
|
||||
bool BigDecimal::operator>=(const BigDecimal& other) const {
|
||||
return other <= *this;
|
||||
}
|
||||
|
||||
bool BigDecimal::operator==(int value) const {
|
||||
return *this == BigDecimal(value);
|
||||
}
|
||||
|
||||
bool BigDecimal::operator!=(int value) const {
|
||||
return !(*this == value);
|
||||
}
|
||||
|
||||
bool BigDecimal::operator<(int value) const {
|
||||
return *this < BigDecimal(value);
|
||||
}
|
||||
|
||||
bool BigDecimal::operator>(int value) const {
|
||||
return *this > BigDecimal(value);
|
||||
}
|
||||
|
||||
bool BigDecimal::operator<=(int value) const {
|
||||
return *this <= BigDecimal(value);
|
||||
}
|
||||
|
||||
bool BigDecimal::operator>=(int value) const {
|
||||
return *this >= BigDecimal(value);
|
||||
}
|
||||
|
||||
bool BigDecimal::operator==(double value) const {
|
||||
return *this == BigDecimal(value);
|
||||
}
|
||||
|
||||
bool BigDecimal::operator!=(double value) const {
|
||||
return !(*this == value);
|
||||
}
|
||||
|
||||
bool BigDecimal::operator<(double value) const {
|
||||
return *this < BigDecimal(value);
|
||||
}
|
||||
|
||||
bool BigDecimal::operator>(double value) const {
|
||||
return *this > BigDecimal(value);
|
||||
}
|
||||
|
||||
bool BigDecimal::operator<=(double value) const {
|
||||
return *this <= BigDecimal(value);
|
||||
}
|
||||
|
||||
bool BigDecimal::operator>=(double value) const {
|
||||
return *this >= BigDecimal(value);
|
||||
}
|
||||
|
||||
BigDecimal BigDecimal::operator+() const {
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigDecimal BigDecimal::operator-() const {
|
||||
if (isZero()) {
|
||||
return BigDecimal(0);
|
||||
}
|
||||
return BigDecimal(-unscaledValue_, scale_);
|
||||
}
|
||||
|
||||
BigDecimal& BigDecimal::operator+=(const BigDecimal& other) {
|
||||
*this = *this + other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigDecimal& BigDecimal::operator-=(const BigDecimal& other) {
|
||||
*this = *this - other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigDecimal& BigDecimal::operator*=(const BigDecimal& other) {
|
||||
*this = *this * other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigDecimal& BigDecimal::operator/=(const BigDecimal& other) {
|
||||
*this = *this / other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigDecimal BigDecimal::operator+(const BigDecimal& other) const {
|
||||
if (isZero()) return other;
|
||||
if (other.isZero()) return *this;
|
||||
|
||||
BigInteger lhs = unscaledValue_;
|
||||
BigInteger rhs = other.unscaledValue_;
|
||||
int lhsScale = scale_;
|
||||
int rhsScale = other.scale_;
|
||||
alignScale(lhs, lhsScale, rhs, rhsScale);
|
||||
|
||||
return BigDecimal(lhs + rhs, lhsScale);
|
||||
}
|
||||
|
||||
BigDecimal BigDecimal::operator-(const BigDecimal& other) const {
|
||||
return *this + (-other);
|
||||
}
|
||||
|
||||
BigDecimal BigDecimal::operator*(const BigDecimal& other) const {
|
||||
if (isZero() || other.isZero()) {
|
||||
return BigDecimal(0);
|
||||
}
|
||||
|
||||
BigInteger result = unscaledValue_ * other.unscaledValue_;
|
||||
int resultScale = scale_ + other.scale_;
|
||||
|
||||
return BigDecimal(result, resultScale);
|
||||
}
|
||||
|
||||
BigDecimal BigDecimal::operator/(const BigDecimal& other) const {
|
||||
if (other.isZero()) {
|
||||
throw std::invalid_argument("division by zero");
|
||||
}
|
||||
|
||||
if (isZero()) {
|
||||
return BigDecimal(0);
|
||||
}
|
||||
|
||||
// 先对齐 scale,然后做整数除法
|
||||
BigInteger lhs = unscaledValue_;
|
||||
BigInteger rhs = other.unscaledValue_;
|
||||
int lhsScale = scale_;
|
||||
int rhsScale = other.scale_;
|
||||
|
||||
// 使用更高的精度进行除法
|
||||
// 乘以 10^precision 来获得更多的精度
|
||||
int precision = 10;
|
||||
for (int i = 0; i < precision; i++) {
|
||||
lhs = lhs * BigInteger(10);
|
||||
}
|
||||
|
||||
BigInteger quotient = lhs / rhs;
|
||||
int resultScale = lhsScale - rhsScale + precision;
|
||||
|
||||
return BigDecimal(quotient, resultScale);
|
||||
}
|
||||
|
||||
BigDecimal BigDecimal::abs() const {
|
||||
if (unscaledValue_.sign() >= 0) {
|
||||
return *this;
|
||||
}
|
||||
return BigDecimal(-unscaledValue_, scale_);
|
||||
}
|
||||
|
||||
BigDecimal BigDecimal::round(int scale) const {
|
||||
if (scale < 0) {
|
||||
throw std::invalid_argument("scale cannot be negative");
|
||||
}
|
||||
|
||||
if (scale >= scale_) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
// 简单实现:直接截断到指定小数位数
|
||||
int diff = scale_ - scale;
|
||||
BigInteger divisor = BigInteger(10);
|
||||
for (int i = 1; i < diff; i++) {
|
||||
divisor = divisor * BigInteger(10);
|
||||
}
|
||||
|
||||
BigInteger rounded = unscaledValue_ / divisor;
|
||||
return BigDecimal(rounded, scale);
|
||||
}
|
||||
|
||||
} // namespace bstl
|
||||
|
||||
@@ -0,0 +1,378 @@
|
||||
#include "BigInteger.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace bstl {
|
||||
|
||||
std::string BigInteger::trimLeadingZeros(const std::string& value) {
|
||||
size_t pos = 0;
|
||||
while (pos < value.size() - 1 && value[pos] == '0') {
|
||||
pos++;
|
||||
}
|
||||
return value.substr(pos);
|
||||
}
|
||||
|
||||
int BigInteger::compareAbs(const std::string& a, const std::string& b) {
|
||||
std::string ta = trimLeadingZeros(a);
|
||||
std::string tb = 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::addAbs(const std::string& a, const std::string& b) {
|
||||
std::string result;
|
||||
int carry = 0;
|
||||
int i = static_cast<int>(a.size()) - 1;
|
||||
int j = static_cast<int>(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 = char('0' + sum % 10) + result;
|
||||
carry = sum / 10;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string BigInteger::subAbs(const std::string& a, const std::string& b) {
|
||||
std::string ta = trimLeadingZeros(a);
|
||||
std::string tb = trimLeadingZeros(b);
|
||||
if (compareAbs(ta, tb) < 0) {
|
||||
return subAbs(tb, ta);
|
||||
}
|
||||
std::string result;
|
||||
int borrow = 0;
|
||||
int i = static_cast<int>(ta.size()) - 1;
|
||||
int j = static_cast<int>(tb.size()) - 1;
|
||||
while (i >= 0) {
|
||||
int diff = (ta[i--] - '0') - borrow;
|
||||
if (j >= 0) {
|
||||
diff -= (tb[j--] - '0');
|
||||
}
|
||||
if (diff < 0) {
|
||||
diff += 10;
|
||||
borrow = 1;
|
||||
} else {
|
||||
borrow = 0;
|
||||
}
|
||||
result = char('0' + diff) + result;
|
||||
}
|
||||
return trimLeadingZeros(result);
|
||||
}
|
||||
|
||||
std::string BigInteger::mulAbs(const std::string& a, const std::string& b) {
|
||||
std::string ta = trimLeadingZeros(a);
|
||||
std::string tb = trimLeadingZeros(b);
|
||||
if (ta == "0" || tb == "0") return "0";
|
||||
|
||||
std::vector<int> 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;
|
||||
}
|
||||
}
|
||||
|
||||
int carry = 0;
|
||||
for (size_t i = 0; i < product.size(); i++) {
|
||||
int sum = product[i] + carry;
|
||||
product[i] = sum % 10;
|
||||
carry = sum / 10;
|
||||
}
|
||||
|
||||
std::string result;
|
||||
for (int i = static_cast<int>(product.size()) - 1; i >= 0; i--) {
|
||||
result += char('0' + product[i]);
|
||||
}
|
||||
return trimLeadingZeros(result);
|
||||
}
|
||||
|
||||
std::string BigInteger::divAbs(const std::string& a, const std::string& b) {
|
||||
std::string tb = trimLeadingZeros(b);
|
||||
if (tb == "0") {
|
||||
throw std::invalid_argument("division by zero");
|
||||
}
|
||||
std::string ta = trimLeadingZeros(a);
|
||||
if (compareAbs(ta, tb) < 0) {
|
||||
return "0";
|
||||
}
|
||||
|
||||
std::string quotient;
|
||||
std::string current;
|
||||
for (char digit : ta) {
|
||||
current += digit;
|
||||
current = trimLeadingZeros(current);
|
||||
int count = 0;
|
||||
while (compareAbs(current, tb) >= 0) {
|
||||
current = subAbs(current, tb);
|
||||
count++;
|
||||
}
|
||||
quotient += char('0' + count);
|
||||
}
|
||||
return trimLeadingZeros(quotient);
|
||||
}
|
||||
|
||||
BigInteger::BigInteger() : digits_("0"), sign_(0) {}
|
||||
|
||||
BigInteger::BigInteger(int value) : digits_("0"), sign_(1) {
|
||||
if (value == 0) {
|
||||
digits_ = "0";
|
||||
sign_ = 0;
|
||||
return;
|
||||
}
|
||||
if (value < 0) {
|
||||
sign_ = -1;
|
||||
value = -value;
|
||||
}
|
||||
digits_.clear();
|
||||
while (value > 0) {
|
||||
digits_ = char('0' + value % 10) + digits_;
|
||||
value /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
BigInteger::BigInteger(long long value) : digits_("0"), sign_(1) {
|
||||
if (value == 0) {
|
||||
digits_ = "0";
|
||||
sign_ = 0;
|
||||
return;
|
||||
}
|
||||
if (value < 0) {
|
||||
sign_ = -1;
|
||||
value = -value;
|
||||
}
|
||||
digits_.clear();
|
||||
while (value > 0) {
|
||||
digits_ = char('0' + value % 10) + digits_;
|
||||
value /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
BigInteger::BigInteger(unsigned long long value) : digits_("0"), sign_(1) {
|
||||
if (value == 0) {
|
||||
digits_ = "0";
|
||||
sign_ = 0;
|
||||
return;
|
||||
}
|
||||
digits_.clear();
|
||||
while (value > 0) {
|
||||
digits_ = char('0' + value % 10) + digits_;
|
||||
value /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
BigInteger::BigInteger(const std::string& value) : digits_("0"), sign_(1) {
|
||||
if (value.empty()) {
|
||||
digits_ = "0";
|
||||
sign_ = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string text = value;
|
||||
sign_ = 1;
|
||||
|
||||
if (text[0] == '-') {
|
||||
sign_ = -1;
|
||||
text = text.substr(1);
|
||||
} else if (text[0] == '+') {
|
||||
text = text.substr(1);
|
||||
}
|
||||
|
||||
if (text.empty()) {
|
||||
digits_ = "0";
|
||||
sign_ = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
for (char ch : text) {
|
||||
if (ch < '0' || ch > '9') {
|
||||
throw std::invalid_argument("BigInteger: invalid numeric string");
|
||||
}
|
||||
}
|
||||
|
||||
digits_ = trimLeadingZeros(text);
|
||||
if (digits_ == "0") {
|
||||
sign_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
BigInteger::BigInteger(const char* value)
|
||||
: BigInteger(value == nullptr ? std::string("0") : std::string(value)) {}
|
||||
|
||||
bool BigInteger::isZero() const {
|
||||
return sign_ == 0 || digits_ == "0";
|
||||
}
|
||||
|
||||
int BigInteger::sign() const {
|
||||
return isZero() ? 0 : sign_;
|
||||
}
|
||||
|
||||
std::string BigInteger::toString() const {
|
||||
if (isZero()) return "0";
|
||||
return (sign_ < 0 ? "-" : "") + digits_;
|
||||
}
|
||||
|
||||
bool BigInteger::operator==(const BigInteger& other) const {
|
||||
if (isZero() && other.isZero()) return true;
|
||||
return sign_ == other.sign_ && digits_ == other.digits_;
|
||||
}
|
||||
|
||||
bool BigInteger::operator!=(const BigInteger& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool BigInteger::operator<(const BigInteger& other) const {
|
||||
if (sign_ != other.sign_) return sign_ < other.sign_;
|
||||
if (sign_ == 0) return false;
|
||||
int cmp = compareAbs(digits_, other.digits_);
|
||||
return sign_ > 0 ? cmp < 0 : cmp > 0;
|
||||
}
|
||||
|
||||
bool BigInteger::operator>(const BigInteger& other) const {
|
||||
return other < *this;
|
||||
}
|
||||
|
||||
bool BigInteger::operator<=(const BigInteger& other) const {
|
||||
return *this < other || *this == other;
|
||||
}
|
||||
|
||||
bool BigInteger::operator>=(const BigInteger& other) const {
|
||||
return other <= *this;
|
||||
}
|
||||
|
||||
bool BigInteger::operator==(int value) const {
|
||||
return *this == BigInteger(value);
|
||||
}
|
||||
|
||||
bool BigInteger::operator!=(int value) const {
|
||||
return !(*this == value);
|
||||
}
|
||||
|
||||
bool BigInteger::operator<(int value) const {
|
||||
return *this < BigInteger(value);
|
||||
}
|
||||
|
||||
bool BigInteger::operator>(int value) const {
|
||||
return *this > BigInteger(value);
|
||||
}
|
||||
|
||||
bool BigInteger::operator<=(int value) const {
|
||||
return *this <= BigInteger(value);
|
||||
}
|
||||
|
||||
bool BigInteger::operator>=(int value) const {
|
||||
return *this >= BigInteger(value);
|
||||
}
|
||||
|
||||
bool BigInteger::operator==(long long value) const {
|
||||
return *this == BigInteger(value);
|
||||
}
|
||||
|
||||
bool BigInteger::operator!=(long long value) const {
|
||||
return !(*this == value);
|
||||
}
|
||||
|
||||
bool BigInteger::operator<(long long value) const {
|
||||
return *this < BigInteger(value);
|
||||
}
|
||||
|
||||
bool BigInteger::operator>(long long value) const {
|
||||
return *this > BigInteger(value);
|
||||
}
|
||||
|
||||
bool BigInteger::operator<=(long long value) const {
|
||||
return *this <= BigInteger(value);
|
||||
}
|
||||
|
||||
bool BigInteger::operator>=(long long value) const {
|
||||
return *this >= BigInteger(value);
|
||||
}
|
||||
|
||||
BigInteger BigInteger::operator+() const {
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger BigInteger::operator-() const {
|
||||
if (isZero()) return BigInteger(0);
|
||||
BigInteger result(*this);
|
||||
result.sign_ = -result.sign_;
|
||||
return result;
|
||||
}
|
||||
|
||||
BigInteger& BigInteger::operator+=(const BigInteger& other) {
|
||||
*this = *this + other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger& BigInteger::operator-=(const BigInteger& other) {
|
||||
*this = *this - other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger& BigInteger::operator*=(const BigInteger& other) {
|
||||
*this = *this * other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger& BigInteger::operator/=(const BigInteger& other) {
|
||||
*this = *this / other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger BigInteger::operator+(const BigInteger& other) const {
|
||||
if (isZero()) return other;
|
||||
if (other.isZero()) return *this;
|
||||
|
||||
BigInteger result;
|
||||
if (sign_ == other.sign_) {
|
||||
result.digits_ = addAbs(digits_, other.digits_);
|
||||
result.sign_ = sign_;
|
||||
} else {
|
||||
int cmp = compareAbs(digits_, other.digits_);
|
||||
if (cmp == 0) {
|
||||
result.digits_ = "0";
|
||||
result.sign_ = 0;
|
||||
} else if (cmp > 0) {
|
||||
result.digits_ = subAbs(digits_, other.digits_);
|
||||
result.sign_ = sign_;
|
||||
} else {
|
||||
result.digits_ = subAbs(other.digits_, digits_);
|
||||
result.sign_ = other.sign_;
|
||||
}
|
||||
}
|
||||
if (result.digits_ == "0") result.sign_ = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
BigInteger BigInteger::operator-(const BigInteger& other) const {
|
||||
return *this + (-other);
|
||||
}
|
||||
|
||||
BigInteger BigInteger::operator*(const BigInteger& other) const {
|
||||
if (isZero() || other.isZero()) return BigInteger(0);
|
||||
BigInteger result;
|
||||
result.digits_ = mulAbs(digits_, other.digits_);
|
||||
result.sign_ = (sign_ * other.sign_);
|
||||
if (result.digits_ == "0") result.sign_ = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
BigInteger BigInteger::operator/(const BigInteger& other) const {
|
||||
if (other.isZero()) {
|
||||
throw std::invalid_argument("division by zero");
|
||||
}
|
||||
if (isZero()) return BigInteger(0);
|
||||
BigInteger result;
|
||||
result.digits_ = divAbs(digits_, other.digits_);
|
||||
result.sign_ = (sign_ * other.sign_);
|
||||
if (result.digits_ == "0") result.sign_ = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace bstl
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
#include <BigDecimal.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main() {
|
||||
using bstl::BigDecimal;
|
||||
|
||||
// 基本构造
|
||||
BigDecimal a("123.45");
|
||||
BigDecimal b("67.89");
|
||||
BigDecimal c = a + b;
|
||||
|
||||
assert(c.toString() == "191.34");
|
||||
|
||||
// 减法
|
||||
BigDecimal d = a - b;
|
||||
assert(d.toString() == "55.56");
|
||||
|
||||
// 乘法
|
||||
BigDecimal e = a * BigDecimal("2");
|
||||
assert(e.toString() == "246.90");
|
||||
|
||||
// 比较
|
||||
assert((a > b) == true);
|
||||
assert((a == a) == true);
|
||||
assert((a != b) == true);
|
||||
|
||||
// 零
|
||||
BigDecimal zero("0.0");
|
||||
assert(zero.isZero());
|
||||
|
||||
// 负数
|
||||
BigDecimal neg("-100.50");
|
||||
assert(neg.sign() < 0);
|
||||
assert((-neg).toString() == "100.50");
|
||||
|
||||
std::cout << "BigDecimal tests passed\n";
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#include <BigInteger.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main() {
|
||||
using bstl::BigInteger;
|
||||
|
||||
BigInteger a("12345678901234567890");
|
||||
BigInteger b("98765432109876543210");
|
||||
BigInteger c = a + b;
|
||||
BigInteger d = b - a;
|
||||
BigInteger e = a * BigInteger("2");
|
||||
BigInteger f = BigInteger("100000000000000000000000") / BigInteger("1000000000000000000");
|
||||
|
||||
assert(c.toString() == "111111111011111111100");
|
||||
assert(d.toString() == "86419753208641975320");
|
||||
assert(e.toString() == "24691357802469135780");
|
||||
assert(f.toString() == "100000");
|
||||
|
||||
BigInteger zero("0");
|
||||
assert((a == a) == true);
|
||||
assert((a != b) == true);
|
||||
assert((zero == 0) == true);
|
||||
assert((a > BigInteger("12345678901234567889")) == true);
|
||||
assert((a < b) == true);
|
||||
|
||||
std::cout << "BigInteger tests passed\n";
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user