commit ac10af30da5b79a03368fd34ddf4359b306b8a11 Author: tovjemam Date: Sat Sep 27 15:56:12 2025 +0200 Init diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..06546a8 --- /dev/null +++ b/.clang-format @@ -0,0 +1,6 @@ +BasedOnStyle: Microsoft +DerivePointerAlignment: false +PointerAlignment: Left +IndentWidth: 4 # spaces per indent level +TabWidth: 4 # width of a tab character +UseTab: Never # options: Never, ForIndentation, Alwayss diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e524d79 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.vscode/ +build/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..72905e1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.10) + +project(CppMpInt) + +set(CMAKE_CXX_STANDARD 20) + +add_executable(main main.cpp) diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..3bab47f --- /dev/null +++ b/main.cpp @@ -0,0 +1,31 @@ +#include + +#include "mp.hpp" + +template +static void PrintInt(const char* name, const T& val) +{ + std::cout << name << " = " << mp::ToHexString(val) << std::endl; +} + +int main() +{ + // mp::Int a{0xDEADBEEFDEADF154, 0x0123456789ABCDEF, 0x1111222233334444}; + mp::Int<4> a{0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}; + mp::Int<5> b{0x55}; + + PrintInt("a", a); + PrintInt("b", b); + + auto c = a + b; + PrintInt("c", c); + + a += mp::Int<1>{1}; + PrintInt("a", a); + + a -= mp::Int<1>{1}; + PrintInt("a", a); + + std::cout << mp::Int<16>::LAST_ELEM_MASK << std::endl; + +} \ No newline at end of file diff --git a/mp.hpp b/mp.hpp new file mode 100644 index 0000000..c0c1545 --- /dev/null +++ b/mp.hpp @@ -0,0 +1,4 @@ +#pragma once + +#include "mp_int.hpp" +#include "mp_lib.hpp" diff --git a/mp_int.hpp b/mp_int.hpp new file mode 100644 index 0000000..0e7b23c --- /dev/null +++ b/mp_int.hpp @@ -0,0 +1,137 @@ +#pragma once + +#include +#include +#include + +#include "mp_math.hpp" +#include "mp_utils.hpp" + +namespace mp +{ + +static constexpr size_t UNLIMITED = std::numeric_limits().max(); + +// template +// struct ElemContainerImpl +// { +// using type = std::vector; +// }; + +// template +// struct ElemContainerImpl +// { +// using type = std::array; +// }; + +// template +// using ElemContainer = typename ElemContainerImpl::type; + +template class BasicInt; + +template >> +using IntOpResultType = BasicInt; + +template class BasicInt +{ + public: + using ElementType = TElem; + static constexpr size_t MAX_SIZE = MaxSize; + + using ThisType = BasicInt; + + static constexpr size_t ELEMENT_BYTES = sizeof(ElementType); + static constexpr size_t MAX_ELEMS = utils::AlignUp(MaxSize, ELEMENT_BYTES) / ELEMENT_BYTES; + static constexpr ElementType LAST_ELEM_MASK = utils::GetNBytesMask(MAX_SIZE % ELEMENT_BYTES); + static constexpr ElementType ELEMENT_MAX = std::numeric_limits().max(); + + // static constexpr size_t LAST_ELEM_MASK = GetNBytesMask(3); + + BasicInt(std::initializer_list init) : m_elems{init} + { + } + + // template Int(TArgs&&... args) + // { + // (m_value.push_back(args), ...); + // } + + size_t GetNumElements() const + { + return m_elems.size(); + } + + TElem GetElement(size_t index) const + { + if (index >= m_elems.size()) + return 0; + + return m_elems[index]; + } + + void SetElement(size_t index, TElem value) + { + if (index >= m_elems.size()) + { + if (value == 0) + { + return; + } + + m_elems.resize(index + 1, 0); + } + + m_elems[index] = value; + } + + template void BinaryOp(TR& r, const TRhs& rhs) const + { + TOp::Op(r, *this, rhs); + } + + template IntOpResultType ExtBinaryOp(const TRhs& rhs) const + { + IntOpResultType result{}; + BinaryOp(result, rhs); + return result; + } + + template ThisType& CompoundBinaryOp(const TRhs& rhs) + { + BinaryOp(*this, rhs); + return *this; + } + + template auto operator+(const TRhs& rhs) const + { + return ExtBinaryOp(rhs); + } + + template auto operator+=(const TRhs& rhs) + { + return CompoundBinaryOp(rhs); + } + + template auto operator-(const TRhs& rhs) const + { + return ExtBinaryOp(rhs); + } + + template auto& operator-=(const TRhs& rhs) + { + return CompoundBinaryOp(rhs); + } + + private: + std::vector m_elems; +}; + +// using UnlimitedInt = Int; +using DefaultElemType = size_t; + + +template using Int = BasicInt; +using UnlimitedInt = Int; + +} // namespace mp diff --git a/mp_lib.hpp b/mp_lib.hpp new file mode 100644 index 0000000..0140085 --- /dev/null +++ b/mp_lib.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include "mp_utils.hpp" + +namespace mp +{ + +template +inline std::string ToHexString(const T& number) +{ + constexpr size_t ELEMENT_DIGITS = T::ELEMENT_BYTES * 2; + + std::string str(number.GetNumElements() * ELEMENT_DIGITS, '-'); + + for (size_t elem = 0; elem < number.GetNumElements(); ++elem) + { + auto v = number.GetElement(elem); + for (size_t digit = 0; digit < ELEMENT_DIGITS; ++digit) + { + str[str.size() - 1 - (elem * ELEMENT_DIGITS) - digit] = utils::HexDigit((v >> (digit * 4)) & 0xF); + } + } + + return str; +} + +} // namespace mp \ No newline at end of file diff --git a/mp_math.hpp b/mp_math.hpp new file mode 100644 index 0000000..938d9ce --- /dev/null +++ b/mp_math.hpp @@ -0,0 +1,73 @@ +#pragma once + +#include +#include +#include +#include + +namespace mp +{ + +struct Addition +{ + template static void Op(TR& r, const TLhs& lhs, const TRhs& rhs) + { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + + using ElementType = TR::ElementType; + + ElementType carry = 0; + size_t end = std::max(lhs.GetNumElements(), rhs.GetNumElements()); + for (size_t i = 0; i < end; ++i) + { + ElementType a = lhs.GetElement(i); + ElementType b = rhs.GetElement(i); + + ElementType c = carry + a; + carry = (c < a) ? 1 : 0; + c += b; + carry |= (c < b) ? 1 : 0; + + r.SetElement(i, c); + + // carry = (((a + carry) > (ELEMENT_MAX - b)) || (a > (ELEMENT_MAX - carry))) ? 1 : 0; + } + + r.SetElement(end, carry); + } +}; + +struct Subtraction +{ + template static void Op(TR& r, const TLhs& lhs, const TRhs& rhs) + { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + + using ElementType = TR::ElementType; + + ElementType borrow = 0; + size_t end = std::max(lhs.GetNumElements(), rhs.GetNumElements()); + for (size_t i = 0; i < end; ++i) + { + ElementType a = lhs.GetElement(i); + ElementType b = rhs.GetElement(i); + + ElementType c = a - b - borrow; + + borrow = (a < b || (a - b) < borrow) ? 1 : 0; + + r.SetElement(i, c); + } + + if (borrow > 0) + { + throw std::runtime_error("Subtraction result negative"); + } + + // r.SetElement(end, borrow); + } +}; + +} // namespace mp \ No newline at end of file diff --git a/mp_utils.hpp b/mp_utils.hpp new file mode 100644 index 0000000..2b78455 --- /dev/null +++ b/mp_utils.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +namespace mp::utils +{ + +template +inline constexpr T GetNBytesMask(size_t bytes) +{ + T res = 0; + + for (size_t i = 0; i < bytes; ++i) + { + res <<= 8; + res |= 0xFF; + } + + return res; +} + +inline char HexDigit(uint8_t bits) +{ + return bits > 9 ? 'a' + (bits - 10) : '0' + bits; +} + +inline constexpr size_t AlignUp(size_t value, size_t alignment) +{ + return (value + alignment - 1) / alignment * alignment; +} + +} // namespace mp::utils