SHA256
Compare commits
12
Commits
5828ec6f4b
...
main
| Author | SHA256 | Date | |
|---|---|---|---|
|
|
202767a608 | ||
|
|
2a6c53d5bf | ||
|
|
9cb17262eb | ||
|
|
ceb7c3fa44 | ||
|
|
1f8fa26d73 | ||
|
|
b3ab9e9429 | ||
|
|
86191b5eb0 | ||
|
|
c145fa8d05 | ||
|
|
feac230fef | ||
|
|
32a43f6161 | ||
|
|
83a75d4e76 | ||
|
|
fb2b24bc72 |
+145
@@ -0,0 +1,145 @@
|
|||||||
|
# Generated from CLion Inspection settings
|
||||||
|
---
|
||||||
|
Checks: '-*,
|
||||||
|
bugprone-argument-comment,
|
||||||
|
bugprone-assert-side-effect,
|
||||||
|
bugprone-bad-signal-to-kill-thread,
|
||||||
|
bugprone-branch-clone,
|
||||||
|
bugprone-copy-constructor-init,
|
||||||
|
bugprone-dangling-handle,
|
||||||
|
bugprone-dynamic-static-initializers,
|
||||||
|
bugprone-fold-init-type,
|
||||||
|
bugprone-forward-declaration-namespace,
|
||||||
|
bugprone-forwarding-reference-overload,
|
||||||
|
bugprone-inaccurate-erase,
|
||||||
|
bugprone-incorrect-roundings,
|
||||||
|
bugprone-integer-division,
|
||||||
|
bugprone-lambda-function-name,
|
||||||
|
bugprone-macro-parentheses,
|
||||||
|
bugprone-macro-repeated-side-effects,
|
||||||
|
bugprone-misplaced-operator-in-strlen-in-alloc,
|
||||||
|
bugprone-misplaced-pointer-arithmetic-in-alloc,
|
||||||
|
bugprone-misplaced-widening-cast,
|
||||||
|
bugprone-move-forwarding-reference,
|
||||||
|
bugprone-multiple-statement-macro,
|
||||||
|
bugprone-no-escape,
|
||||||
|
bugprone-parent-virtual-call,
|
||||||
|
bugprone-posix-return,
|
||||||
|
bugprone-reserved-identifier,
|
||||||
|
bugprone-sizeof-container,
|
||||||
|
bugprone-sizeof-expression,
|
||||||
|
bugprone-spuriously-wake-up-functions,
|
||||||
|
bugprone-string-constructor,
|
||||||
|
bugprone-string-integer-assignment,
|
||||||
|
bugprone-string-literal-with-embedded-nul,
|
||||||
|
bugprone-suspicious-enum-usage,
|
||||||
|
bugprone-suspicious-include,
|
||||||
|
bugprone-suspicious-memset-usage,
|
||||||
|
bugprone-suspicious-missing-comma,
|
||||||
|
bugprone-suspicious-semicolon,
|
||||||
|
bugprone-suspicious-string-compare,
|
||||||
|
bugprone-suspicious-memory-comparison,
|
||||||
|
bugprone-suspicious-realloc-usage,
|
||||||
|
bugprone-swapped-arguments,
|
||||||
|
bugprone-terminating-continue,
|
||||||
|
bugprone-throw-keyword-missing,
|
||||||
|
bugprone-too-small-loop-variable,
|
||||||
|
bugprone-undefined-memory-manipulation,
|
||||||
|
bugprone-undelegated-constructor,
|
||||||
|
bugprone-unhandled-self-assignment,
|
||||||
|
bugprone-unused-raii,
|
||||||
|
bugprone-unused-return-value,
|
||||||
|
bugprone-use-after-move,
|
||||||
|
bugprone-virtual-near-miss,
|
||||||
|
cert-dcl21-cpp,
|
||||||
|
cert-dcl58-cpp,
|
||||||
|
cert-err34-c,
|
||||||
|
cert-err52-cpp,
|
||||||
|
cert-err60-cpp,
|
||||||
|
cert-flp30-c,
|
||||||
|
cert-msc50-cpp,
|
||||||
|
cert-msc51-cpp,
|
||||||
|
cert-str34-c,
|
||||||
|
cppcoreguidelines-interfaces-global-init,
|
||||||
|
cppcoreguidelines-narrowing-conversions,
|
||||||
|
cppcoreguidelines-pro-type-member-init,
|
||||||
|
cppcoreguidelines-pro-type-static-cast-downcast,
|
||||||
|
cppcoreguidelines-slicing,
|
||||||
|
google-default-arguments,
|
||||||
|
google-runtime-operator,
|
||||||
|
hicpp-exception-baseclass,
|
||||||
|
hicpp-multiway-paths-covered,
|
||||||
|
misc-misplaced-const,
|
||||||
|
misc-new-delete-overloads,
|
||||||
|
misc-non-copyable-objects,
|
||||||
|
misc-throw-by-value-catch-by-reference,
|
||||||
|
misc-unconventional-assign-operator,
|
||||||
|
misc-uniqueptr-reset-release,
|
||||||
|
modernize-avoid-bind,
|
||||||
|
modernize-concat-nested-namespaces,
|
||||||
|
modernize-deprecated-headers,
|
||||||
|
modernize-deprecated-ios-base-aliases,
|
||||||
|
modernize-loop-convert,
|
||||||
|
modernize-make-shared,
|
||||||
|
modernize-make-unique,
|
||||||
|
modernize-pass-by-value,
|
||||||
|
modernize-raw-string-literal,
|
||||||
|
modernize-redundant-void-arg,
|
||||||
|
modernize-replace-auto-ptr,
|
||||||
|
modernize-replace-disallow-copy-and-assign-macro,
|
||||||
|
modernize-replace-random-shuffle,
|
||||||
|
modernize-return-braced-init-list,
|
||||||
|
modernize-shrink-to-fit,
|
||||||
|
modernize-unary-static-assert,
|
||||||
|
modernize-use-auto,
|
||||||
|
modernize-use-bool-literals,
|
||||||
|
modernize-use-emplace,
|
||||||
|
modernize-use-equals-default,
|
||||||
|
modernize-use-equals-delete,
|
||||||
|
modernize-use-nodiscard,
|
||||||
|
modernize-use-noexcept,
|
||||||
|
modernize-use-nullptr,
|
||||||
|
modernize-use-override,
|
||||||
|
modernize-use-transparent-functors,
|
||||||
|
modernize-use-uncaught-exceptions,
|
||||||
|
mpi-buffer-deref,
|
||||||
|
mpi-type-mismatch,
|
||||||
|
openmp-use-default-none,
|
||||||
|
performance-faster-string-find,
|
||||||
|
performance-for-range-copy,
|
||||||
|
performance-implicit-conversion-in-loop,
|
||||||
|
performance-inefficient-algorithm,
|
||||||
|
performance-inefficient-string-concatenation,
|
||||||
|
performance-inefficient-vector-operation,
|
||||||
|
performance-move-const-arg,
|
||||||
|
performance-move-constructor-init,
|
||||||
|
performance-no-automatic-move,
|
||||||
|
performance-noexcept-move-constructor,
|
||||||
|
performance-trivially-destructible,
|
||||||
|
performance-type-promotion-in-math-fn,
|
||||||
|
performance-unnecessary-copy-initialization,
|
||||||
|
performance-unnecessary-value-param,
|
||||||
|
portability-simd-intrinsics,
|
||||||
|
readability-avoid-const-params-in-decls,
|
||||||
|
readability-const-return-type,
|
||||||
|
readability-container-size-empty,
|
||||||
|
readability-convert-member-functions-to-static,
|
||||||
|
readability-delete-null-pointer,
|
||||||
|
readability-deleted-default,
|
||||||
|
readability-inconsistent-declaration-parameter-name,
|
||||||
|
readability-make-member-function-const,
|
||||||
|
readability-misleading-indentation,
|
||||||
|
readability-misplaced-array-index,
|
||||||
|
readability-non-const-parameter,
|
||||||
|
readability-redundant-control-flow,
|
||||||
|
readability-redundant-declaration,
|
||||||
|
readability-redundant-function-ptr-dereference,
|
||||||
|
readability-redundant-smartptr-get,
|
||||||
|
readability-redundant-string-cstr,
|
||||||
|
readability-redundant-string-init,
|
||||||
|
readability-simplify-subscript-expr,
|
||||||
|
readability-static-accessed-through-instance,
|
||||||
|
readability-static-definition-in-anonymous-namespace,
|
||||||
|
readability-string-compare,
|
||||||
|
readability-uniqueptr-delete-release,
|
||||||
|
readability-use-anyofallof'
|
||||||
+15
-4
@@ -4,8 +4,9 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|||||||
|
|
||||||
# 定义源文件
|
# 定义源文件
|
||||||
set(BETTERSTL_SOURCES
|
set(BETTERSTL_SOURCES
|
||||||
src/BigInteger.cpp
|
src/big_integer.cpp
|
||||||
src/BigDecimal.cpp)
|
src/big_decimal.cpp
|
||||||
|
src/string.cpp)
|
||||||
|
|
||||||
# 生成静态库 (.a 文件)
|
# 生成静态库 (.a 文件)
|
||||||
add_library(BetterSTL_static STATIC ${BETTERSTL_SOURCES})
|
add_library(BetterSTL_static STATIC ${BETTERSTL_SOURCES})
|
||||||
@@ -26,16 +27,26 @@ add_library(BetterSTL ALIAS BetterSTL_static)
|
|||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
||||||
add_executable(BigIntegerTests tests/BigIntegerTest.cpp)
|
add_executable(BigIntegerTests tests/big_integer_test.cpp)
|
||||||
target_include_directories(BigIntegerTests PRIVATE include)
|
target_include_directories(BigIntegerTests PRIVATE include)
|
||||||
target_link_libraries(BigIntegerTests PRIVATE BetterSTL_static)
|
target_link_libraries(BigIntegerTests PRIVATE BetterSTL_static)
|
||||||
add_test(NAME BigIntegerTests COMMAND BigIntegerTests)
|
add_test(NAME BigIntegerTests COMMAND BigIntegerTests)
|
||||||
|
|
||||||
add_executable(BigDecimalTests tests/BigDecimalTest.cpp)
|
add_executable(BigDecimalTests tests/big_decimal_test.cpp)
|
||||||
target_include_directories(BigDecimalTests PRIVATE include)
|
target_include_directories(BigDecimalTests PRIVATE include)
|
||||||
target_link_libraries(BigDecimalTests PRIVATE BetterSTL_static)
|
target_link_libraries(BigDecimalTests PRIVATE BetterSTL_static)
|
||||||
add_test(NAME BigDecimalTests COMMAND BigDecimalTests)
|
add_test(NAME BigDecimalTests COMMAND BigDecimalTests)
|
||||||
|
|
||||||
|
add_executable(StringTests tests/StringTest.cpp)
|
||||||
|
target_include_directories(StringTests PRIVATE include)
|
||||||
|
target_link_libraries(StringTests PRIVATE BetterSTL_static)
|
||||||
|
add_test(NAME StringTests COMMAND StringTests)
|
||||||
|
|
||||||
|
add_executable(IOTests tests/IOTest.cpp)
|
||||||
|
target_include_directories(IOTests PRIVATE include)
|
||||||
|
target_link_libraries(IOTests PRIVATE BetterSTL_static)
|
||||||
|
add_test(NAME IOTests COMMAND IOTests)
|
||||||
|
|
||||||
# 生成导出信息用于外部使用
|
# 生成导出信息用于外部使用
|
||||||
install(TARGETS BetterSTL_static BetterSTL_shared
|
install(TARGETS BetterSTL_static BetterSTL_shared
|
||||||
LIBRARY DESTINATION lib
|
LIBRARY DESTINATION lib
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
# BetterSTL cin/cout 支持
|
||||||
|
|
||||||
|
现在三个核心类都支持标准输入输出:
|
||||||
|
|
||||||
|
## BigInteger - 高精度整数
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <bstl/big_integer.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
bstl::BigInteger bi;
|
||||||
|
std::cout << "Enter a large integer: ";
|
||||||
|
std::cin >> bi;
|
||||||
|
std::cout << "You entered: " << bi << std::endl;
|
||||||
|
```
|
||||||
|
|
||||||
|
支持任意精度的整数输入输出,不受 `long long` 限制。
|
||||||
|
|
||||||
|
## BigDecimal - 高精度浮点数
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <bstl/big_decimal.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
bstl::BigDecimal bd;
|
||||||
|
std::cout << "Enter a decimal number: ";
|
||||||
|
std::cin >> bd;
|
||||||
|
std::cout << "You entered: " << bd << std::endl;
|
||||||
|
```
|
||||||
|
|
||||||
|
支持任意精度的浮点数输入输出,精度不丢失。
|
||||||
|
|
||||||
|
## String - 增强字符串
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <bstl/string.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
bstl::String str;
|
||||||
|
std::cout << "Enter a word: ";
|
||||||
|
std::cin >> str;
|
||||||
|
std::cout << "You entered: " << str << std::endl;
|
||||||
|
|
||||||
|
// 可以使用 Python 风格的方法
|
||||||
|
std::cout << "Uppercase: " << str.upper() << std::endl;
|
||||||
|
std::cout << "Split: ";
|
||||||
|
auto parts = str.split("_");
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用示例
|
||||||
|
|
||||||
|
编译和运行演示程序:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/archzero/C++/BetterSTL
|
||||||
|
cmake -S . -B out/build -G Ninja
|
||||||
|
cmake --build out/build
|
||||||
|
|
||||||
|
# 运行库测试
|
||||||
|
ctest --test-dir out/build
|
||||||
|
|
||||||
|
# 运行演示(需要在终端交互)
|
||||||
|
./out/build/IOTests
|
||||||
|
```
|
||||||
|
|
||||||
|
## 实现细节
|
||||||
|
|
||||||
|
### operator<<(输出)
|
||||||
|
- BigInteger: 通过 `toString()` 输出
|
||||||
|
- BigDecimal: 通过 `toString()` 输出
|
||||||
|
- String: 通过 `str()` 输出
|
||||||
|
|
||||||
|
### operator>>(输入)
|
||||||
|
- BigInteger: 读取字符串,创建新对象
|
||||||
|
- BigDecimal: 读取字符串,创建新对象
|
||||||
|
- String: 读取字符串,创建新对象
|
||||||
|
|
||||||
|
所有运算符都定义在 `bstl` 命名空间中。
|
||||||
|
|
||||||
|
## 编译链接
|
||||||
|
|
||||||
|
在编译你的程序时:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
g++ your_program.cpp -I/path/to/include -L/path/to/lib -lBetterSTL -o your_program
|
||||||
|
```
|
||||||
|
|
||||||
|
或者使用静态库:
|
||||||
|
```bash
|
||||||
|
g++ your_program.cpp -I/path/to/include /path/to/libBetterSTL.a -o your_program
|
||||||
|
```
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#include <bstl/big_integer.hpp>
|
||||||
|
#include <bstl/big_decimal.hpp>
|
||||||
|
#include <bstl/string.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
using bstl::BigInteger;
|
||||||
|
using bstl::BigDecimal;
|
||||||
|
using bstl::String;
|
||||||
|
|
||||||
|
std::cout << "=== BetterSTL cin/cout Demo ===\n\n";
|
||||||
|
|
||||||
|
// BigInteger 示例
|
||||||
|
std::cout << "BigInteger Example:\n";
|
||||||
|
std::cout << "Enter a large integer: ";
|
||||||
|
BigInteger bi;
|
||||||
|
std::cin >> bi;
|
||||||
|
std::cout << "You entered: " << bi << "\n";
|
||||||
|
std::cout << "Doubled: " << (bi * BigInteger(2)) << "\n\n";
|
||||||
|
|
||||||
|
// BigDecimal 示例
|
||||||
|
std::cout << "BigDecimal Example:\n";
|
||||||
|
std::cout << "Enter a decimal number: ";
|
||||||
|
BigDecimal bd;
|
||||||
|
std::cin >> bd;
|
||||||
|
std::cout << "You entered: " << bd << "\n";
|
||||||
|
std::cout << "Doubled: " << (bd * BigDecimal(2)) << "\n\n";
|
||||||
|
|
||||||
|
// String 示例
|
||||||
|
std::cout << "String Example:\n";
|
||||||
|
std::cout << "Enter a word: ";
|
||||||
|
String str;
|
||||||
|
std::cin >> str;
|
||||||
|
std::cout << "You entered: " << str << "\n";
|
||||||
|
std::cout << "Uppercase: " << str.upper() << "\n";
|
||||||
|
std::cout << "Lowercase: " << str.lower() << "\n\n";
|
||||||
|
|
||||||
|
std::cout << "Demo completed!\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Executable
BIN
Binary file not shown.
@@ -1,7 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include<BigDecimal.hpp>
|
|
||||||
#include<BigInteger.hpp>
|
|
||||||
#include <bstlint.hpp>
|
|
||||||
#ifndef BETTERSTL_BSTL_HPP
|
|
||||||
#define BETTERSTL_BSTL_HPP
|
|
||||||
#endif //BETTERSTL_BSTL_HPP
|
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
#pragma once
|
#ifndef BETTERSTL_BIG_DECIMAL_H
|
||||||
|
#define BETTERSTL_BIG_DECIMAL_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "BigInteger.hpp"
|
#include <iostream>
|
||||||
|
#include <bstl/big_integer.hpp>
|
||||||
|
|
||||||
namespace bstl {
|
namespace bstl {
|
||||||
|
|
||||||
class BigDecimal {
|
class BigDecimal {
|
||||||
public:
|
public:
|
||||||
BigDecimal();
|
BigDecimal();
|
||||||
@@ -17,11 +18,11 @@ public:
|
|||||||
BigDecimal(const BigDecimal& other) = default;
|
BigDecimal(const BigDecimal& other) = default;
|
||||||
BigDecimal& operator=(const BigDecimal& other) = default;
|
BigDecimal& operator=(const BigDecimal& other) = default;
|
||||||
|
|
||||||
bool isZero() const;
|
[[nodiscard]] bool isZero() const;
|
||||||
int sign() const;
|
[[nodiscard]] int sign() const;
|
||||||
int getScale() const;
|
[[nodiscard]] int getScale() const;
|
||||||
BigInteger getUnscaledValue() const;
|
[[nodiscard]] BigInteger getUnscaledValue() const;
|
||||||
std::string toString() const;
|
[[nodiscard]] std::string toString() const;
|
||||||
|
|
||||||
// Comparison operators
|
// Comparison operators
|
||||||
bool operator==(const BigDecimal& other) const;
|
bool operator==(const BigDecimal& other) const;
|
||||||
@@ -58,15 +59,21 @@ public:
|
|||||||
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;
|
[[nodiscard]] BigDecimal abs() const;
|
||||||
BigDecimal round(int scale) const;
|
[[nodiscard]] BigDecimal round(int scale) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BigInteger unscaledValue_; // 去掉小数点后的值
|
BigInteger m_unscaledValue; // 去掉小数点后的值
|
||||||
int scale_; // 小数点后的位数
|
int m_scale; // 小数点后的位数
|
||||||
|
|
||||||
static void alignScale(BigInteger& lhs, int& lhsScale,
|
static void m_alignScale(BigInteger& lhs, int& lhsScale,
|
||||||
BigInteger& rhs, int& rhsScale);
|
BigInteger& rhs, int& rhsScale);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 流运算符重载
|
||||||
|
std::ostream& operator<<(std::ostream& os, const BigDecimal& bd);
|
||||||
|
std::istream& operator>>(std::istream& is, BigDecimal& bd);
|
||||||
|
|
||||||
} // namespace bstl
|
} // namespace bstl
|
||||||
|
|
||||||
|
#endif //BETTERSTL_BIG_DECIMAL_H
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
#pragma once
|
#ifndef BETTERSTL_BIG_INTEGER_HPP
|
||||||
|
#define BETTERSTL_BIG_INTEGER_HPP
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace bstl {
|
namespace bstl {
|
||||||
|
|
||||||
@@ -15,9 +18,9 @@ public:
|
|||||||
BigInteger(const BigInteger& other) = default;
|
BigInteger(const BigInteger& other) = default;
|
||||||
BigInteger& operator=(const BigInteger& other) = default;
|
BigInteger& operator=(const BigInteger& other) = default;
|
||||||
|
|
||||||
bool isZero() const;
|
[[nodiscard]] bool isZero() const;
|
||||||
int sign() const;
|
[[nodiscard]] int sign() const;
|
||||||
std::string toString() const;
|
[[nodiscard]] 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;
|
||||||
@@ -53,17 +56,21 @@ public:
|
|||||||
BigInteger operator/(const BigInteger& other) const;
|
BigInteger operator/(const BigInteger& other) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string digits_; // 无符号数字,从高位到低位
|
std::vector<int> m_digits; // 无符号数字,低位在前
|
||||||
int sign_; // -1, 0, 1
|
int m_sign; // -1, 0, 1
|
||||||
|
|
||||||
static std::string trimLeadingZeros(const std::string& value);
|
static std::vector<int> m_trimLeadingZeros(const std::vector<int>& value);
|
||||||
static int compareAbs(const std::string& a, const std::string& b);
|
static int m_compareAbs(const std::vector<int>& a, const std::vector<int>& b);
|
||||||
static std::string addAbs(const std::string& a, const std::string& b);
|
static std::vector<int> m_addAbs(const std::vector<int>& a, const std::vector<int>& b);
|
||||||
static std::string subAbs(const std::string& a, const std::string& b);
|
static std::vector<int> m_subAbs(const std::vector<int>& a, const std::vector<int>& b);
|
||||||
static std::string mulAbs(const std::string& a, const std::string& b);
|
static std::vector<int> m_mulAbs(const std::vector<int>& a, const std::vector<int>& b);
|
||||||
static std::string divAbs(const std::string& a, const std::string& b);
|
static std::vector<int> m_divAbs(const std::vector<int>& a, const std::vector<int>& b);
|
||||||
};
|
};
|
||||||
|
|
||||||
using BitInteger = BigInteger;
|
// 流运算符重载
|
||||||
|
std::ostream& operator<<(std::ostream& os, const BigInteger& bi);
|
||||||
|
std::istream& operator>>(std::istream& is, BigInteger& bi);
|
||||||
|
|
||||||
} // namespace bstl
|
} // namespace bstl
|
||||||
|
|
||||||
|
#endif //BETTERSTL_BIG_INTEGER_HPP
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#ifndef BETTERSTL_BIG_NUMBERS_HPP
|
||||||
|
#define BETTERSTL_BIG_NUMBERS_HPP
|
||||||
|
|
||||||
|
#include <bstl/big_integer.hpp>
|
||||||
|
#include <bstl/big_decimal.hpp>
|
||||||
|
|
||||||
|
#endif // BETTERSTL_BIG_NUMBERS_HPP
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef BETTERSTL_BSTL_HPP
|
||||||
|
|
||||||
|
#include<bstl/big_decimal.hpp>
|
||||||
|
#include<bstl/big_integer.hpp>
|
||||||
|
#include <bstl/bstlint.hpp>
|
||||||
|
|
||||||
|
#define BETTERSTL_BSTL_HPP
|
||||||
|
#endif //BETTERSTL_BSTL_HPP
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
#define BETTERSTL_BSTLINT_HPP
|
#define BETTERSTL_BSTLINT_HPP
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <>
|
|
||||||
|
|
||||||
typedef std::int8_t i8;
|
typedef std::int8_t i8;
|
||||||
typedef std::int16_t i16;
|
typedef std::int16_t i16;
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace bstl {
|
||||||
|
|
||||||
|
class String {
|
||||||
|
public:
|
||||||
|
String();
|
||||||
|
String(std::string str);
|
||||||
|
String(const char* str);
|
||||||
|
String(const String& other) = default;
|
||||||
|
String& operator=(const String& other) = default;
|
||||||
|
|
||||||
|
// 获取标准字符串
|
||||||
|
[[nodiscard]] std::string str() const;
|
||||||
|
[[nodiscard]] const char* c_str() const;
|
||||||
|
[[nodiscard]] size_t length() const;
|
||||||
|
[[nodiscard]] size_t size() const;
|
||||||
|
[[nodiscard]] bool empty() const;
|
||||||
|
|
||||||
|
// 获取/修改字符
|
||||||
|
[[nodiscard]] char at(size_t pos) const;
|
||||||
|
char operator[](size_t pos) const;
|
||||||
|
char& operator[](size_t pos);
|
||||||
|
|
||||||
|
// 分割 - 按分隔符分割字符串
|
||||||
|
[[nodiscard]] std::vector<String> split(const String& delimiter = " ") const;
|
||||||
|
|
||||||
|
// 连接 - 用分隔符连接多个字符串
|
||||||
|
static String join(const std::vector<String>& parts, const String& delimiter = "");
|
||||||
|
|
||||||
|
// 替换 - 替换第一个/所有匹配项
|
||||||
|
[[nodiscard]] String replace(const String& oldStr, const String& newStr, int count = -1) const;
|
||||||
|
|
||||||
|
// 大小写转换
|
||||||
|
[[nodiscard]] String upper() const;
|
||||||
|
[[nodiscard]] String lower() const;
|
||||||
|
[[nodiscard]] String capitalize() const; // 首字母大写
|
||||||
|
[[nodiscard]] String title() const; // 每个单词首字母大写
|
||||||
|
|
||||||
|
// 判断函数
|
||||||
|
[[nodiscard]] bool startswith(const String& prefix) const;
|
||||||
|
[[nodiscard]] bool endswith(const String& suffix) const;
|
||||||
|
[[nodiscard]] bool contains(const String& substring) const;
|
||||||
|
[[nodiscard]] bool isdigit() const;
|
||||||
|
[[nodiscard]] bool isalpha() const;
|
||||||
|
[[nodiscard]] bool isalnum() const;
|
||||||
|
[[nodiscard]] bool isspace() const;
|
||||||
|
[[nodiscard]] bool isupper() const;
|
||||||
|
[[nodiscard]] bool islower() const;
|
||||||
|
|
||||||
|
// 查找和计数
|
||||||
|
[[nodiscard]] int find(const String& substring, size_t start = 0) const;
|
||||||
|
[[nodiscard]] int rfind(const String& substring) const; // 从后往前查找
|
||||||
|
[[nodiscard]] int count(const String& substring) const;
|
||||||
|
|
||||||
|
// 去除空格和其他字符
|
||||||
|
[[nodiscard]] String strip() const; // 去除前后空格
|
||||||
|
[[nodiscard]] String lstrip() const; // 去除前导空格
|
||||||
|
[[nodiscard]] String rstrip() const; // 去除尾部空格
|
||||||
|
[[nodiscard]] String strip(const String& chars) const; // 去除指定字符
|
||||||
|
|
||||||
|
// 对齐和填充
|
||||||
|
[[nodiscard]] String ljust(size_t width, char fillchar = ' ') const;
|
||||||
|
[[nodiscard]] String rjust(size_t width, char fillchar = ' ') const;
|
||||||
|
[[nodiscard]] String center(size_t width, char fillchar = ' ') const;
|
||||||
|
|
||||||
|
// 字符串转换
|
||||||
|
[[nodiscard]] int toInt() const;
|
||||||
|
[[nodiscard]] long long toLongLong() const;
|
||||||
|
[[nodiscard]] double toDouble() const;
|
||||||
|
|
||||||
|
// 运算符重载
|
||||||
|
String operator+(const String& other) const;
|
||||||
|
String operator+(const char* str) const;
|
||||||
|
String& operator+=(const String& other);
|
||||||
|
bool operator==(const String& other) const;
|
||||||
|
bool operator!=(const String& other) const;
|
||||||
|
bool operator<(const String& other) const;
|
||||||
|
bool operator>(const String& other) const;
|
||||||
|
bool operator<=(const String& other) const;
|
||||||
|
bool operator>=(const String& other) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 流运算符重载
|
||||||
|
std::ostream& operator<<(std::ostream& os, const String& str);
|
||||||
|
std::istream& operator>>(std::istream& is, String& str);
|
||||||
|
|
||||||
|
} // namespace bstl
|
||||||
@@ -1,378 +0,0 @@
|
|||||||
#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
|
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "BigDecimal.hpp"
|
#include <bstl/big_decimal.hpp>
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -6,16 +6,16 @@
|
|||||||
|
|
||||||
namespace bstl {
|
namespace bstl {
|
||||||
|
|
||||||
BigDecimal::BigDecimal() : unscaledValue_(0), scale_(0) {}
|
BigDecimal::BigDecimal() : m_unscaledValue(0), m_scale(0) {}
|
||||||
|
|
||||||
BigDecimal::BigDecimal(int value) : unscaledValue_(value), scale_(0) {}
|
BigDecimal::BigDecimal(int value) : m_unscaledValue(value), m_scale(0) {}
|
||||||
|
|
||||||
BigDecimal::BigDecimal(long long value) : unscaledValue_(value), scale_(0) {}
|
BigDecimal::BigDecimal(long long value) : m_unscaledValue(value), m_scale(0) {}
|
||||||
|
|
||||||
BigDecimal::BigDecimal(double value) : scale_(0) {
|
BigDecimal::BigDecimal(double value) : m_scale(0) {
|
||||||
if (value == 0.0) {
|
if (value == 0.0) {
|
||||||
unscaledValue_ = 0;
|
m_unscaledValue = 0;
|
||||||
scale_ = 0;
|
m_scale = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ BigDecimal::BigDecimal(double value) : scale_(0) {
|
|||||||
*this = BigDecimal(oss.str());
|
*this = BigDecimal(oss.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
BigDecimal::BigDecimal(const std::string& value) : unscaledValue_(0), scale_(0) {
|
BigDecimal::BigDecimal(const std::string& value) : m_unscaledValue(0), m_scale(0) {
|
||||||
if (value.empty()) {
|
if (value.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -46,12 +46,12 @@ BigDecimal::BigDecimal(const std::string& value) : unscaledValue_(0), scale_(0)
|
|||||||
// 查找小数点位置
|
// 查找小数点位置
|
||||||
size_t dotPos = text.find('.');
|
size_t dotPos = text.find('.');
|
||||||
if (dotPos != std::string::npos) {
|
if (dotPos != std::string::npos) {
|
||||||
scale_ = text.size() - dotPos - 1;
|
m_scale = static_cast<int>(text.size() - dotPos - 1);
|
||||||
std::string digits = text.substr(0, dotPos) + text.substr(dotPos + 1);
|
std::string digits = text.substr(0, dotPos) + text.substr(dotPos + 1);
|
||||||
unscaledValue_ = BigInteger(digits);
|
m_unscaledValue = BigInteger(digits);
|
||||||
} else {
|
} else {
|
||||||
scale_ = 0;
|
m_scale = 0;
|
||||||
unscaledValue_ = BigInteger(text);
|
m_unscaledValue = BigInteger(text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,26 +59,26 @@ BigDecimal::BigDecimal(const char* value)
|
|||||||
: BigDecimal(value == nullptr ? std::string("0") : std::string(value)) {}
|
: BigDecimal(value == nullptr ? std::string("0") : std::string(value)) {}
|
||||||
|
|
||||||
BigDecimal::BigDecimal(const BigInteger& unscaledValue, int scale)
|
BigDecimal::BigDecimal(const BigInteger& unscaledValue, int scale)
|
||||||
: unscaledValue_(unscaledValue), scale_(scale) {
|
: m_unscaledValue(unscaledValue), m_scale(scale) {
|
||||||
if (scale < 0) {
|
if (scale < 0) {
|
||||||
throw std::invalid_argument("scale cannot be negative");
|
throw std::invalid_argument("scale cannot be negative");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BigDecimal::isZero() const {
|
bool BigDecimal::isZero() const {
|
||||||
return unscaledValue_.isZero();
|
return m_unscaledValue.isZero();
|
||||||
}
|
}
|
||||||
|
|
||||||
int BigDecimal::sign() const {
|
int BigDecimal::sign() const {
|
||||||
return unscaledValue_.sign();
|
return m_unscaledValue.sign();
|
||||||
}
|
}
|
||||||
|
|
||||||
int BigDecimal::getScale() const {
|
int BigDecimal::getScale() const {
|
||||||
return scale_;
|
return m_scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
BigInteger BigDecimal::getUnscaledValue() const {
|
BigInteger BigDecimal::getUnscaledValue() const {
|
||||||
return unscaledValue_;
|
return m_unscaledValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string BigDecimal::toString() const {
|
std::string BigDecimal::toString() const {
|
||||||
@@ -86,7 +86,7 @@ std::string BigDecimal::toString() const {
|
|||||||
return "0";
|
return "0";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string digitStr = unscaledValue_.toString();
|
std::string digitStr = m_unscaledValue.toString();
|
||||||
|
|
||||||
// 处理符号
|
// 处理符号
|
||||||
bool negative = false;
|
bool negative = false;
|
||||||
@@ -96,26 +96,26 @@ std::string BigDecimal::toString() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 插入小数点
|
// 插入小数点
|
||||||
if (scale_ == 0) {
|
if (m_scale == 0) {
|
||||||
return (negative ? "-" : "") + digitStr;
|
return (negative ? "-" : "") + digitStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (static_cast<int>(digitStr.size()) <= scale_) {
|
if (static_cast<int>(digitStr.size()) <= m_scale) {
|
||||||
// 需要前置 "0."
|
// 需要前置 "0."
|
||||||
std::string result = "0.";
|
std::string result = "0.";
|
||||||
for (int i = 0; i < scale_ - static_cast<int>(digitStr.size()); i++) {
|
for (int i = 0; i < m_scale - static_cast<int>(digitStr.size()); i++) {
|
||||||
result += "0";
|
result += "0";
|
||||||
}
|
}
|
||||||
result += digitStr;
|
result += digitStr;
|
||||||
return (negative ? "-" : "") + result;
|
return (negative ? "-" : "") + result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dotPos = digitStr.size() - scale_;
|
int dotPos = static_cast<int>(digitStr.size()) - m_scale;
|
||||||
std::string result = digitStr.substr(0, dotPos) + "." + digitStr.substr(dotPos);
|
std::string result = digitStr.substr(0, dotPos) + "." + digitStr.substr(dotPos);
|
||||||
return (negative ? "-" : "") + result;
|
return (negative ? "-" : "") + result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BigDecimal::alignScale(BigInteger& lhs, int& lhsScale,
|
void BigDecimal::m_alignScale(BigInteger& lhs, int& lhsScale,
|
||||||
BigInteger& rhs, int& rhsScale) {
|
BigInteger& rhs, int& rhsScale) {
|
||||||
if (lhsScale < rhsScale) {
|
if (lhsScale < rhsScale) {
|
||||||
// 左边需要扩大
|
// 左边需要扩大
|
||||||
@@ -134,11 +134,11 @@ void BigDecimal::alignScale(BigInteger& lhs, int& lhsScale,
|
|||||||
|
|
||||||
bool BigDecimal::operator==(const BigDecimal& other) const {
|
bool BigDecimal::operator==(const BigDecimal& other) const {
|
||||||
if (isZero() && other.isZero()) return true;
|
if (isZero() && other.isZero()) return true;
|
||||||
BigInteger lhs = unscaledValue_;
|
BigInteger lhs = m_unscaledValue;
|
||||||
BigInteger rhs = other.unscaledValue_;
|
BigInteger rhs = other.m_unscaledValue;
|
||||||
int lhsScale = scale_;
|
int lhsScale = m_scale;
|
||||||
int rhsScale = other.scale_;
|
int rhsScale = other.m_scale;
|
||||||
alignScale(lhs, lhsScale, rhs, rhsScale);
|
m_alignScale(lhs, lhsScale, rhs, rhsScale);
|
||||||
return lhs == rhs;
|
return lhs == rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,17 +147,17 @@ bool BigDecimal::operator!=(const BigDecimal& other) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool BigDecimal::operator<(const BigDecimal& other) const {
|
bool BigDecimal::operator<(const BigDecimal& other) const {
|
||||||
if (unscaledValue_.sign() != other.unscaledValue_.sign()) {
|
if (m_unscaledValue.sign() != other.m_unscaledValue.sign()) {
|
||||||
return unscaledValue_.sign() < other.unscaledValue_.sign();
|
return m_unscaledValue.sign() < other.m_unscaledValue.sign();
|
||||||
}
|
}
|
||||||
|
|
||||||
BigInteger lhs = unscaledValue_;
|
BigInteger lhs = m_unscaledValue;
|
||||||
BigInteger rhs = other.unscaledValue_;
|
BigInteger rhs = other.m_unscaledValue;
|
||||||
int lhsScale = scale_;
|
int lhsScale = m_scale;
|
||||||
int rhsScale = other.scale_;
|
int rhsScale = other.m_scale;
|
||||||
alignScale(lhs, lhsScale, rhs, rhsScale);
|
m_alignScale(lhs, lhsScale, rhs, rhsScale);
|
||||||
|
|
||||||
if (unscaledValue_.sign() >= 0) {
|
if (m_unscaledValue.sign() >= 0) {
|
||||||
return lhs < rhs;
|
return lhs < rhs;
|
||||||
} else {
|
} else {
|
||||||
return lhs > rhs;
|
return lhs > rhs;
|
||||||
@@ -230,9 +230,9 @@ BigDecimal BigDecimal::operator+() const {
|
|||||||
|
|
||||||
BigDecimal BigDecimal::operator-() const {
|
BigDecimal BigDecimal::operator-() const {
|
||||||
if (isZero()) {
|
if (isZero()) {
|
||||||
return BigDecimal(0);
|
return {0};
|
||||||
}
|
}
|
||||||
return BigDecimal(-unscaledValue_, scale_);
|
return {-m_unscaledValue, m_scale};
|
||||||
}
|
}
|
||||||
|
|
||||||
BigDecimal& BigDecimal::operator+=(const BigDecimal& other) {
|
BigDecimal& BigDecimal::operator+=(const BigDecimal& other) {
|
||||||
@@ -259,13 +259,13 @@ BigDecimal BigDecimal::operator+(const BigDecimal& other) const {
|
|||||||
if (isZero()) return other;
|
if (isZero()) return other;
|
||||||
if (other.isZero()) return *this;
|
if (other.isZero()) return *this;
|
||||||
|
|
||||||
BigInteger lhs = unscaledValue_;
|
BigInteger lhs = m_unscaledValue;
|
||||||
BigInteger rhs = other.unscaledValue_;
|
BigInteger rhs = other.m_unscaledValue;
|
||||||
int lhsScale = scale_;
|
int lhsScale = m_scale;
|
||||||
int rhsScale = other.scale_;
|
int rhsScale = other.m_scale;
|
||||||
alignScale(lhs, lhsScale, rhs, rhsScale);
|
m_alignScale(lhs, lhsScale, rhs, rhsScale);
|
||||||
|
|
||||||
return BigDecimal(lhs + rhs, lhsScale);
|
return {lhs + rhs, lhsScale};
|
||||||
}
|
}
|
||||||
|
|
||||||
BigDecimal BigDecimal::operator-(const BigDecimal& other) const {
|
BigDecimal BigDecimal::operator-(const BigDecimal& other) const {
|
||||||
@@ -274,13 +274,13 @@ BigDecimal BigDecimal::operator-(const BigDecimal& other) const {
|
|||||||
|
|
||||||
BigDecimal BigDecimal::operator*(const BigDecimal& other) const {
|
BigDecimal BigDecimal::operator*(const BigDecimal& other) const {
|
||||||
if (isZero() || other.isZero()) {
|
if (isZero() || other.isZero()) {
|
||||||
return BigDecimal(0);
|
return {0};
|
||||||
}
|
}
|
||||||
|
|
||||||
BigInteger result = unscaledValue_ * other.unscaledValue_;
|
BigInteger result = m_unscaledValue * other.m_unscaledValue;
|
||||||
int resultScale = scale_ + other.scale_;
|
int resultScale = m_scale + other.m_scale;
|
||||||
|
|
||||||
return BigDecimal(result, resultScale);
|
return {result, resultScale};
|
||||||
}
|
}
|
||||||
|
|
||||||
BigDecimal BigDecimal::operator/(const BigDecimal& other) const {
|
BigDecimal BigDecimal::operator/(const BigDecimal& other) const {
|
||||||
@@ -289,14 +289,14 @@ BigDecimal BigDecimal::operator/(const BigDecimal& other) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isZero()) {
|
if (isZero()) {
|
||||||
return BigDecimal(0);
|
return {0};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 先对齐 scale,然后做整数除法
|
// 先对齐 scale,然后做整数除法
|
||||||
BigInteger lhs = unscaledValue_;
|
BigInteger lhs = m_unscaledValue;
|
||||||
BigInteger rhs = other.unscaledValue_;
|
BigInteger rhs = other.m_unscaledValue;
|
||||||
int lhsScale = scale_;
|
int lhsScale = m_scale;
|
||||||
int rhsScale = other.scale_;
|
int rhsScale = other.m_scale;
|
||||||
|
|
||||||
// 使用更高的精度进行除法
|
// 使用更高的精度进行除法
|
||||||
// 乘以 10^precision 来获得更多的精度
|
// 乘以 10^precision 来获得更多的精度
|
||||||
@@ -308,14 +308,14 @@ BigDecimal BigDecimal::operator/(const BigDecimal& other) const {
|
|||||||
BigInteger quotient = lhs / rhs;
|
BigInteger quotient = lhs / rhs;
|
||||||
int resultScale = lhsScale - rhsScale + precision;
|
int resultScale = lhsScale - rhsScale + precision;
|
||||||
|
|
||||||
return BigDecimal(quotient, resultScale);
|
return {quotient, resultScale};
|
||||||
}
|
}
|
||||||
|
|
||||||
BigDecimal BigDecimal::abs() const {
|
BigDecimal BigDecimal::abs() const {
|
||||||
if (unscaledValue_.sign() >= 0) {
|
if (m_unscaledValue.sign() >= 0) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
return BigDecimal(-unscaledValue_, scale_);
|
return {-m_unscaledValue, m_scale};
|
||||||
}
|
}
|
||||||
|
|
||||||
BigDecimal BigDecimal::round(int scale) const {
|
BigDecimal BigDecimal::round(int scale) const {
|
||||||
@@ -323,19 +323,30 @@ BigDecimal BigDecimal::round(int scale) const {
|
|||||||
throw std::invalid_argument("scale cannot be negative");
|
throw std::invalid_argument("scale cannot be negative");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scale >= scale_) {
|
if (scale >= m_scale) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 简单实现:直接截断到指定小数位数
|
// 简单实现:直接截断到指定小数位数
|
||||||
int diff = scale_ - scale;
|
int diff = m_scale - scale;
|
||||||
BigInteger divisor = BigInteger(10);
|
BigInteger divisor = BigInteger(10);
|
||||||
for (int i = 1; i < diff; i++) {
|
for (int i = 1; i < diff; i++) {
|
||||||
divisor = divisor * BigInteger(10);
|
divisor = divisor * BigInteger(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
BigInteger rounded = unscaledValue_ / divisor;
|
BigInteger rounded = m_unscaledValue / divisor;
|
||||||
return BigDecimal(rounded, scale);
|
return {rounded, scale};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const BigDecimal& bd) {
|
||||||
|
return os << bd.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istream& operator>>(std::istream& is, BigDecimal& bd) {
|
||||||
|
std::string str;
|
||||||
|
is >> str;
|
||||||
|
bd = BigDecimal(str);
|
||||||
|
return is;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace bstl
|
} // namespace bstl
|
||||||
@@ -0,0 +1,447 @@
|
|||||||
|
#include <bstl/big_integer.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace bstl {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
std::vector<int> toDigits(unsigned long long value) {
|
||||||
|
std::vector<int> digits;
|
||||||
|
while (value > 0) {
|
||||||
|
digits.push_back(static_cast<int>(value % 10));
|
||||||
|
value /= 10;
|
||||||
|
}
|
||||||
|
return digits;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::vector<int> BigInteger::m_trimLeadingZeros(const std::vector<int>& value) {
|
||||||
|
size_t end = value.size();
|
||||||
|
while (end > 0 && value[end - 1] == 0) {
|
||||||
|
--end;
|
||||||
|
}
|
||||||
|
std::vector<int> result(value);
|
||||||
|
result.resize(end);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BigInteger::m_compareAbs(const std::vector<int>& a, const std::vector<int>& b) {
|
||||||
|
std::vector<int> ta = m_trimLeadingZeros(a);
|
||||||
|
std::vector<int> 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<int> BigInteger::m_addAbs(const std::vector<int>& a, const std::vector<int>& b) {
|
||||||
|
std::vector<int> ta = m_trimLeadingZeros(a);
|
||||||
|
std::vector<int> tb = m_trimLeadingZeros(b);
|
||||||
|
std::vector<int> 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<int> BigInteger::m_subAbs(const std::vector<int>& a, const std::vector<int>& b) {
|
||||||
|
std::vector<int> ta = m_trimLeadingZeros(a);
|
||||||
|
std::vector<int> tb = m_trimLeadingZeros(b);
|
||||||
|
if (m_compareAbs(ta, tb) < 0) {
|
||||||
|
return m_subAbs(tb, ta);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> result;
|
||||||
|
result.reserve(ta.size());
|
||||||
|
|
||||||
|
int borrow = 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;
|
||||||
|
borrow = 1;
|
||||||
|
} else {
|
||||||
|
borrow = 0;
|
||||||
|
}
|
||||||
|
result.push_back(diff);
|
||||||
|
}
|
||||||
|
return m_trimLeadingZeros(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> BigInteger::m_mulAbs(const std::vector<int>& a, const std::vector<int>& b) {
|
||||||
|
std::vector<int> ta = m_trimLeadingZeros(a);
|
||||||
|
std::vector<int> tb = m_trimLeadingZeros(b);
|
||||||
|
if (ta.empty() || tb.empty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
product[i + j] += ta[i] * tb[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int carry = 0;
|
||||||
|
for (int& digit : product) {
|
||||||
|
const int sum = digit + carry;
|
||||||
|
digit = sum % 10;
|
||||||
|
carry = sum / 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_trimLeadingZeros(product);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> BigInteger::m_divAbs(const std::vector<int>& a, const std::vector<int>& b) {
|
||||||
|
std::vector<int> tb = m_trimLeadingZeros(b);
|
||||||
|
if (tb.empty()) {
|
||||||
|
throw std::invalid_argument("division by zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> ta = m_trimLeadingZeros(a);
|
||||||
|
if (m_compareAbs(ta, tb) < 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> quotientHigh;
|
||||||
|
std::vector<int> 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;
|
||||||
|
}
|
||||||
|
quotientHigh.push_back(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::reverse(quotientHigh.begin(), quotientHigh.end());
|
||||||
|
return m_trimLeadingZeros(quotientHigh);
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger::BigInteger() : m_sign(0) {}
|
||||||
|
|
||||||
|
BigInteger::BigInteger(int value) : m_sign(0) {
|
||||||
|
if (value == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto v = static_cast<long long>(value);
|
||||||
|
if (v < 0) {
|
||||||
|
m_sign = -1;
|
||||||
|
v = -v;
|
||||||
|
} else {
|
||||||
|
m_sign = 1;
|
||||||
|
}
|
||||||
|
m_digits = toDigits(static_cast<unsigned long long>(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger::BigInteger(long long value) : m_sign(0) {
|
||||||
|
if (value == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long magnitude = 0;
|
||||||
|
if (value < 0) {
|
||||||
|
m_sign = -1;
|
||||||
|
magnitude = static_cast<unsigned long long>(-(value + 1)) + 1ULL;
|
||||||
|
} else {
|
||||||
|
m_sign = 1;
|
||||||
|
magnitude = static_cast<unsigned long long>(value);
|
||||||
|
}
|
||||||
|
m_digits = toDigits(magnitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger::BigInteger(unsigned long long value) : m_sign(0) {
|
||||||
|
if (value == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_sign = 1;
|
||||||
|
m_digits = toDigits(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger::BigInteger(const std::string& value) : m_sign(0) {
|
||||||
|
if (value.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string text = value;
|
||||||
|
m_sign = 1;
|
||||||
|
if (text[0] == '-') {
|
||||||
|
m_sign = -1;
|
||||||
|
text = text.substr(1);
|
||||||
|
} else if (text[0] == '+') {
|
||||||
|
text = text.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text.empty()) {
|
||||||
|
m_sign = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (char ch : text) {
|
||||||
|
if (ch < '0' || ch > '9') {
|
||||||
|
throw std::invalid_argument("BigInteger: invalid numeric string");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger::BigInteger(const char* value)
|
||||||
|
: BigInteger(value == nullptr ? std::string("0") : std::string(value)) {}
|
||||||
|
|
||||||
|
bool BigInteger::isZero() const {
|
||||||
|
return m_sign == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BigInteger::sign() const {
|
||||||
|
return m_sign;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BigInteger::toString() const {
|
||||||
|
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<char>('0' + *it));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BigInteger::operator==(const BigInteger& other) const {
|
||||||
|
if (isZero() && other.isZero()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return m_sign == other.m_sign && m_digits == other.m_digits;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BigInteger::operator!=(const BigInteger& other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
const int cmp = m_compareAbs(m_digits, other.m_digits);
|
||||||
|
return m_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 {0};
|
||||||
|
}
|
||||||
|
BigInteger result(*this);
|
||||||
|
result.m_sign = -result.m_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 (m_sign == other.m_sign) {
|
||||||
|
result.m_digits = m_addAbs(m_digits, other.m_digits);
|
||||||
|
result.m_sign = m_sign;
|
||||||
|
} else {
|
||||||
|
const int cmp = m_compareAbs(m_digits, other.m_digits);
|
||||||
|
if (cmp == 0) {
|
||||||
|
result.m_digits.clear();
|
||||||
|
result.m_sign = 0;
|
||||||
|
} else if (cmp > 0) {
|
||||||
|
result.m_digits = m_subAbs(m_digits, other.m_digits);
|
||||||
|
result.m_sign = m_sign;
|
||||||
|
} else {
|
||||||
|
result.m_digits = m_subAbs(other.m_digits, m_digits);
|
||||||
|
result.m_sign = other.m_sign;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result.m_digits.empty()) {
|
||||||
|
result.m_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 {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.empty()) {
|
||||||
|
result.m_sign = 0;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger BigInteger::operator/(const BigInteger& other) const {
|
||||||
|
if (other.isZero()) {
|
||||||
|
throw std::invalid_argument("division by zero");
|
||||||
|
}
|
||||||
|
if (isZero()) {
|
||||||
|
return {0};
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger result;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const BigInteger& bi) {
|
||||||
|
return os << bi.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istream& operator>>(std::istream& is, BigInteger& bi) {
|
||||||
|
std::string str;
|
||||||
|
is >> str;
|
||||||
|
bi = BigInteger(str);
|
||||||
|
return is;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace bstl
|
||||||
+358
@@ -0,0 +1,358 @@
|
|||||||
|
#include "bstl/string.hpp"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace bstl {
|
||||||
|
|
||||||
|
String::String() = default;
|
||||||
|
|
||||||
|
String::String(std::string str) : m_data(std::move(str)) {}
|
||||||
|
|
||||||
|
String::String(const char* str) : m_data(str == nullptr ? "" : str) {}
|
||||||
|
|
||||||
|
std::string String::str() const {
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* String::c_str() const {
|
||||||
|
return m_data.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t String::length() const {
|
||||||
|
return m_data.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t String::size() const {
|
||||||
|
return m_data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::empty() const {
|
||||||
|
return m_data.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
char String::at(size_t pos) const {
|
||||||
|
if (pos >= m_data.size()) {
|
||||||
|
throw std::out_of_range("String::at: index out of range");
|
||||||
|
}
|
||||||
|
return m_data[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
char String::operator[](size_t pos) const {
|
||||||
|
return m_data[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
char& String::operator[](size_t pos) {
|
||||||
|
return m_data[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<String> String::split(const String& delimiter) const {
|
||||||
|
std::vector<String> result;
|
||||||
|
|
||||||
|
if (m_data.empty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delimiter.empty()) {
|
||||||
|
result.push_back(*this);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t start = 0;
|
||||||
|
size_t pos = 0;
|
||||||
|
|
||||||
|
while ((pos = m_data.find(delimiter.m_data, start)) != std::string::npos) {
|
||||||
|
result.emplace_back(m_data.substr(start, pos - start));
|
||||||
|
start = pos + delimiter.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
result.emplace_back(m_data.substr(start));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::join(const std::vector<String>& parts, const String& delimiter) {
|
||||||
|
if (parts.empty()) {
|
||||||
|
return {""};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string result = parts[0].str();
|
||||||
|
for (size_t i = 1; i < parts.size(); i++) {
|
||||||
|
result += delimiter.str() + parts[i].str();
|
||||||
|
}
|
||||||
|
return {result};
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::replace(const String& oldStr, const String& newStr, int count) const {
|
||||||
|
if (oldStr.empty()) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string result = m_data;
|
||||||
|
size_t pos = 0;
|
||||||
|
int replaced = 0;
|
||||||
|
|
||||||
|
while ((pos = result.find(oldStr.m_data, pos)) != std::string::npos && (count < 0 || replaced < count)) {
|
||||||
|
result.replace(pos, oldStr.size(), newStr.str());
|
||||||
|
pos += newStr.size();
|
||||||
|
replaced++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {result};
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::upper() const {
|
||||||
|
std::string result = m_data;
|
||||||
|
std::transform(result.begin(), result.end(), result.begin(),
|
||||||
|
[](unsigned char c) { return std::toupper(c); });
|
||||||
|
return {result};
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::lower() const {
|
||||||
|
std::string result = m_data;
|
||||||
|
std::transform(result.begin(), result.end(), result.begin(),
|
||||||
|
[](unsigned char c) { return std::tolower(c); });
|
||||||
|
return {result};
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::capitalize() const {
|
||||||
|
if (m_data.empty()) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
std::string result = m_data;
|
||||||
|
result[0] = static_cast<char>(std::toupper(static_cast<unsigned char>(result[0])));
|
||||||
|
for (size_t i = 1; i < result.size(); i++) {
|
||||||
|
result[i] = static_cast<char>(std::tolower(static_cast<unsigned char>(result[i])));
|
||||||
|
}
|
||||||
|
return {result};
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::title() const {
|
||||||
|
std::string result = m_data;
|
||||||
|
bool newWord = true;
|
||||||
|
for (char & i : result) {
|
||||||
|
if (std::isspace(static_cast<unsigned char>(i))) {
|
||||||
|
newWord = true;
|
||||||
|
} else {
|
||||||
|
if (newWord) {
|
||||||
|
i = static_cast<char>(std::toupper(static_cast<unsigned char>(i)));
|
||||||
|
newWord = false;
|
||||||
|
} else {
|
||||||
|
i = static_cast<char>(std::tolower(static_cast<unsigned char>(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {result};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::startswith(const String& prefix) const {
|
||||||
|
if (prefix.size() > m_data.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return m_data.compare(0, prefix.size(), prefix.m_data) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::endswith(const String& suffix) const {
|
||||||
|
if (suffix.size() > m_data.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return m_data.compare(m_data.size() - suffix.size(), suffix.size(), suffix.m_data) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::contains(const String& substring) const {
|
||||||
|
return m_data.find(substring.m_data) != std::string::npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::isdigit() const {
|
||||||
|
return !m_data.empty() &&
|
||||||
|
std::all_of(m_data.begin(), m_data.end(),
|
||||||
|
[](unsigned char c) { return std::isdigit(c) != 0; });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::isalpha() const {
|
||||||
|
return !m_data.empty() &&
|
||||||
|
std::all_of(m_data.begin(), m_data.end(),
|
||||||
|
[](unsigned char c) { return std::isalpha(c) != 0; });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::isalnum() const {
|
||||||
|
return !m_data.empty() &&
|
||||||
|
std::all_of(m_data.begin(), m_data.end(),
|
||||||
|
[](unsigned char c) { return std::isalnum(c) != 0; });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::isspace() const {
|
||||||
|
return !m_data.empty() &&
|
||||||
|
std::all_of(m_data.begin(), m_data.end(),
|
||||||
|
[](unsigned char c) { return std::isspace(c) != 0; });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::isupper() const {
|
||||||
|
return !m_data.empty() &&
|
||||||
|
std::all_of(m_data.begin(), m_data.end(),
|
||||||
|
[](unsigned char c) { return !std::isalpha(c) || std::isupper(c) != 0; });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::islower() const {
|
||||||
|
return !m_data.empty() &&
|
||||||
|
std::all_of(m_data.begin(), m_data.end(),
|
||||||
|
[](unsigned char c) { return !std::isalpha(c) || std::islower(c) != 0; });
|
||||||
|
}
|
||||||
|
|
||||||
|
int String::find(const String& substring, size_t start) const {
|
||||||
|
size_t pos = m_data.find(substring.m_data, start);
|
||||||
|
return pos == std::string::npos ? -1 : static_cast<int>(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
int String::rfind(const String& substring) const {
|
||||||
|
size_t pos = m_data.rfind(substring.m_data);
|
||||||
|
return pos == std::string::npos ? -1 : static_cast<int>(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
int String::count(const String& substring) const {
|
||||||
|
if (substring.empty()) return 0;
|
||||||
|
int count = 0;
|
||||||
|
size_t pos = 0;
|
||||||
|
while ((pos = m_data.find(substring.m_data, pos)) != std::string::npos) {
|
||||||
|
count++;
|
||||||
|
pos += substring.size();
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::strip() const {
|
||||||
|
size_t start = 0;
|
||||||
|
size_t end = m_data.size();
|
||||||
|
|
||||||
|
while (start < end && std::isspace(static_cast<unsigned char>(m_data[start]))) {
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
while (end > start && std::isspace(static_cast<unsigned char>(m_data[end - 1]))) {
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {m_data.substr(start, end - start)};
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::lstrip() const {
|
||||||
|
size_t start = 0;
|
||||||
|
while (start < m_data.size() && std::isspace(static_cast<unsigned char>(m_data[start]))) {
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
return {m_data.substr(start)};
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::rstrip() const {
|
||||||
|
size_t end = m_data.size();
|
||||||
|
while (end > 0 && std::isspace(static_cast<unsigned char>(m_data[end - 1]))) {
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
return {m_data.substr(0, end)};
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::strip(const String& chars) const {
|
||||||
|
size_t start = 0;
|
||||||
|
size_t end = m_data.size();
|
||||||
|
|
||||||
|
while (start < end && chars.m_data.find(m_data[start]) != std::string::npos) {
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
while (end > start && chars.m_data.find(m_data[end - 1]) != std::string::npos) {
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {m_data.substr(start, end - start)};
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::ljust(size_t width, char fillchar) const {
|
||||||
|
if (m_data.size() >= width) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
std::string result = m_data;
|
||||||
|
result.append(width - m_data.size(), fillchar);
|
||||||
|
return {result};
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::rjust(size_t width, char fillchar) const {
|
||||||
|
if (m_data.size() >= width) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
std::string result(width - m_data.size(), fillchar);
|
||||||
|
result.append(m_data);
|
||||||
|
return {result};
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::center(size_t width, char fillchar) const {
|
||||||
|
if (m_data.size() >= width) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
size_t totalPad = width - m_data.size();
|
||||||
|
size_t leftPad = totalPad / 2;
|
||||||
|
size_t rightPad = totalPad - leftPad;
|
||||||
|
std::string result(leftPad, fillchar);
|
||||||
|
result.append(m_data);
|
||||||
|
result.append(rightPad, fillchar);
|
||||||
|
return {result};
|
||||||
|
}
|
||||||
|
|
||||||
|
int String::toInt() const {
|
||||||
|
return std::stoi(m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
long long String::toLongLong() const {
|
||||||
|
return std::stoll(m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
double String::toDouble() const {
|
||||||
|
return std::stod(m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::operator+(const String& other) const {
|
||||||
|
return {m_data + other.m_data};
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::operator+(const char* str) const {
|
||||||
|
return {m_data + (str == nullptr ? "" : str)};
|
||||||
|
}
|
||||||
|
|
||||||
|
String& String::operator+=(const String& other) {
|
||||||
|
m_data += other.m_data;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::operator==(const String& other) const {
|
||||||
|
return m_data == other.m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::operator!=(const String& other) const {
|
||||||
|
return m_data != other.m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::operator<(const String& other) const {
|
||||||
|
return m_data < other.m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::operator>(const String& other) const {
|
||||||
|
return m_data > other.m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::operator<=(const String& other) const {
|
||||||
|
return m_data <= other.m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::operator>=(const String& other) const {
|
||||||
|
return m_data >= other.m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const String& str) {
|
||||||
|
return os << str.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istream& operator>>(std::istream& is, String& str) {
|
||||||
|
std::string temp;
|
||||||
|
is >> temp;
|
||||||
|
str = String(temp);
|
||||||
|
return is;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace bstl
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
#include <bstl/big_integer.hpp>
|
||||||
|
#include <bstl/big_decimal.hpp>
|
||||||
|
#include <bstl/string.hpp>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
using bstl::BigInteger;
|
||||||
|
using bstl::BigDecimal;
|
||||||
|
using bstl::String;
|
||||||
|
|
||||||
|
// 测试 BigInteger 的 cout
|
||||||
|
BigInteger bi1("12345678901234567890");
|
||||||
|
std::ostringstream oss1;
|
||||||
|
oss1 << bi1;
|
||||||
|
assert(oss1.str() == "12345678901234567890");
|
||||||
|
|
||||||
|
// 测试 BigInteger 的 cin
|
||||||
|
std::istringstream iss1("987654321");
|
||||||
|
BigInteger bi2;
|
||||||
|
iss1 >> bi2;
|
||||||
|
assert(bi2.toString() == "987654321");
|
||||||
|
|
||||||
|
// 测试负数
|
||||||
|
std::istringstream iss2("-555");
|
||||||
|
BigInteger bi3;
|
||||||
|
iss2 >> bi3;
|
||||||
|
assert(bi3.toString() == "-555");
|
||||||
|
|
||||||
|
// 测试 BigDecimal 的 cout
|
||||||
|
BigDecimal bd1("123.45");
|
||||||
|
std::ostringstream oss2;
|
||||||
|
oss2 << bd1;
|
||||||
|
assert(oss2.str() == "123.45");
|
||||||
|
|
||||||
|
// 测试 BigDecimal 的 cin
|
||||||
|
std::istringstream iss3("67.89");
|
||||||
|
BigDecimal bd2;
|
||||||
|
iss3 >> bd2;
|
||||||
|
assert(bd2.toString() == "67.89");
|
||||||
|
|
||||||
|
// 测试负小数
|
||||||
|
std::istringstream iss4("-12.34");
|
||||||
|
BigDecimal bd3;
|
||||||
|
iss4 >> bd3;
|
||||||
|
assert(bd3.toString() == "-12.34");
|
||||||
|
|
||||||
|
// 测试 String 的 cout
|
||||||
|
String s1("Hello World");
|
||||||
|
std::ostringstream oss3;
|
||||||
|
oss3 << s1;
|
||||||
|
assert(oss3.str() == "Hello World");
|
||||||
|
|
||||||
|
// 测试 String 的 cin
|
||||||
|
std::istringstream iss5("HelloWorld");
|
||||||
|
String s2;
|
||||||
|
iss5 >> s2;
|
||||||
|
assert(s2.str() == "HelloWorld");
|
||||||
|
|
||||||
|
std::cout << "All cin/cout tests passed!\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
#include <bstl/string.hpp>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
using bstl::String;
|
||||||
|
|
||||||
|
// 基本构造和获取
|
||||||
|
String s1("Hello, World!");
|
||||||
|
assert(s1.length() == 13);
|
||||||
|
assert(s1.c_str() == std::string("Hello, World!"));
|
||||||
|
|
||||||
|
// split 分割
|
||||||
|
String s2("apple,banana,cherry");
|
||||||
|
auto parts = s2.split(",");
|
||||||
|
assert(parts.size() == 3);
|
||||||
|
assert(parts[0] == String("apple"));
|
||||||
|
assert(parts[1] == String("banana"));
|
||||||
|
assert(parts[2] == String("cherry"));
|
||||||
|
|
||||||
|
// join 连接
|
||||||
|
std::vector<String> words = {String("Hello"), String("World")};
|
||||||
|
String joined = String::join(words, " ");
|
||||||
|
assert(joined == String("Hello World"));
|
||||||
|
|
||||||
|
// replace 替换
|
||||||
|
String s3("hello hello world");
|
||||||
|
String replaced = s3.replace("hello", "hi");
|
||||||
|
assert(replaced == String("hi hi world"));
|
||||||
|
|
||||||
|
String replaced1 = s3.replace("hello", "hi", 1);
|
||||||
|
assert(replaced1 == String("hi hello world"));
|
||||||
|
|
||||||
|
// upper/lower
|
||||||
|
String s4("HeLLo WoRLd");
|
||||||
|
assert(s4.upper() == String("HELLO WORLD"));
|
||||||
|
assert(s4.lower() == String("hello world"));
|
||||||
|
|
||||||
|
// capitalize
|
||||||
|
String s5("hello");
|
||||||
|
assert(s5.capitalize() == String("Hello"));
|
||||||
|
|
||||||
|
// title
|
||||||
|
String s6("hello world");
|
||||||
|
assert(s6.title() == String("Hello World"));
|
||||||
|
|
||||||
|
// startswith/endswith
|
||||||
|
String s7("hello.txt");
|
||||||
|
assert(s7.startswith("hello"));
|
||||||
|
assert(s7.endswith(".txt"));
|
||||||
|
assert(!s7.startswith(".txt"));
|
||||||
|
|
||||||
|
// contains
|
||||||
|
assert(s7.contains("llo"));
|
||||||
|
assert(!s7.contains("xyz"));
|
||||||
|
|
||||||
|
// isdigit/isalpha/isalnum
|
||||||
|
assert(String("12345").isdigit());
|
||||||
|
assert(!String("123a").isdigit());
|
||||||
|
assert(String("abc").isalpha());
|
||||||
|
assert(!String("abc1").isalpha());
|
||||||
|
assert(String("abc123").isalnum());
|
||||||
|
|
||||||
|
// isupper/islower
|
||||||
|
assert(String("HELLO").isupper());
|
||||||
|
assert(String("hello").islower());
|
||||||
|
assert(!String("Hello").isupper());
|
||||||
|
|
||||||
|
// find/rfind/count
|
||||||
|
assert(s2.find("banana") == 6);
|
||||||
|
assert(s2.find("xyz") == -1);
|
||||||
|
assert(s3.count("hello") == 2);
|
||||||
|
|
||||||
|
// strip
|
||||||
|
String s8(" hello world ");
|
||||||
|
assert(s8.strip() == String("hello world"));
|
||||||
|
assert(s8.lstrip() == String("hello world "));
|
||||||
|
assert(s8.rstrip() == String(" hello world"));
|
||||||
|
|
||||||
|
// ljust/rjust/center
|
||||||
|
String s9("hi");
|
||||||
|
assert(s9.ljust(5, '.') == String("hi..."));
|
||||||
|
assert(s9.rjust(5, '.') == String("...hi"));
|
||||||
|
assert(s9.center(5, '.') == String(".hi.."));
|
||||||
|
|
||||||
|
// 字符串转换
|
||||||
|
assert(String("123").toInt() == 123);
|
||||||
|
assert(String("456789").toLongLong() == 456789);
|
||||||
|
assert(String("3.14").toDouble() == 3.14);
|
||||||
|
|
||||||
|
// 运算符
|
||||||
|
String sa("Hello");
|
||||||
|
String sb(" World");
|
||||||
|
String sc = sa + sb;
|
||||||
|
assert(sc == String("Hello World"));
|
||||||
|
|
||||||
|
sa += sb;
|
||||||
|
assert(sa == String("Hello World"));
|
||||||
|
|
||||||
|
// 比较
|
||||||
|
assert(String("abc") < String("def"));
|
||||||
|
assert(String("xyz") > String("abc"));
|
||||||
|
|
||||||
|
std::cout << "All String tests passed!\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include <BigDecimal.hpp>
|
#include <bstl/big_decimal.hpp>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include <BigInteger.hpp>
|
#include <bstl/big_integer.hpp>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -7,19 +7,19 @@
|
|||||||
int main() {
|
int main() {
|
||||||
using bstl::BigInteger;
|
using bstl::BigInteger;
|
||||||
|
|
||||||
BigInteger a("12345678901234567890");
|
const BigInteger a("12345678901234567890");
|
||||||
BigInteger b("98765432109876543210");
|
const BigInteger b("98765432109876543210");
|
||||||
BigInteger c = a + b;
|
const BigInteger c = a + b;
|
||||||
BigInteger d = b - a;
|
const BigInteger d = b - a;
|
||||||
BigInteger e = a * BigInteger("2");
|
const BigInteger e = a * BigInteger("2");
|
||||||
BigInteger f = BigInteger("100000000000000000000000") / BigInteger("1000000000000000000");
|
const BigInteger f = BigInteger("100000000000000000000000") / BigInteger("1000000000000000000");
|
||||||
|
|
||||||
assert(c.toString() == "111111111011111111100");
|
assert(c.toString() == "111111111011111111100");
|
||||||
assert(d.toString() == "86419753208641975320");
|
assert(d.toString() == "86419753208641975320");
|
||||||
assert(e.toString() == "24691357802469135780");
|
assert(e.toString() == "24691357802469135780");
|
||||||
assert(f.toString() == "100000");
|
assert(f.toString() == "100000");
|
||||||
|
|
||||||
BigInteger zero("0");
|
const BigInteger zero("0");
|
||||||
assert((a == a) == true);
|
assert((a == a) == true);
|
||||||
assert((a != b) == true);
|
assert((a != b) == true);
|
||||||
assert((zero == 0) == true);
|
assert((zero == 0) == true);
|
||||||
Reference in New Issue
Block a user