diff --git a/.github/workflows/CI-CD.yml b/.github/workflows/CI-CD.yml index 76112d3..80293a4 100644 --- a/.github/workflows/CI-CD.yml +++ b/.github/workflows/CI-CD.yml @@ -40,13 +40,13 @@ jobs: echo "CXX=g++-13" >> $GITHUB_ENV echo "CC=gcc-13" >> $GITHUB_ENV - - name: Set up Clang 17 + - name: Set up Clang 18 if: matrix.compiler == 'clang' run: | sudo apt-get update - sudo apt-get install -y clang-17 - echo "CXX=clang++-17" >> $GITHUB_ENV - echo "CC=clang-17" >> $GITHUB_ENV + sudo apt-get install -y clang-18 + echo "CXX=clang++-18" >> $GITHUB_ENV + echo "CC=clang-18" >> $GITHUB_ENV - name: Configure CMake shell: bash diff --git a/bigint.h b/bigint.h index 43725b3..936be5f 100644 --- a/bigint.h +++ b/bigint.h @@ -45,7 +45,7 @@ namespace BigInt { { public: // LLONG_MAX = 9'223'372'036'854'775'807 - static constexpr auto MAX_SIZE = 1'000'000'000'000'000'000LL; + static constexpr auto MAX_SIZE = 1000000000LL; bigint() : vec({0}) {} @@ -77,13 +77,13 @@ namespace BigInt { } } - bigint(const unsigned int n) : bigint(static_cast(n)) {} - - bigint(const int n) : bigint(static_cast(n)) {} - - bigint(const long n) : bigint(static_cast(n)) {} + bigint(const char* n) : bigint(std::string(n)) {} - bigint(const double n) : bigint(static_cast(n)) {} + bigint(const int n) : bigint(static_cast(n)) {} + bigint(const unsigned int n) : bigint(static_cast(n)) {} + bigint(const long n) : bigint(static_cast(n)) {} + bigint(const unsigned long n) : bigint(static_cast(n)) {} + bigint(const double n) : bigint(static_cast(n)) {} bigint(const long long n): is_neg(n < 0) { if (n == 0) { @@ -116,8 +116,6 @@ namespace BigInt { bigint(const bigint& n) = default; - bigint(const char* n) : bigint(std::string(n)) {} - /* If initializing from a vector that should be negative, the negative value must be set afterward. * bigint alpha(std::vector(...)); * -alpha; @@ -371,9 +369,7 @@ namespace BigInt { bool is_neg{false}; std::vector vec; - // Function Definitions for Internal Uses - static bigint trim(bigint input) { while (input.vec.size() > 1 && input.vec.front() == 0) { input.vec.erase(input.vec.begin()); @@ -454,7 +450,6 @@ namespace BigInt { } }; - inline bool bigint::is_bigint(const std::string& s) { if (s.empty()) return false; @@ -591,8 +586,7 @@ namespace BigInt { for (auto it_lhs = lhs.vec.rbegin(); it_lhs != lhs.vec.rend(); ++it_lhs) { for (auto it_rhs = rhs.vec.rbegin(); it_rhs != rhs.vec.rend(); ++it_rhs) { // Calculate the product and the corresponding indices in the result vector - // use 128 bits to carefully store overflow - __int128 mul = static_cast<__int128>(*it_lhs) * static_cast<__int128>(*it_rhs); + long long mul = (*it_lhs) * (*it_rhs); auto pos_low_it = result.rbegin() + (std::distance(lhs.vec.rbegin(), it_lhs) + std::distance( rhs.vec.rbegin(), it_rhs)); auto pos_high_it = pos_low_it + 1; @@ -705,7 +699,6 @@ namespace BigInt { return answer; } - inline bigint bigint::log2(const bigint& input) { if (is_negative(input) || input == 0) throw std::domain_error("Invalid input for natural log"); @@ -847,14 +840,16 @@ namespace BigInt { } inline std::vector bigint::string_to_vector(std::string input) { - // Break into chunks of 18 characters + // Break into chunks of 9 characters std::vector result; - constexpr int chunk_size = 18; + constexpr int chunk_size = 9; const int size = input.size(); if (size > chunk_size) { // Pad the length to get appropriate sized chunks - input.insert(0, chunk_size - (size % chunk_size), '0'); + if (int mod = size % chunk_size; mod != 0) { + input.insert(0, chunk_size - mod, '0'); + } } for (int i = 0; i < input.size(); i += chunk_size) { std::string temp_str = input.substr(i, chunk_size); @@ -878,8 +873,8 @@ namespace BigInt { else throw std::runtime_error("Invalid hex character."); // Multiply current value by 16 and add digit. - // Max intermediate value: (MAX_SIZE-1)*16+15 = 15,999,999,999,999,999,999 - // which fits in unsigned long long (max ~18.4 * 10^18). + // Max intermediate value: (MAX_SIZE-1)*16+15 = 15,999,999,999 + // which fits in unsigned long long. unsigned long long carry = digit; for (int i = static_cast(result.size()) - 1; i >= 0; --i) { const unsigned long long val = static_cast(result[i]) * 16 + carry; @@ -905,7 +900,7 @@ namespace BigInt { first = false; } else { - ss << std::setw(18) << std::setfill('0') << partial; // Pad to 18 digits + ss << std::setw(9) << std::setfill('0') << partial; // Pad to 9 digits } } return ss.str(); @@ -920,7 +915,7 @@ namespace BigInt { template<> struct std::hash { - std::size_t operator()(const BigInt::bigint& input) const { + std::size_t operator()(const BigInt::bigint& input) const noexcept { std::size_t seed = input.vec.size(); for (auto x : input.vec) { x = ((x >> 16) ^ x) * 0x45d9f3b; diff --git a/tests/test.cpp b/tests/test.cpp index 2d86402..1b660fc 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -74,8 +74,8 @@ static auto measure_execution = [](const int count, const char* label, const siz class Test_BigInt_Performance : public ::testing::Test { protected: - static constexpr size_t number_count = 500; - const std::vector sizes = {5, 20, 50, 100, 1000, 10'000, 100'000, 1'000'000}; + static constexpr size_t number_count = 2; + const std::vector sizes = {10, 100, 1000, 10000, 50000}; volatile int dce_sink = 0; void SetUp() override {