From 707fb7425010fd7e42163f34c1f9d0ac34df25c3 Mon Sep 17 00:00:00 2001 From: tovjemam Date: Wed, 26 Nov 2025 21:59:39 +0100 Subject: [PATCH] Negative numbers etc --- main.cpp | 133 +++++++++++++++++++++++++++++++++++++++------- mp/int.hpp | 9 ++++ mp/lib.hpp | 34 +++++++++++- mp/math.hpp | 145 ++++++++++++++++++++++++++++++++++++++------------- mp/utils.hpp | 10 +++- 5 files changed, 272 insertions(+), 59 deletions(-) diff --git a/main.cpp b/main.cpp index 69a004f..0600d8c 100644 --- a/main.cpp +++ b/main.cpp @@ -1,4 +1,5 @@ #include +#include #include //#include "mp.hpp" @@ -17,6 +18,14 @@ static void PrintDec(const char* name, const T& val){ std::cout << name << " = " << mp::to_string(val) << std::endl; } +using MyInt = mp::Int<32>; + +static void display_op(const char* desc, const MyInt& a, const MyInt& b, std::function op) +{ + std::cout << "op: " << mp::to_string(a) << ' ' << desc << ' ' << mp::to_string(b) << " = " << mp::to_string(op(a, b)) << std::endl; +} + + int main() { // mp::Int a{0xDEADBEEFDEADF154, 0x0123456789ABCDEF, 0x1111222233334444}; @@ -66,27 +75,27 @@ int main() - { - mp::Int<1024> acc{1}; + // { + // mp::Int<1024> acc{1}; - try - { - while (true) - { - acc *= mp::Int<1>{10}; - PrintDec("acc", acc); - } - } - catch (const mp::OverflowErrorOf>& e) - { - std::cout << "overflow" << std::endl; - PrintDec("value", e.value()); - } - catch (const std::exception& e) - { - std::cout << "error: " << e.what() << std::endl; - } - } + // try + // { + // while (true) + // { + // acc *= mp::Int<1>{10}; + // PrintDec("acc", acc); + // } + // } + // catch (const mp::OverflowErrorOf>& e) + // { + // std::cout << "overflow" << std::endl; + // PrintDec("value", e.value()); + // } + // catch (const std::exception& e) + // { + // std::cout << "error: " << e.what() << std::endl; + // } + // } //{ // mp::Int<32> val{1}; @@ -136,4 +145,88 @@ int main() PrintDec("c", c); } + { + display_op("+", + mp::from_string<32>("123456789012345678901234567890"), + mp::from_string<32>("987654321098765432109876543210"), + std::plus<>{}); + + display_op("+", + mp::from_string<32>("987654321098765432109876543210"), + mp::from_string<32>("-123456789012345678901234567890"), + std::plus<>{}); + + display_op("+", + mp::from_string<32>("-123456789012345678901234567890"), + mp::from_string<32>("-987654321098765432109876543210"), + std::plus<>{}); + + display_op("+", + mp::from_string<32>("123456789012345678901234567890"), + mp::from_string<32>("-987654321098765432109876543210"), + std::plus<>{}); + + display_op("-", + mp::from_string<32>("987654321098765432109876543210"), + mp::from_string<32>("123456789012345678901234567890"), + std::minus<>{}); + + display_op("-", + mp::from_string<32>("123456789012345678901234567890"), + mp::from_string<32>("987654321098765432109876543210"), + std::minus<>{}); + + display_op("-", + mp::from_string<32>("-123456789012345678901234567890"), + mp::from_string<32>("-987654321098765432109876543210"), + std::minus<>{}); + + display_op("-", + mp::from_string<32>("987654321098765432109876543210"), + mp::from_string<32>("-123456789012345678901234567890"), + std::minus<>{}); + + display_op("*", + mp::from_string<32>("12345678901234567890"), + mp::from_string<32>("98765432109876543210"), + std::multiplies<>{}); + + display_op("*", + mp::from_string<32>("-12345678901234567890"), + mp::from_string<32>("98765432109876543210"), + std::multiplies<>{}); + + display_op("*", + mp::from_string<32>("-12345678901234567890"), + mp::from_string<32>("-98765432109876543210"), + std::multiplies<>{}); + + display_op("/", + mp::from_string<32>("1219326311370217952237463801111263506900"), + mp::from_string<32>("12345678901234567890"), + std::divides<>{}); + + display_op("/", + mp::from_string<32>("-1219326311370217952237463801111263506900"), + mp::from_string<32>("12345678901234567890"), + std::divides<>{}); + + display_op("/", + mp::from_string<32>("-1219326311370217952237463801111263506900"), + mp::from_string<32>("-12345678901234567890"), + std::divides<>{}); + + auto a = mp::from_string<32>("12345678901234567890"); + auto b = mp::from_string<32>("98765432109876543210"); + b.set_negative(true); + + display_op("*", + a, + b, + std::multiplies<>{}); + + + + } + } \ No newline at end of file diff --git a/mp/int.hpp b/mp/int.hpp index f82efdb..a00e6b0 100644 --- a/mp/int.hpp +++ b/mp/int.hpp @@ -26,6 +26,11 @@ class BasicInt } } + BasicInt(const BasicInt& other) = default; + BasicInt(BasicInt&& other) noexcept = default; + BasicInt& operator=(const BasicInt& other) = default; + BasicInt& operator=(BasicInt&& other) noexcept = default; + TElem& operator[](size_t index) { return m_data[index]; } const TElem& operator[](size_t index) const { return m_data[index]; } @@ -96,8 +101,12 @@ class BasicInt size_t size_elems() const { return m_data.size(); } + bool negative() const { return m_negative; } + void set_negative(bool neg) { m_negative = neg; } + private: Container m_data; + bool m_negative = false; }; template diff --git a/mp/lib.hpp b/mp/lib.hpp index 790be82..37ae889 100644 --- a/mp/lib.hpp +++ b/mp/lib.hpp @@ -5,6 +5,7 @@ #include #include "utils.hpp" +#include "int.hpp" namespace mp { @@ -19,7 +20,7 @@ inline std::string to_hex_string(const T& number) { constexpr size_t ELEMENT_DIGITS = T::ELEMENT_BYTES * 2; - std::string str(number.size_elems() * ELEMENT_DIGITS, '-'); + std::string str(number.size_elems() * ELEMENT_DIGITS, '?'); for (size_t elem = 0; elem < number.size_elems(); ++elem) { @@ -33,7 +34,7 @@ inline std::string to_hex_string(const T& number) auto first = str.find_first_not_of('0'); if (first != std::string::npos) { - return "0x" + str.substr(first); + return (number.negative() ? "-" : "") + ("0x" + str.substr(first)); } return "0x0"; @@ -68,6 +69,9 @@ inline std::string to_string(const T& number) str.push_back(static_cast('0' + rem)); } while (temp != 0U); + if (number.negative()) + str.push_back('-'); + std::reverse(str.begin(), str.end()); return str; } @@ -77,6 +81,14 @@ inline void parse_string(const char* str, T& number) { number.zero(); + bool negative = false; + + if (*str == '-') + { + negative = true; + ++str; + } + for (; *str; ++str) { if (*str < '0' || *str > '9') @@ -86,6 +98,24 @@ inline void parse_string(const char* str, T& number) number = number * 10U + static_cast(*str - '0'); } + + number.set_negative(negative); +} + +template +inline T from_string(const char* str) +{ + T number; + parse_string(str, number); + return number; +} + +template +inline Int from_string(const char* str) +{ + Int number; + parse_string(str, number); + return number; } diff --git a/mp/math.hpp b/mp/math.hpp index 5fb4ec7..c9764d9 100644 --- a/mp/math.hpp +++ b/mp/math.hpp @@ -127,34 +127,101 @@ bool operator!=(const TLhs& lhs, const TRhs& rhs) return !(lhs == rhs); } +template + requires ElementTypesMatch && ElementTypesMatch +inline void sub_ignore_underflow(const TLhs& lhs, const TRhs& rhs, TRes& res) +{ + using ElementType = typename TRes::ElementType; + + res.zero(); + + ElementType borrow = 0; + size_t end = std::max(lhs.size_elems(), rhs.size_elems()); + + for (size_t i = 0; i < end; ++i) + { + ElementType a = lhs.get(i); + ElementType b = rhs.get(i); + + ElementType c = a - b - borrow; + borrow = (a < b) || (borrow && a == b); + res.set(i, c); + } + + if (borrow != 0) + { + throw std::overflow_error("Subtraction underflow"); + } +} + +template + requires ElementTypesMatch && ElementTypesMatch +inline void sub_ignore_sign(const TLhs& lhs, const TRhs& rhs, TRes& res) +{ + if (lhs < rhs) + { + sub_ignore_underflow(rhs, lhs, res); + res.set_negative(true); + } + else + { + sub_ignore_underflow(lhs, rhs, res); + res.set_negative(false); + } +} + +template + requires ElementTypesMatch && ElementTypesMatch +inline void add_ignore_sign(const TLhs& lhs, const TRhs& rhs, TRes& res) +{ + using ElementType = typename TRes::ElementType; + + res.zero(); + + ElementType carry = 0; + size_t end = std::max(lhs.size_elems(), rhs.size_elems()); + + for (size_t i = 0; i < end; ++i) + { + ElementType a = lhs.get(i); + ElementType b = rhs.get(i); + + ElementType c = carry + a; + carry = (c < a) ? 1 : 0; + c += b; + if (c < b) + carry = 1; + + res.set(i, c); + } + + res.set(end, carry); +} + struct Addition { template requires ElementTypesMatch && ElementTypesMatch static void invoke(const TLhs& lhs, const TRhs& rhs, TRes& res) { - using ElementType = typename TRes::ElementType; + const bool lhs_neg = lhs.negative(); + const bool rhs_neg = rhs.negative(); - res.zero(); - - ElementType carry = 0; - size_t end = std::max(lhs.size_elems(), rhs.size_elems()); - - for (size_t i = 0; i < end; ++i) + if (lhs_neg == rhs_neg) { - ElementType a = lhs.get(i); - ElementType b = rhs.get(i); - - ElementType c = carry + a; - carry = (c < a) ? 1 : 0; - c += b; - if (c < b) - carry = 1; - - res.set(i, c); + add_ignore_sign(lhs, rhs, res); + res.set_negative(lhs_neg); + } + else if (lhs_neg) + { + // (-a) + b == b - a + sub_ignore_sign(rhs, lhs, res); + } + else + { + // a + (-b) == a - b + sub_ignore_sign(lhs, rhs, res); } - - res.set(end, carry); } }; @@ -164,27 +231,33 @@ struct Subtraction requires ElementTypesMatch && ElementTypesMatch static void invoke(const TLhs& lhs, const TRhs& rhs, TRes& res) { - using ElementType = typename TRes::ElementType; + const bool lhs_neg = lhs.negative(); + const bool rhs_neg = rhs.negative(); - res.zero(); - - ElementType borrow = 0; - size_t end = std::max(lhs.size_elems(), rhs.size_elems()); - - for (size_t i = 0; i < end; ++i) + if (!lhs_neg && !rhs_neg) { - ElementType a = lhs.get(i); - ElementType b = rhs.get(i); - - ElementType c = a - b - borrow; - borrow = (a < b) || (borrow && a == b); - res.set(i, c); + // a - b + sub_ignore_sign(lhs, rhs, res); } - - if (borrow != 0) + else if (lhs_neg && rhs_neg) { - throw std::overflow_error("Subtraction underflow"); + // (-a) - (-b) == b - a + sub_ignore_sign(rhs, lhs, res); } + else if (lhs_neg && !rhs_neg) + { + // (-a) - b == -(a + b) + add_ignore_sign(lhs, rhs, res); + res.set_negative(true); + } + else // if (!lhs_neg && rhs_neg) + { + // a - (-b) == a + b + add_ignore_sign(lhs, rhs, res); + res.set_negative(false); + } + + } }; @@ -198,6 +271,7 @@ struct Multiplication using LongerType = DoubleWidthType; res.zero(); + res.set_negative(lhs.negative() != rhs.negative()); bool overflow = false; @@ -297,6 +371,7 @@ struct Division // Prepare quotient res.zero(); + res.set_negative(lhs.negative() != rhs.negative()); // Main loop j = m .. 0 for (int j = static_cast(m); j >= 0; --j) diff --git a/mp/utils.hpp b/mp/utils.hpp index cca9972..4fa694b 100644 --- a/mp/utils.hpp +++ b/mp/utils.hpp @@ -5,6 +5,10 @@ #include #include +#ifdef __SIZEOF_INT128__ +#define USE_UINT128 +#endif + namespace mp { @@ -31,7 +35,7 @@ struct DoubleWidth using type = uint64_t; }; -#if USE_UINT128 +#ifdef USE_UINT128 template <> struct DoubleWidth { @@ -78,6 +82,7 @@ concept AnyConstMpInt = requires(T t, TElem a, size_t i) { { t[i] } -> std::convertible_to; { t.get(i) } -> std::convertible_to; { t.size_elems() } -> std::convertible_to; + { t.negative() } -> std::convertible_to; { T::MAX_BYTES } -> std::convertible_to; { T::MAX_ELEMS } -> std::convertible_to; { T::ELEMENT_BYTES } -> std::convertible_to; @@ -85,9 +90,10 @@ concept AnyConstMpInt = requires(T t, TElem a, size_t i) { }; template -concept AnyMpInt = AnyConstMpInt && requires(T t, TElem a, size_t i) { +concept AnyMpInt = AnyConstMpInt && requires(T t, TElem a, size_t i, bool b) { { t.set(i, a) }; { t.try_set(i, a) } -> std::convertible_to; + { t.set_negative(b) }; { t.zero() }; };