Negative numbers etc
This commit is contained in:
parent
42a055d224
commit
707fb74250
133
main.cpp
133
main.cpp
@ -1,4 +1,5 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
//#include "mp.hpp"
|
//#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;
|
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<MyInt(const MyInt&, const MyInt&)> op)
|
||||||
|
{
|
||||||
|
std::cout << "op: " << mp::to_string(a) << ' ' << desc << ' ' << mp::to_string(b) << " = " << mp::to_string(op(a, b)) << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
// mp::Int a{0xDEADBEEFDEADF154, 0x0123456789ABCDEF, 0x1111222233334444};
|
// mp::Int a{0xDEADBEEFDEADF154, 0x0123456789ABCDEF, 0x1111222233334444};
|
||||||
@ -66,27 +75,27 @@ int main()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
// {
|
||||||
mp::Int<1024> acc{1};
|
// mp::Int<1024> acc{1};
|
||||||
|
|
||||||
try
|
// try
|
||||||
{
|
// {
|
||||||
while (true)
|
// while (true)
|
||||||
{
|
// {
|
||||||
acc *= mp::Int<1>{10};
|
// acc *= mp::Int<1>{10};
|
||||||
PrintDec("acc", acc);
|
// PrintDec("acc", acc);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
catch (const mp::OverflowErrorOf<decltype(acc), mp::Int<1>>& e)
|
// catch (const mp::OverflowErrorOf<decltype(acc), mp::Int<1>>& e)
|
||||||
{
|
// {
|
||||||
std::cout << "overflow" << std::endl;
|
// std::cout << "overflow" << std::endl;
|
||||||
PrintDec("value", e.value());
|
// PrintDec("value", e.value());
|
||||||
}
|
// }
|
||||||
catch (const std::exception& e)
|
// catch (const std::exception& e)
|
||||||
{
|
// {
|
||||||
std::cout << "error: " << e.what() << std::endl;
|
// std::cout << "error: " << e.what() << std::endl;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
//{
|
//{
|
||||||
// mp::Int<32> val{1};
|
// mp::Int<32> val{1};
|
||||||
@ -136,4 +145,88 @@ int main()
|
|||||||
PrintDec("c", c);
|
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<>{});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -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]; }
|
TElem& operator[](size_t index) { return m_data[index]; }
|
||||||
const TElem& operator[](size_t index) const { 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(); }
|
size_t size_elems() const { return m_data.size(); }
|
||||||
|
|
||||||
|
bool negative() const { return m_negative; }
|
||||||
|
void set_negative(bool neg) { m_negative = neg; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Container<TElem, MAX_ELEMS> m_data;
|
Container<TElem, MAX_ELEMS> m_data;
|
||||||
|
bool m_negative = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<size_t MaxBytes>
|
template<size_t MaxBytes>
|
||||||
|
|||||||
34
mp/lib.hpp
34
mp/lib.hpp
@ -5,6 +5,7 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
|
#include "int.hpp"
|
||||||
|
|
||||||
namespace mp
|
namespace mp
|
||||||
{
|
{
|
||||||
@ -19,7 +20,7 @@ inline std::string to_hex_string(const T& number)
|
|||||||
{
|
{
|
||||||
constexpr size_t ELEMENT_DIGITS = T::ELEMENT_BYTES * 2;
|
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)
|
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');
|
auto first = str.find_first_not_of('0');
|
||||||
if (first != std::string::npos)
|
if (first != std::string::npos)
|
||||||
{
|
{
|
||||||
return "0x" + str.substr(first);
|
return (number.negative() ? "-" : "") + ("0x" + str.substr(first));
|
||||||
}
|
}
|
||||||
|
|
||||||
return "0x0";
|
return "0x0";
|
||||||
@ -68,6 +69,9 @@ inline std::string to_string(const T& number)
|
|||||||
str.push_back(static_cast<char>('0' + rem));
|
str.push_back(static_cast<char>('0' + rem));
|
||||||
} while (temp != 0U);
|
} while (temp != 0U);
|
||||||
|
|
||||||
|
if (number.negative())
|
||||||
|
str.push_back('-');
|
||||||
|
|
||||||
std::reverse(str.begin(), str.end());
|
std::reverse(str.begin(), str.end());
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
@ -77,6 +81,14 @@ inline void parse_string(const char* str, T& number)
|
|||||||
{
|
{
|
||||||
number.zero();
|
number.zero();
|
||||||
|
|
||||||
|
bool negative = false;
|
||||||
|
|
||||||
|
if (*str == '-')
|
||||||
|
{
|
||||||
|
negative = true;
|
||||||
|
++str;
|
||||||
|
}
|
||||||
|
|
||||||
for (; *str; ++str)
|
for (; *str; ++str)
|
||||||
{
|
{
|
||||||
if (*str < '0' || *str > '9')
|
if (*str < '0' || *str > '9')
|
||||||
@ -86,6 +98,24 @@ inline void parse_string(const char* str, T& number)
|
|||||||
|
|
||||||
number = number * 10U + static_cast<typename T::ElementType>(*str - '0');
|
number = number * 10U + static_cast<typename T::ElementType>(*str - '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
number.set_negative(negative);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <AnyConstInt T>
|
||||||
|
inline T from_string(const char* str)
|
||||||
|
{
|
||||||
|
T number;
|
||||||
|
parse_string(str, number);
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
inline Int<N> from_string(const char* str)
|
||||||
|
{
|
||||||
|
Int<N> number;
|
||||||
|
parse_string(str, number);
|
||||||
|
return number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
117
mp/math.hpp
117
mp/math.hpp
@ -127,12 +127,53 @@ bool operator!=(const TLhs& lhs, const TRhs& rhs)
|
|||||||
return !(lhs == rhs);
|
return !(lhs == rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Addition
|
template <AnyConstMpInt TLhs, AnyConstMpInt TRhs, AnyMpInt TRes>
|
||||||
{
|
|
||||||
template <AnyConstMpInt TLhs, AnyConstMpInt TRhs, AnyMpInt TRes>
|
|
||||||
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
||||||
static void invoke(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
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 <AnyConstMpInt TLhs, AnyConstMpInt TRhs, AnyMpInt TRes>
|
||||||
|
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
||||||
|
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 <AnyConstMpInt TLhs, AnyConstMpInt TRhs, AnyMpInt TRes>
|
||||||
|
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
||||||
|
inline void add_ignore_sign(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
||||||
|
{
|
||||||
using ElementType = typename TRes::ElementType;
|
using ElementType = typename TRes::ElementType;
|
||||||
|
|
||||||
res.zero();
|
res.zero();
|
||||||
@ -155,6 +196,32 @@ struct Addition
|
|||||||
}
|
}
|
||||||
|
|
||||||
res.set(end, carry);
|
res.set(end, carry);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Addition
|
||||||
|
{
|
||||||
|
template <AnyConstMpInt TLhs, AnyConstMpInt TRhs, AnyMpInt TRes>
|
||||||
|
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
||||||
|
static void invoke(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
||||||
|
{
|
||||||
|
const bool lhs_neg = lhs.negative();
|
||||||
|
const bool rhs_neg = rhs.negative();
|
||||||
|
|
||||||
|
if (lhs_neg == rhs_neg)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -164,27 +231,33 @@ struct Subtraction
|
|||||||
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
requires ElementTypesMatch<TLhs, TRes> && ElementTypesMatch<TRhs, TRes>
|
||||||
static void invoke(const TLhs& lhs, const TRhs& rhs, TRes& res)
|
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();
|
if (!lhs_neg && !rhs_neg)
|
||||||
|
|
||||||
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);
|
// a - b
|
||||||
ElementType b = rhs.get(i);
|
sub_ignore_sign(lhs, rhs, res);
|
||||||
|
}
|
||||||
ElementType c = a - b - borrow;
|
else if (lhs_neg && rhs_neg)
|
||||||
borrow = (a < b) || (borrow && a == b);
|
{
|
||||||
res.set(i, c);
|
// (-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);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (borrow != 0)
|
|
||||||
{
|
|
||||||
throw std::overflow_error("Subtraction underflow");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -198,6 +271,7 @@ struct Multiplication
|
|||||||
using LongerType = DoubleWidthType<ElementType>;
|
using LongerType = DoubleWidthType<ElementType>;
|
||||||
|
|
||||||
res.zero();
|
res.zero();
|
||||||
|
res.set_negative(lhs.negative() != rhs.negative());
|
||||||
|
|
||||||
bool overflow = false;
|
bool overflow = false;
|
||||||
|
|
||||||
@ -297,6 +371,7 @@ struct Division
|
|||||||
|
|
||||||
// Prepare quotient
|
// Prepare quotient
|
||||||
res.zero();
|
res.zero();
|
||||||
|
res.set_negative(lhs.negative() != rhs.negative());
|
||||||
|
|
||||||
// Main loop j = m .. 0
|
// Main loop j = m .. 0
|
||||||
for (int j = static_cast<int>(m); j >= 0; --j)
|
for (int j = static_cast<int>(m); j >= 0; --j)
|
||||||
|
|||||||
10
mp/utils.hpp
10
mp/utils.hpp
@ -5,6 +5,10 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
#ifdef __SIZEOF_INT128__
|
||||||
|
#define USE_UINT128
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace mp
|
namespace mp
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -31,7 +35,7 @@ struct DoubleWidth<uint32_t>
|
|||||||
using type = uint64_t;
|
using type = uint64_t;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if USE_UINT128
|
#ifdef USE_UINT128
|
||||||
template <>
|
template <>
|
||||||
struct DoubleWidth<uint64_t>
|
struct DoubleWidth<uint64_t>
|
||||||
{
|
{
|
||||||
@ -78,6 +82,7 @@ concept AnyConstMpInt = requires(T t, TElem a, size_t i) {
|
|||||||
{ t[i] } -> std::convertible_to<TElem>;
|
{ t[i] } -> std::convertible_to<TElem>;
|
||||||
{ t.get(i) } -> std::convertible_to<TElem>;
|
{ t.get(i) } -> std::convertible_to<TElem>;
|
||||||
{ t.size_elems() } -> std::convertible_to<size_t>;
|
{ t.size_elems() } -> std::convertible_to<size_t>;
|
||||||
|
{ t.negative() } -> std::convertible_to<bool>;
|
||||||
{ T::MAX_BYTES } -> std::convertible_to<size_t>;
|
{ T::MAX_BYTES } -> std::convertible_to<size_t>;
|
||||||
{ T::MAX_ELEMS } -> std::convertible_to<size_t>;
|
{ T::MAX_ELEMS } -> std::convertible_to<size_t>;
|
||||||
{ T::ELEMENT_BYTES } -> std::convertible_to<size_t>;
|
{ T::ELEMENT_BYTES } -> std::convertible_to<size_t>;
|
||||||
@ -85,9 +90,10 @@ concept AnyConstMpInt = requires(T t, TElem a, size_t i) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename TElem = T::ElementType>
|
template <typename T, typename TElem = T::ElementType>
|
||||||
concept AnyMpInt = AnyConstMpInt<T> && requires(T t, TElem a, size_t i) {
|
concept AnyMpInt = AnyConstMpInt<T> && requires(T t, TElem a, size_t i, bool b) {
|
||||||
{ t.set(i, a) };
|
{ t.set(i, a) };
|
||||||
{ t.try_set(i, a) } -> std::convertible_to<bool>;
|
{ t.try_set(i, a) } -> std::convertible_to<bool>;
|
||||||
|
{ t.set_negative(b) };
|
||||||
{ t.zero() };
|
{ t.zero() };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user