From 3d2bd0ba52e52f12cba4dbbd616ddb8075d7e58f Mon Sep 17 00:00:00 2001 From: Rinzii Date: Sat, 6 Apr 2024 19:08:15 -0400 Subject: [PATCH] Begin initial work on creating usable big_int type --- ccmath_headers.cmake | 1 + include/ccmath/internal/types/big_int.hpp | 93 +++++++++++++++++++++++ test/CMakeLists.txt | 15 +++- test/internal/types/big_int_test.cpp | 22 ++++++ 4 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 include/ccmath/internal/types/big_int.hpp create mode 100644 test/internal/types/big_int_test.cpp diff --git a/ccmath_headers.cmake b/ccmath_headers.cmake index efd866ac..b5def49d 100644 --- a/ccmath_headers.cmake +++ b/ccmath_headers.cmake @@ -40,6 +40,7 @@ set(ccmath_internal_types_headers ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/types/number_pair.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/types/sign.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/types/float128.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/types/big_int.hpp ) diff --git a/include/ccmath/internal/types/big_int.hpp b/include/ccmath/internal/types/big_int.hpp new file mode 100644 index 00000000..39b47203 --- /dev/null +++ b/include/ccmath/internal/types/big_int.hpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2024-Present Ian Pike + * Copyright (c) 2024-Present ccmath contributors + * + * This library is provided under the MIT License. + * See LICENSE for more information. + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace ccm +{ + + template + struct BigInt + { + private: + static_assert(std::is_integral_v && std::is_unsigned_v, "WordType must be unsigned integer."); + + struct Division + { + BigInt quotient; + BigInt remainder; + }; + + public: + using word_type = WordType; + using unsigned_type = BigInt; + using signed_type = BigInt; + + static constexpr bool is_signed = Signed; + static constexpr std::size_t bits = Bits; + static constexpr std::size_t word_size = sizeof(word_type) * CHAR_BIT; + + static_assert(Bits > 0 && Bits % word_size == 0, "Number of bits in BigInt should be a multiple of word_size."); + + static constexpr std::size_t word_count = Bits / word_size; + + std::array data{}; + + constexpr BigInt() = default; + constexpr BigInt(const BigInt & other) = default; + + /** + * @brief Extend the internal representation of the big integer by filling remaining words with a specific value. + * @param index The starting index from where the extension should begin. + * @param is_negative Boolean flag indicating whether the big integer is negative. + * @return void + */ + constexpr void extend(std::size_t index, bool is_negative) + { + const word_type value = is_negative ? std::numeric_limits::max() : std::numeric_limits::min(); + for (size_t i = index; i < word_count; ++i) { data[i] = value; } + } + + template + constexpr BigInt(const BigInt & other) + { + if constexpr (OtherBits > Bits) // truncate bits + { + for (std::size_t i = 0; i < word_count; ++i) { data[i] = other.data[i]; } + } + else // Will be zero or sign extended + { + size_t i = 0; + for (; i < OtherBits / word_size; ++i) { data[i] = other.data[i]; } + extend(i, Signed && other.is_neg()); + } + } + + /** + * @brief Construct a BigInt from a C-style array of words. + * @tparam N The size of the array. + * @param nums The C-style array of words. + */ + template + constexpr BigInt(const WordType (&nums)[N]) // NOLINT + { + static_assert(N == word_count); + for (size_t i = 0; i < word_count; ++i) { data[i] = nums[i]; } + } + + constexpr explicit BigInt(const std::array & words) : data(words) {} + + + }; +} // namespace ccm diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4a1736b1..8815b4b1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -134,6 +134,18 @@ target_link_libraries(${PROJECT_NAME}-misc PRIVATE ) +# Tests for internal items +add_executable(${PROJECT_NAME}-internal-types) +target_sources(${PROJECT_NAME}-internal-types PRIVATE + internal/types/big_int_test.cpp + +) +target_link_libraries(${PROJECT_NAME}-internal-types PRIVATE + ccmath::test + gtest::gtest +) + + if(CCMATH_OS_WINDOWS) # For Windows: Prevent overriding the parent project's compiler/linker settings set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) @@ -159,5 +171,6 @@ add_test(NAME ${PROJECT_NAME}-nearest COMMAND ${PROJECT_NAME}-nearest) add_test(NAME ${PROJECT_NAME}-power COMMAND ${PROJECT_NAME}-power) add_test(NAME ${PROJECT_NAME}-misc COMMAND ${PROJECT_NAME}-misc) - +# Internal tests +add_test(NAME ${PROJECT_NAME}-internal-types COMMAND ${PROJECT_NAME}-internal-types) diff --git a/test/internal/types/big_int_test.cpp b/test/internal/types/big_int_test.cpp new file mode 100644 index 00000000..fa8e35c0 --- /dev/null +++ b/test/internal/types/big_int_test.cpp @@ -0,0 +1,22 @@ +/* +* Copyright (c) 2024-Present Ian Pike +* Copyright (c) 2024-Present ccmath contributors +* +* This library is provided under the MIT License. +* See LICENSE for more information. +*/ + +#include + +#include "ccmath/internal/types/big_int.hpp" + +TEST(CcmathInternalTypesTests, BigIntTest) +{ + ccm::BigInt<64, false> a; + auto t1 = ccm::BigInt<64, false>::bits; + auto t2 = ccm::BigInt<64, false>::is_signed; + + EXPECT_EQ(t1, 64); + EXPECT_EQ(t2, false); +} +