diff --git a/include/data/encoding/base58.hpp b/include/data/encoding/base58.hpp index abe62a47..882dd602 100644 --- a/include/data/encoding/base58.hpp +++ b/include/data/encoding/base58.hpp @@ -13,22 +13,30 @@ #include #include #include +#include +#include #include namespace data::encoding::base58 { const std::string Format{"base58"}; - inline std::string characters() {return "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";} + std::string inline characters() {return "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";} static constexpr auto pattern = ctll::fixed_string{"1|([2-9A-HJ-NP-Za-km-z][1-9A-HJ-NP-Za-km-z]*)"}; - inline bool valid(const string_view s) { + bool inline valid(const string_view s) { return ctre::match(s); } - inline char digit(char c) { - return c < '1' ? -1 : c <= '9' ? c - '1' : c < 'A' ? -1 : c <= 'H' ? c - 'A' + 9 : c < 'J' ? -1 : c <= 'N' ? c - 'J' + 17 : c < 'P' ? -1 : c <= 'Z' ? c - 'P' + 22 : c < 'a' ? -1 : c <= 'k' ? c - 'a' + 33 : c < 'm' ? -1 : c <= 'z' ? c - 'm' + 44 : -1; + bool inline nonzero(const string_view s) { + return valid(s) && s[0] != '1'; + } + + char inline digit(char c) { + return c < '1' ? -1 : c <= '9' ? c - '1' : c < 'A' ? -1 : c <= 'H' ? c - 'A' + 9 : + c < 'J' ? -1 : c <= 'N' ? c - 'J' + 17 : c < 'P' ? -1 : c <= 'Z' ? c - 'P' + 22 : + c < 'a' ? -1 : c <= 'k' ? c - 'a' + 33 : c < 'm' ? -1 : c <= 'z' ? c - 'm' + 44 : -1; }; template @@ -39,14 +47,10 @@ namespace data::encoding::base58 { N n{0}; - //std::cout << " reading base 58 number " << s << std::endl; - for (int i = s.size() - 1; i >= 0; i--) { char v = digit(s[i]); - //std::cout << " digit is " << s[i] << " or " << uint64(v) << std::endl; if (v == -1) return N{}; n += power * uint64(v); - //std::cout << " n is " << n << std::endl; power *= 58; } @@ -72,18 +76,18 @@ namespace data::encoding::base58 { struct string : std::string { string(); - string(const std::string&); + explicit string(string_view); + explicit string(std::string &&x): std::string{x} {}; string(uint64); - + bool valid() const { return base58::valid(*this); } - bool operator<=(const string&) const; - bool operator>=(const string&) const; - bool operator<(const string&) const; - bool operator>(const string&) const; - + static string read(string_view x); + + std::strong_ordering operator<=>(const string&) const; + string& operator++(); string& operator--(); @@ -109,11 +113,77 @@ namespace data::encoding::base58 { template string write(N n) { - return encoding::write_base(n, characters()); + return string{encoding::write_base(n, characters())}; }; string write(const bytes_view b); } +namespace data { + using base58_uint = encoding::base58::string; + + math::sign sign(const base58_uint&); +} + +namespace data::math { + + template <> struct abs { + base58_uint operator()(const base58_uint&); + }; + + template + struct root { + set operator()(const base58_uint& n); + }; +} + +namespace data::math::number { + + base58_uint increment(const base58_uint&); + base58_uint decrement(const base58_uint&); + + bool is_zero(const base58_uint &); + bool is_negative(const base58_uint &); + bool is_positive(const base58_uint &); + +} + +namespace data { + + math::sign inline sign(const base58_uint &n) { + if (!encoding::base58::valid(n)) throw std::invalid_argument{std::string{"invalid base 58 string: "} + std::string{n}}; + return encoding::base58::nonzero(n) ? math::positive : math::zero; + } +} + +namespace data::math::number { + + base58_uint inline increment(const base58_uint &n) { + auto x = n; + return ++x; + } + + base58_uint inline decrement(const base58_uint &n) { + auto x = n; + return --x; + } + + bool inline is_zero(const base58_uint &n) { + if (encoding::base58::valid(n)) throw std::invalid_argument{std::string{"invalid base 58 string: "} + std::string{n}}; + return !encoding::base58::nonzero(n); + } + + bool inline is_negative(const base58_uint &n) { + if (encoding::base58::valid(n)) throw std::invalid_argument{std::string{"invalid base 58 string: "} + std::string{n}}; + return false; + } + + bool inline is_positive(const base58_uint &n) { + if (encoding::base58::valid(n)) throw std::invalid_argument{std::string{"invalid base 58 string: "} + std::string{n}}; + return encoding::base58::nonzero(n); + } + +} + #endif diff --git a/include/data/encoding/integer.hpp b/include/data/encoding/integer.hpp index 203fd2b4..d883da91 100644 --- a/include/data/encoding/integer.hpp +++ b/include/data/encoding/integer.hpp @@ -14,80 +14,53 @@ #include #include #include +#include namespace data::encoding { namespace decimal { static constexpr ctll::fixed_string pattern{"0|([1-9][0-9]*)"}; - std::string inline characters() { - return "0123456789"; - } + std::string characters(); + char digit(char x); + bool valid(string_view s); + bool nonzero(string_view s); + uint32 digits(string_view s); - char inline digit(char x) { - return x < '0' || x > '9' ? -1 : x - '0'; - } + template ptr> read(string_view s); - bool inline valid(string_view s) { - return ctre::match(s); - } + template + std::ostream &write(std::ostream& o, range r); - bool inline nonzero(string_view s) { - return valid(s) && s[0] != '0'; - } + // a decimal string inherets from std::string but is + // a big number that supports standard numerical operations. + struct string; - uint32 inline digits(string_view s) { - return valid(s) ? s.size() : 0; - } + template + string write(const math::number::N_bytes &z); - template ptr> read(string_view s); + // all valid decimal strings are uniquely associated with + // a natural number, so we can use a strong ordering. + std::strong_ordering operator<=>(const string &, const string &); - template - std::ostream &write(std::ostream& o, range r); + string &operator++(string&); + string &operator--(string&); - template - std::string inline write(range r) { - std::stringstream ss; - write(ss, r); - return ss.str(); - } + string operator++(string&, int); + string operator--(string&, int); - struct N : string { - N(); - N(const string&); - N(uint64); - - bool valid() const { - return decimal::valid(*this); - } + string operator+(const string&, const string&); + string operator-(const string&, const string&); + string operator*(const string&, const string&); - bool operator<=(const N&) const; - bool operator>=(const N&) const; - bool operator<(const N&) const; - bool operator>(const N&) const; + string operator<<(const string&, int); + string operator>>(const string&, int); - N& operator++(); - N& operator--(); - - N operator++(int); - N operator--(int); - - N operator+(const N&) const; - N operator-(const N&) const; - N operator*(const N&) const; - - N operator<<(int) const; - N operator>>(int) const; - - N& operator+=(const N&); - N& operator-=(const N&); - N& operator*=(const N&); - - N& operator<<=(int); - N& operator>>=(int); - - math::division divide(uint64) const; - }; + string operator|(const string&, const string&); + string operator&(const string&, const string&); + + string operator/(const string&, const string&); + string operator%(const string&, const string&); } @@ -95,121 +68,88 @@ namespace data::encoding { static constexpr ctll::fixed_string pattern{"0|(-?[1-9][0-9]*)"}; - bool inline valid(string_view s) { - return ctre::match(s); - } + bool valid(string_view s); + bool nonzero(string_view s); + bool positive(string_view s); + bool negative(string_view s); + math::sign sign(string_view s); template ptr> read(string_view s); template - std::ostream inline &write(std::ostream &o, const math::number::Z_bytes &z) { - if (math::number::is_negative(z)) o << '-'; - return decimal::write(o, data::abs(z)); - } + std::ostream &write(std::ostream &o, const math::number::Z_bytes &z); + + // a decimal string inherets from std::string but is + // a big number that supports standard numerical operations. + struct string; template - string inline write(const math::number::Z_bytes &z) { - std::stringstream ss; - write(ss, z); - return ss.str(); - } - } + string write(const math::number::Z_bytes &z); + + // all valid decimal strings are uniquely associated with + // a natural number, so we can use a strong ordering. + std::strong_ordering operator<=>(const string &, const string &); + + string &operator++(string&); + string &operator--(string&); + + string operator++(string&, int); + string operator--(string&, int); - namespace hexidecimal { - static constexpr ctll::fixed_string pattern{"0x((([0-9a-f][0-9a-f])*)|(([0-9A-F][0-9A-F])*))"}; - static constexpr ctll::fixed_string zero_pattern{"0x(00)*"}; + string operator-(const string &); - bool inline valid(string_view s) { - return ctre::match(s); - } + string operator+(const string&, const string&); + string operator-(const string&, const string&); + string operator*(const string&, const string&); + + string operator<<(const string&, int); + string operator>>(const string&, int); - bool inline zero(string_view s) { - return ctre::match(s); - } + string operator|(const string&, const string&); + string operator&(const string&, const string&); - bool inline nonzero(string_view s) { - return valid(s) && !ctre::match(s); - } + string operator/(const string&, const string&); - uint32 inline digits(string_view s) { - return valid(s) ? s.size() - 2 : 0; - } + string operator+(const string &n, const decimal::string &x); + string operator-(const string &n, const decimal::string &x); + string operator*(const string &n, const decimal::string &x); + string operator|(const string &n, const decimal::string &x); + string operator&(const string &n, const decimal::string &x); + string operator/(const string &n, const decimal::string &x); - char inline digit(char x) { - if (x >= '0' && x <= '9') return x - '0'; - if (x >= 'A' && x <= 'F') return x - 'A' + 10; - if (x >= 'a' && x <= 'f') return x - 'a' + 10; - return -1; - } + decimal::string operator%(const string&, const decimal::string &x); - hex::letter_case read_case(string_view s); + string &operator+=(string &n, const decimal::string &x); + string &operator-=(string &n, const decimal::string &x); + string &operator*=(string &n, const decimal::string &x); + string &operator|=(string &n, const decimal::string &x); + string &operator&=(string &n, const decimal::string &x); + string &operator/=(string &n, const decimal::string &x); + } - template - ptr> read(string_view s) { - if (!valid(s)) return nullptr; - - ptr> n = std::make_shared>(); - n->resize((s.size() - 2) / 2); - boost::algorithm::unhex(s.begin() + 2, s.end(), n->words().rbegin()); - - return n; - } + namespace hexidecimal { + static constexpr ctll::fixed_string pattern{"0x((([0-9a-f][0-9a-f])*)|(([0-9A-F][0-9A-F])*))"}; + static constexpr ctll::fixed_string zero_pattern{"0x(00)*"}; + + bool valid(string_view s); + bool zero(string_view s); + bool nonzero(string_view s); + uint32 digits(string_view s); + char digit(char x); + hex::letter_case read_case(string_view s); + template - std::ostream inline &write(std::ostream &o, const oriented &d, hex::letter_case q) { - o << "0x"; - return encoding::hex::write(o, d.words().reverse(), q); - } + ptr> read(string_view s); template - string write(const oriented &z, hex::letter_case q) { - std::stringstream ss; - write(ss, z, q); - return ss.str(); - } + std::ostream inline &write(std::ostream &o, const oriented &d, hex::letter_case q); - struct N : string { - - N(); - N(const string&); - N(uint64); - - bool valid() const { - return hexidecimal::valid(*this); - } - - bool operator==(const N&) const; - bool operator!=(const N&) const; - - bool operator<=(const N&) const; - bool operator>=(const N&) const; - bool operator<(const N&) const; - bool operator>(const N&) const; + struct string; - N& operator++(); - N& operator--(); - - N operator++(int); - N operator--(int); - - N operator+(const N&) const; - N operator-(const N&) const; - N operator*(const N&) const; - - N operator<<(int) const; - N operator>>(int) const; - - N& operator+=(const N&); - N& operator-=(const N&); - N& operator*=(const N&); - - N& operator<<=(int); - N& operator>>=(int); - - math::division divide(uint64) const; - - }; + template + string write(const oriented &z, hex::letter_case q); } @@ -218,21 +158,10 @@ namespace data::encoding { static constexpr ctll::fixed_string zero_pattern{"0|0x(00)*"}; - bool inline valid(string_view s) { - return ctre::match(s); - } - - bool inline zero(string_view s) { - return ctre::match(s); - } - - bool inline nonzero(string_view s) { - return valid(s) && ! ctre::match(s); - } - - uint32 inline digits(string_view s) { - return std::max(decimal::digits(s), hexidecimal::digits(s)); - } + bool valid(string_view s); + bool zero(string_view s); + bool nonzero(string_view s); + uint32 digits(string_view s); template ptr> read(string_view s); @@ -245,45 +174,612 @@ namespace data::encoding { static constexpr ctll::fixed_string negative_pattern{"(-(0*[1-9][0-9]*))|0x(([8-9a-f][0-9a-f]([0-9a-f][0-9a-f])*)|([8-9A-F][0-9A-F]([0-9A-F][0-9A-F])*))"}; - bool inline valid(string_view s) { - return ctre::match(s); - } + bool valid(string_view s); + bool negative(string_view s); + bool zero(string_view s); + bool nonzero(string_view s); + uint32 digits(string_view s); - bool inline negative(string_view s) { - return ctre::match(s); - } + template + ptr> read(string_view s); + + } + +} + +namespace data { + using dec_uint = encoding::decimal::string; + using dec_int = encoding::signed_decimal::string; + using hex_uint = encoding::hexidecimal::string; + + math::sign sign(const dec_uint&); + math::sign sign(const dec_int&); + math::sign sign(const hex_uint&); + + dec_uint increment(const dec_uint&); + dec_uint decrement(const dec_uint&); + + dec_int increment(const dec_int&); + dec_int decrement(const dec_int&); + + hex_uint increment(const hex_uint&); + hex_uint decrement(const hex_uint&); + +} + +namespace data::math { + + template <> struct abs { + dec_uint operator()(const dec_uint&); + }; + + template <> struct abs { + dec_uint operator()(const dec_int&); + }; + + template <> struct abs { + hex_uint operator()(const hex_uint&); + }; + +} + +namespace data::math::number { + + bool is_zero(const hex_uint &); + bool is_negative(const hex_uint &); + bool is_positive(const hex_uint &); + + bool is_zero(const dec_uint &); + bool is_negative(const dec_uint &); + bool is_positive(const dec_uint &); + + bool is_zero(const dec_int &); + bool is_negative(const dec_int &); + bool is_positive(const dec_int &); + +} + +namespace data::encoding::decimal { + + struct string : std::string { + string() : std::string{"0"} {}; - bool inline zero(string_view s) { - return ctre::match(s); + explicit string(const std::string &x) : std::string{decimal::valid(x) ? x : ""} {} + explicit string(std::string &&x) : std::string{x} {} + string(uint64); + + bool valid() const { + return decimal::valid(*this); } - bool inline nonzero(string_view s) { - return valid(s) && ! ctre::match(s); + static string read(string_view x); + + string &operator+=(const string&); + string &operator-=(const string&); + string &operator*=(const string&); + + string &operator<<=(int); + string &operator>>=(int); + + string &operator|=(const string&) const; + string &operator&=(const string&) const; + + math::division divide(uint64) const; + + bool operator==(uint64) const; + std::strong_ordering operator<=>(uint64) const; + + string operator+(uint64) const; + string operator-(uint64) const; + string operator*(uint64) const; + + string &operator+=(uint64); + string &operator-=(uint64); + string &operator*=(uint64); + + explicit operator double() const; + }; + + signed_decimal::string operator-(const string &); + +} + +namespace data::encoding::signed_decimal { + + struct string : std::string { + string() : std::string{"0"} {}; + explicit string(const std::string &x) : std::string{signed_decimal::valid(x) ? x : ""} {} + explicit string(std::string &&x) : std::string{x} {} + string(int64); + + bool valid() const { + return signed_decimal::valid(*this); } - uint32 inline digits(string_view s) { - return negative(s) ? natural::digits(s.substr(1, s.size() - 1)) : natural::digits(s); + static string read(string_view x); + + string &operator+=(const string&); + string &operator-=(const string&); + string &operator*=(const string&); + + string &operator<<=(int); + string &operator>>=(int); + + string &operator|=(const string&) const; + string &operator&=(const string&) const; + + math::division divide(int64) const; + + bool operator==(int64) const; + std::strong_ordering operator<=>(int64) const; + + string operator+(int64)const; + string operator-(int64) const; + string operator*(int64) const; + + string &operator+=(int64); + string &operator-=(int64); + string &operator*=(int64); + + explicit operator double() const; + }; + +} + +namespace data::encoding::hexidecimal { + + struct string : std::string { + + string() : std::string{"0x"} {}; + explicit string(string_view x) : std::string{hexidecimal::valid(x) ? x : ""} {} + explicit string(std::string &&x) : std::string{x} {} + string(uint64); + + static string read(string_view x); + + bool valid() const { + return hexidecimal::valid(*this); } - template - ptr> read(string_view s) { - if (!valid(s)) return nullptr; - - if (hexidecimal::valid(s)) { - auto z = hexidecimal::read(s); - if (z == nullptr) return nullptr; - auto x = std::make_shared>(); - x->resize(z->size()); - std::copy(z->begin(), z->end(), x->begin()); - return x; - } - - auto z = signed_decimal::read(s); + bool operator==(const string&) const; + std::weak_ordering operator<=>(const string&) const; + + string& operator++(); + string& operator--(); + + string operator++(int); + string operator--(int); + + string operator+(const string&) const; + string operator-(const string&) const; + string operator*(const string&) const; + + string operator<<(int) const; + string operator>>(int) const; + + string& operator+=(const string&); + string& operator-=(const string&); + string& operator*=(const string&); + + string& operator<<=(int); + string& operator>>=(int); + + math::division divide(uint64) const; + + }; + +} + +namespace data::math { + + template + struct root { + set operator()(const dec_uint& n); + }; + + template + struct root { + set operator()(const dec_int& n); + }; + + template + struct root { + set operator()(const hex_uint& n); + }; + +} + +namespace data::encoding::decimal { + + std::string inline characters() { + return "0123456789"; + } + + char inline digit(char x) { + return x < '0' || x > '9' ? -1 : x - '0'; + } + + bool inline valid(string_view s) { + return ctre::match(s); + } + + bool inline nonzero(string_view s) { + return valid(s) && s[0] != '0'; + } + + uint32 inline digits(string_view s) { + return valid(s) ? s.size() : 0; + } + + string inline &string::operator+=(const string &x) { + return *this = *this + x; + } + + string inline &string::operator-=(const string &x) { + return *this = *this - x; + } + + string inline &string::operator*=(const string &x) { + return *this = *this * x; + } + + string inline &string::operator<<=(int x) { + return *this = *this << x; + } + + string inline &string::operator>>=(int x) { + return *this = *this >> x; + } + + string inline string::operator+(uint64 x) const { + return *this + string{x}; + } + + string inline string::operator-(uint64 x) const { + return *this - string{x}; + } + + string inline string::operator*(uint64 x) const { + return *this * string{x}; + } + + string inline &string::operator+=(uint64 x) { + return *this += string{x}; + } + + string inline &string::operator-=(uint64 x) { + return *this -= string{x}; + } + + string inline &string::operator*=(uint64 x) { + return *this *= string{x}; + } + +} + +namespace data::encoding::signed_decimal { + + bool inline valid(string_view s) { + return ctre::match(s); + } + + bool inline nonzero(string_view s) { + return valid(s) && s[0] != '0'; + } + + bool inline negative(string_view s) { + return valid(s) && s[0] == '-'; + } + + bool inline positive(string_view s) { + return valid(s) && s[0] != '-' && s[0] != '0'; + } + + math::sign inline sign(string_view s) { + if (!valid(s)) throw std::invalid_argument{std::string{"invalid decimal string: "} + std::string{s}}; + return s[0] == '-' ? math::negative : s[0] == '0' ? math::zero : math::positive; + } + + template + std::ostream inline &write(std::ostream &o, const math::number::Z_bytes &z) { + if (math::number::is_negative(z)) o << '-'; + return decimal::write(o, data::abs(z)); + } + + string inline string::operator+(int64 x) const { + return *this + string{x}; + } + + string inline string::operator-(int64 x) const { + return *this - string{x}; + } + + string inline string::operator*(int64 x) const { + return *this * string{x}; + } + + string inline &string::operator+=(int64 x) { + return *this += string{x}; + } + + string inline &string::operator-=(int64 x) { + return *this += string{x}; + } + + string inline &string::operator*=(int64 x) { + return *this += string{x}; + } + + string inline operator+(const string &n, const decimal::string &x) { + return n + string{static_cast(x)}; + } + + string inline operator-(const string &n, const decimal::string &x) { + return n - string{static_cast(x)}; + } + + string inline operator*(const string &n, const decimal::string &x) { + return n * string{static_cast(x)}; + } + + string inline operator|(const string &n, const decimal::string &x) { + return n | string{static_cast(x)}; + } + + string inline operator&(const string &n, const decimal::string &x) { + return n & string{static_cast(x)}; + } + + string inline &operator+=(string &n, const decimal::string &x) { + return n += string{static_cast(x)}; + } + + string inline &operator-=(string &n, const decimal::string &x) { + return n -= string{static_cast(x)}; + } + + string inline &operator*=(string &n, const decimal::string &x) { + return n *= string{static_cast(x)}; + } + + string inline &operator|=(string &n, const decimal::string &x) { + return n |= string{static_cast(x)}; + } + + string inline &operator&=(string &n, const decimal::string &x) { + return n &= string{static_cast(x)}; + } + + string inline operator/(const string &n, const decimal::string &x) { + return n / string{static_cast(x)}; + } + +} + +namespace data::encoding::hexidecimal { + + bool inline valid(string_view s) { + return ctre::match(s); + } + + bool inline zero(string_view s) { + return ctre::match(s); + } + + bool inline nonzero(string_view s) { + return valid(s) && !ctre::match(s); + } + + uint32 inline digits(string_view s) { + return valid(s) ? s.size() - 2 : 0; + } + + char inline digit(char x) { + if (x >= '0' && x <= '9') return x - '0'; + if (x >= 'A' && x <= 'F') return x - 'A' + 10; + if (x >= 'a' && x <= 'f') return x - 'a' + 10; + return -1; + } + + template + ptr> read(string_view s) { + if (!valid(s)) return nullptr; + + ptr> n = std::make_shared>(); + n->resize((s.size() - 2) / 2); + boost::algorithm::unhex(s.begin() + 2, s.end(), n->words().rbegin()); + + return n; + } + + template + std::ostream inline &write(std::ostream &o, const oriented &d, hex::letter_case q) { + o << "0x"; + return encoding::hex::write(o, d.words().reverse(), q); + } + + template + string write(const oriented &z, hex::letter_case q) { + std::stringstream ss; + write(ss, z, q); + return string{ss.str()}; + } + +} + +namespace data::encoding::natural { + + bool inline valid(string_view s) { + return ctre::match(s); + } + + bool inline zero(string_view s) { + return ctre::match(s); + } + + bool inline nonzero(string_view s) { + return valid(s) && ! ctre::match(s); + } + + uint32 inline digits(string_view s) { + return std::max(decimal::digits(s), hexidecimal::digits(s)); + } + +} + +namespace data::encoding::integer { + + bool inline valid(string_view s) { + return ctre::match(s); + } + + bool inline negative(string_view s) { + return ctre::match(s); + } + + bool inline zero(string_view s) { + return ctre::match(s); + } + + bool inline nonzero(string_view s) { + return valid(s) && ! ctre::match(s); + } + + uint32 inline digits(string_view s) { + return negative(s) ? natural::digits(s.substr(1, s.size() - 1)) : natural::digits(s); + } + + template + ptr> read(string_view s) { + if (!valid(s)) return nullptr; + + if (hexidecimal::valid(s)) { + auto z = hexidecimal::read(s); if (z == nullptr) return nullptr; - return std::make_shared>(math::number::Z_bytes(*z)); + auto x = std::make_shared>(); + x->resize(z->size()); + std::copy(z->begin(), z->end(), x->begin()); + return x; } - }; + auto z = signed_decimal::read(s); + if (z == nullptr) return nullptr; + return std::make_shared>(math::number::Z_bytes(*z)); + } + +} + +namespace data::math::number { + + bool inline is_zero(const hex_uint &n) { + if (!encoding::hexidecimal::valid(n)) throw std::invalid_argument{std::string{"invalid hexidecimal string: "} + std::string{n}}; + return !encoding::hexidecimal::nonzero(n); + } + + bool inline is_negative(const hex_uint &n) { + if (!encoding::hexidecimal::valid(n)) throw std::invalid_argument{std::string{"invalid hexidecimal string: "} + std::string{n}}; + return false; + } + + bool inline is_positive(const hex_uint &n) { + if (!encoding::hexidecimal::valid(n)) throw std::invalid_argument{std::string{"invalid hexidecimal string: "} + std::string{n}}; + return encoding::hexidecimal::nonzero(n); + } + + bool inline is_zero(const dec_uint &n) { + if (!encoding::decimal::valid(n)) throw std::invalid_argument{std::string{"invalid decimal string: "} + std::string{n}}; + return !encoding::decimal::nonzero(n); + } + + bool inline is_negative(const dec_uint &n) { + if (!encoding::decimal::valid(n)) throw std::invalid_argument{std::string{"invalid decimal string: "} + std::string{n}}; + return false; + } + + bool inline is_positive(const dec_uint &n) { + if (!encoding::decimal::valid(n)) throw std::invalid_argument{std::string{"invalid decimal string: "} + std::string{n}}; + return encoding::decimal::nonzero(n); + } + + bool inline is_zero(const dec_int &n) { + if (!encoding::signed_decimal::valid(n)) throw std::invalid_argument{std::string{"invalid decimal string: "} + std::string{n}}; + return !encoding::signed_decimal::nonzero(n); + } + + bool inline is_negative(const dec_int &n) { + if (!encoding::signed_decimal::valid(n)) throw std::invalid_argument{std::string{"invalid decimal string: "} + std::string{n}}; + return encoding::signed_decimal::negative(n); + } + + bool inline is_positive(const dec_int &n) { + if (!encoding::signed_decimal::valid(n)) throw std::invalid_argument{std::string{"invalid decimal string: "} + std::string{n}}; + return encoding::signed_decimal::positive(n); + } + +} + +namespace data { + + math::sign inline sign(const dec_uint &n) { + if (!encoding::decimal::valid(n)) throw std::invalid_argument{std::string{"invalid decimal string: "} + std::string{n}}; + return encoding::decimal::nonzero(n) ? math::positive : math::zero; + } + + math::sign inline sign(const dec_int &n) { + return encoding::signed_decimal::sign(n); + } + + math::sign inline sign(const hex_uint &n) { + if (!encoding::hexidecimal::valid(n)) throw std::invalid_argument{std::string{"invalid hexidecimal string: "} + std::string{n}}; + return encoding::hexidecimal::nonzero(n) ? math::positive : math::zero; + } + + dec_uint inline increment(const dec_uint &n) { + auto x = n; + return ++x; + } + + dec_uint inline decrement(const dec_uint &n) { + auto x = n; + return --x; + } + + dec_int inline increment(const dec_int &n) { + auto x = n; + return ++x; + } + + dec_int inline decrement(const dec_int &n) { + auto x = n; + return --x; + } + + hex_uint inline increment(const hex_uint &n) { + auto x = n; + return ++x; + } + + hex_uint inline decrement(const hex_uint &n) { + auto x = n; + return --x; + } + +} + +namespace data::math { + + dec_uint inline abs::operator()(const dec_uint &x) { + return x; + } + + dec_uint inline abs::operator()(const dec_int &x) { + if (encoding::signed_decimal::negative(x)) return dec_uint{x.substr(1)}; + return dec_uint{x}; + } + + hex_uint inline abs::operator()(const hex_uint &x) { + return x; + } } diff --git a/include/data/math/number/bytes/N.hpp b/include/data/math/number/bytes/N.hpp index a6247522..e5c92125 100644 --- a/include/data/math/number/bytes/N.hpp +++ b/include/data/math/number/bytes/N.hpp @@ -100,10 +100,6 @@ namespace data::math::number { std::copy(b.begin(), b.end(), this->begin()); } - math::sign sign() const { - return *this == N_bytes(uint64(0)) ? math::zero : positive; - } - operator N_bytes() const { N_bytes z; z.resize(this->size()); @@ -124,15 +120,9 @@ namespace data::math::number { return N_bytes(size, 0x00); } - N_bytes& operator++() { - operator+=(1); - return *this; - } + N_bytes& operator++(); - N_bytes& operator--() { - operator+=(1); - return *this; - } + N_bytes& operator--(); N_bytes operator++(int) const { N_bytes z = *this; @@ -311,7 +301,7 @@ namespace data::encoding::decimal { string inline write(const math::number::N_bytes &n) { std::stringstream ss; write(ss, n); - return ss.str(); + return string{ss.str()}; } } @@ -372,6 +362,20 @@ namespace data::math::number { return a <=> N_bytes(b); } + template + N_bytes& N_bytes::operator++() { + *this = extend(*this, this->size() + 1); + data::arithmetic::plus(this->words().end(), this->words().begin(), 1, this->words().begin()); + return this->trim(); + } + + template + N_bytes& N_bytes::operator--() { + if (is_zero(*this)) return *this; + data::arithmetic::minus(this->words().end(), this->words().begin(), 1, this->words().begin()); + return this->trim(); + } + template Z_bytes inline operator&(const N_bytes &a, const Z_bytes &b) { return Z_bytes(a) & b; } @@ -505,6 +509,32 @@ namespace data { math::sign inline sign(const math::N_bytes &n) { return math::arithmetic::N_sign(n.words()); } + + template + math::sign inline sign(const math::Z_bytes &n) { + return math::arithmetic::Z_sign_ones(n.words()); + } + + template math::number::N_bytes inline increment(const math::number::N_bytes &n) { + auto x = n; + return ++x; + } + + template math::number::N_bytes inline decrement(const math::number::N_bytes &n) { + auto x = n; + return --x; + } + + template math::number::Z_bytes inline increment(const math::number::Z_bytes &n) { + auto x = n; + return ++x; + } + + template math::number::Z_bytes inline decrement(const math::number::Z_bytes &n) { + auto x = n; + return --x; + } + } #endif diff --git a/include/data/math/number/bytes/Z.hpp b/include/data/math/number/bytes/Z.hpp index 658469c2..e3272d71 100644 --- a/include/data/math/number/bytes/Z.hpp +++ b/include/data/math/number/bytes/Z.hpp @@ -60,13 +60,6 @@ namespace data::math::number { return Z_bytes(size, 0x00); } - math::sign sign() const { - if (this->size() == 0) return math::zero; - if (is_negative(*this)) return negative; - if (is_zero(*this)) return math::zero; - return positive; - } - Z_bytes operator~() const { Z_bytes z = extend(*this, this->size() + 1); data::arithmetic::bit_negate(z.end(), z.begin(), z.begin()); @@ -389,13 +382,6 @@ namespace data::math { } } -namespace data { - template - math::sign inline sign(const math::Z_bytes &n) { - return math::arithmetic::Z_sign_ones(n.words()); - } -} - namespace data::encoding::signed_decimal { template @@ -409,6 +395,13 @@ namespace data::encoding::signed_decimal { return z; } + template + string inline write(const math::number::Z_bytes &z) { + std::stringstream ss; + write(ss, z); + return string{ss.str()}; + } + } #endif diff --git a/include/data/math/number/bytes/bytes.hpp b/include/data/math/number/bytes/bytes.hpp index 92ea1a41..e9a2c0d0 100644 --- a/include/data/math/number/bytes/bytes.hpp +++ b/include/data/math/number/bytes/bytes.hpp @@ -198,11 +198,6 @@ namespace data::math { }; template number::N_bytes next(const number::N_bytes&); - template number::N_bytes increment(const number::N_bytes&); - template number::N_bytes decrement(const number::N_bytes&); - - template number::Z_bytes increment(const number::Z_bytes&); - template number::Z_bytes decrement(const number::Z_bytes&); // Declare that the plus and times operation are commutative and associative. template @@ -242,6 +237,12 @@ namespace data { template math::sign sign(const math::N_bytes &); template math::sign sign(const math::Z_bytes &); + template math::number::N_bytes increment(const math::number::N_bytes&); + template math::number::N_bytes decrement(const math::number::N_bytes&); + + template math::number::Z_bytes increment(const math::number::Z_bytes&); + template math::number::Z_bytes decrement(const math::number::Z_bytes&); + } // functions for reading and wriing these numbers in various formats. @@ -271,6 +272,8 @@ namespace data::encoding::hexidecimal { template std::ostream inline &write(std::ostream &o, const oriented &d, hex::letter_case q = hex::lower); + struct string; + template string write(const oriented &z, hex::letter_case q = hex::lower); diff --git a/include/data/math/number/gmp/N.hpp b/include/data/math/number/gmp/N.hpp index bf4db1c3..ef2d0650 100644 --- a/include/data/math/number/gmp/N.hpp +++ b/include/data/math/number/gmp/N.hpp @@ -376,20 +376,20 @@ namespace data::math { namespace data::encoding::hexidecimal { - std::string inline write(const math::N &n) { + string inline write(const math::N &n) { std::stringstream ss; write(ss, n); - return ss.str(); + return string{ss.str()}; } } namespace data::encoding::decimal { - N inline write(const math::N& n) { + string inline write(const math::N& n) { std::stringstream ss; write(ss, n); - return {ss.str()}; + return string{ss.str()}; } } @@ -400,6 +400,39 @@ namespace data { return math::number::GMP::sign(z.Value.MPZ[0]); } + math::sign inline sign(const math::Z &z) { + return math::number::GMP::sign(z.MPZ[0]); + } + + math::N inline square(const math::N &n) { + return n * n; + } + + math::N inline square(const math::Z &z) { + auto n = abs(z); + return n * n; + } + + math::N inline increment(const math::N &n) { + auto x = n; + return ++x; + } + + math::N inline decrement(const math::N &n) { + auto x = n; + return --x; + } + + math::Z inline increment(const math::Z &n) { + auto x = n; + return ++x; + } + + math::Z inline decrement(const math::Z &n) { + auto x = n; + return --x; + } + } #endif diff --git a/include/data/math/number/gmp/Z.hpp b/include/data/math/number/gmp/Z.hpp index 22759964..719c6569 100644 --- a/include/data/math/number/gmp/Z.hpp +++ b/include/data/math/number/gmp/Z.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -174,30 +175,22 @@ namespace data::math { } } -namespace data { - - math::sign inline sign(const math::Z &z) { - return math::number::GMP::sign(z.MPZ[0]); - } - -} - namespace data::encoding::hexidecimal { - std::string inline write(const math::Z& n) { + string inline write(const math::Z& n) { std::stringstream ss; write(ss, n); - return ss.str(); + return string{ss.str()}; } } namespace data::encoding::signed_decimal { - std::string inline write(const math::Z& n) { + string inline write(const math::Z& n) { std::stringstream ss; write(ss, n); - return ss.str(); + return string{ss.str()}; } } diff --git a/include/data/math/number/gmp/mpz.hpp b/include/data/math/number/gmp/mpz.hpp index f0ae2535..ad3cfb5f 100644 --- a/include/data/math/number/gmp/mpz.hpp +++ b/include/data/math/number/gmp/mpz.hpp @@ -171,15 +171,6 @@ namespace data::math { N operator()(const Z&); }; - N square(const N &n); - N square(const Z &z); - - N increment(const N&); - N decrement(const N&); - - Z increment(const Z&); - Z decrement(const Z&); - template <> struct commutative, N> {}; template <> struct associative, N> {}; template <> struct commutative, N> {}; @@ -214,37 +205,41 @@ namespace data::math { namespace data { - math::sign inline sign(const math::N &x); - math::sign inline sign(const math::Z &x); + math::sign sign(const math::N &x); + math::sign sign(const math::Z &x); + + math::N square(const math::N &n); + math::N square(const math::Z &z); + + math::N increment(const math::N&); + math::N decrement(const math::N&); + + math::Z increment(const math::Z&); + math::Z decrement(const math::Z&); + } namespace data::encoding::decimal { - struct N; - N write(const math::N&); + struct string; + string write(const math::N&); std::ostream &write(std::ostream &, const math::N &); } namespace data::encoding::hexidecimal { - - std::string write(const math::Z&); - std::string write(const math::N&); + struct string; + string write(const math::Z&); + string write(const math::N&); std::ostream &write(std::ostream &, const math::Z &); std::ostream &write(std::ostream &, const math::N &); } -namespace data::encoding::natural { - - std::string write(const math::N&); - -} - namespace data::encoding::signed_decimal { - - std::string write(const math::Z&); + struct string; + string write(const math::Z&); std::ostream &write(std::ostream &, const math::Z &); diff --git a/include/data/math/number/gmp/sqrt.hpp b/include/data/math/number/gmp/sqrt.hpp index 298212fa..baa944df 100644 --- a/include/data/math/number/gmp/sqrt.hpp +++ b/include/data/math/number/gmp/sqrt.hpp @@ -28,6 +28,32 @@ namespace data::math { return number::GMP::root(z, pow); } }; + + template + set root::operator()(const dec_uint& n) { + std::cout << " taking root of " << n << std::endl; + set x; + set roots = root{}(N::read(n)); + for (const N &z : roots.values()) x = insert(x, encoding::decimal::write(z)); + return x; + } + + template + set root::operator()(const dec_int& n) { + set x; + set roots = root{}(Z::read(n)); + for (const Z &z : roots.values()) x = insert(x, encoding::signed_decimal::write(z)); + return x; + } + + template + set root::operator()(const hex_uint& n) { + std::cout << " taking root of " << n << std::endl; + set x; + set roots = root{}(N::read(n)); + for (const N &z : roots.values()) x = insert(x, encoding::hexidecimal::write(z)); + return x; + } } diff --git a/include/data/numbers.hpp b/include/data/numbers.hpp index 807db3dc..7ec61213 100644 --- a/include/data/numbers.hpp +++ b/include/data/numbers.hpp @@ -77,6 +77,11 @@ namespace data { using int448 = int_little<56>; using int512 = int_little<64>; + using dec_uint = encoding::decimal::string; + using dec_int = encoding::signed_decimal::string; + using hex_uint = encoding::hexidecimal::string; + using base58_uint = encoding::base58::string; + // rational numbers. using Q = math::fraction; @@ -105,4 +110,15 @@ namespace data { } +namespace data::math { + + template + set root::operator()(const base58_uint& n) { + set x; + set roots = root{}(encoding::base58::read(n)); + for (const N &z : roots.values()) x = insert(x, encoding::base58::write(z)); + return x; + } +} + #endif diff --git a/src/data/encoding/base58.cpp b/src/data/encoding/base58.cpp index 2fe3f78f..1a5e2024 100644 --- a/src/data/encoding/base58.cpp +++ b/src/data/encoding/base58.cpp @@ -30,7 +30,7 @@ namespace data::encoding::base58 { string::string() : std::string{"1"} {} - string::string(const std::string& x) : std::string{base58::valid(x) ? x : ""} {} + string::string(string_view x) : std::string{base58::valid(x) ? x : ""} {} string::string(uint64 x) : std::string{write_b58(nat{x})} {} @@ -38,20 +38,22 @@ namespace data::encoding::base58 { return read_base(n, 58, &digit); } - bool string::operator<=(const string& n) const { - return read_num(*this) <= read_num(n); - } - - bool string::operator>=(const string& n) const { - return read_num(*this) >= read_num(n); - } - - bool string::operator<(const string& n) const { - return read_num(*this) < read_num(n); + // TODO it should be possible to compare decimal strings + // with basic functions in math::arithmetic. + std::strong_ordering N_compare(string_view a, string_view b) { + std::strong_ordering cmp_size = a.size() <=> b.size(); + if (cmp_size != std::strong_ordering::equal) return cmp_size; + + for (int i = 0; i < a.size(); i++) { + std::strong_ordering cmp_chr = digit(a[i]) <=> digit(b[i]); + if (cmp_chr != std::strong_ordering::equal) return cmp_chr; + } + + return std::strong_ordering::equal; } - bool string::operator>(const string& n) const { - return read_num(*this) > read_num(n); + std::strong_ordering string::operator<=>(const string &n) const { + return N_compare(*this, n); } string string::operator+(const string& n) const { @@ -125,7 +127,11 @@ namespace data::encoding::base58 { } math::division div = read_num(*this).divide(nat{static_cast(x)}); - return math::division{write_b58(div.Quotient), uint64(div.Remainder)}; + return math::division{string{write_b58(div.Quotient)}, uint64(div.Remainder)}; + } + + string string::read(string_view x) { + return base58::write(nat::read(x)); } } diff --git a/src/data/encoding/integer.cpp b/src/data/encoding/integer.cpp index 49782f60..6a71e741 100644 --- a/src/data/encoding/integer.cpp +++ b/src/data/encoding/integer.cpp @@ -5,9 +5,7 @@ #include #include #include -#include -#include -#include +#include #include #include @@ -15,120 +13,283 @@ namespace data::encoding { namespace decimal { - using nat = math::N; + string::string(uint64 x) : string{decimal::write(x)} {} - ptr read(string_view s, endian::order r) { - if (!valid(s)) return nullptr; - math::number::N_bytes n{nat{s}}; - if (r == endian::little) std::reverse(n.begin(), n.end()); - return std::make_shared(static_cast(n)); + // TODO it should be possible to compare decimal strings + // with basic functions in math::arithmetic. + std::strong_ordering N_compare(string_view a, string_view b) { + std::strong_ordering cmp_size = a.size() <=> b.size(); + if (cmp_size != std::strong_ordering::equal) return cmp_size; + + for (int i = 0; i < a.size(); i++) { + std::strong_ordering cmp_chr = digit(a[i]) <=> digit(b[i]); + if (cmp_chr != std::strong_ordering::equal) return cmp_chr; + } + + return std::strong_ordering::equal; } - N::N() : string{"0"} {} + std::strong_ordering operator<=>(const string &m, const string &n) { + if (!m.valid() || !n.valid()) throw std::invalid_argument{"invalid decimal string"}; + return N_compare(m, n); + } - N::N(const string& x) : string{decimal::valid(x) ? x : ""} {} + char N_increment(string &x) { + auto characters = decimal::characters(); + + auto i = x.rbegin(); + auto e = x.rend(); + char remainder = 1; + while (i != e) { + auto d = digit(*i) + remainder; + *i = characters[d % 10]; + remainder = d / 10; + if (remainder == 0) return '0'; + i++; + } + return characters[remainder]; + } - template - std::string write_decimal(const N& n) { - static std::string Characters = characters(); - if (n == 0) return "0"; - return write_base(n, Characters); + string &operator++(string &x) { + if (!x.valid()) throw std::invalid_argument{"invalid dec string"}; + char remainder = N_increment(x); + if (remainder == '0') return x; + string new_x; + new_x.resize(x.size() + 1); + new_x[0] = remainder; + std::copy(x.begin(), x.end(), new_x.begin() + 1); + return x = new_x; } - N::N(uint64 x) : string{write_decimal(nat{x})} {} + void N_decrement(string &x) { + auto characters = decimal::characters(); + + auto i = x.rbegin(); + auto e = x.rend(); + while (i != e) { + auto d = digit(*i); + if (d != 0) { + *i = characters[d - 1]; + break; + } + *i = characters[9]; + i++; + } + } - inline nat read_num(const N& n) { - return read_base(n, 10, &digit); + string &operator--(string &x) { + if (!x.valid()) throw std::invalid_argument{"invalid dec string"}; + if (x == "0") return x; + if (x == "1") return x = string{"0"}; + + N_decrement(x); + + if (!valid(x)) return x = string{x.substr(1)}; + return x; } - bool N::operator<=(const N& n) const { - return read_num(*this) <= read_num(n); + string operator+(const string &m, const string& n) { + if (!m.valid()) throw std::invalid_argument{"invalid dec string"}; + if (!n.valid()) throw std::invalid_argument{"invalid dec string"}; + return decimal::write(N::read(m) + N::read(n)); } - bool N::operator>=(const N& n) const { - return read_num(*this) >= read_num(n); + string operator-(const string &m, const string& n) { + if (!m.valid()) throw std::invalid_argument{"invalid dec string"}; + if (!n.valid()) throw std::invalid_argument{"invalid dec string"}; + return decimal::write(N::read(m) - N::read(n)); } - bool N::operator<(const N& n) const { - return read_num(*this) < read_num(n); + string operator*(const string &m, const string& n) { + if (!m.valid()) throw std::invalid_argument{"invalid dec string"}; + if (!n.valid()) throw std::invalid_argument{"invalid dec string"}; + return decimal::write(N::read(m) * N::read(n)); } - bool N::operator>(const N& n) const { - return read_num(*this) > read_num(n); + string operator<<(const string &m, int i) { + if (!m.valid()) throw std::invalid_argument{"invalid dec string"}; + return decimal::write(N::read(m) << i); } - N N::operator+(const N& n) const { - return N{write_decimal(read_num(*this) + read_num(n))}; + string operator>>(const string &m, int i) { + if (!m.valid()) throw std::invalid_argument{"invalid dec string"}; + return decimal::write(N::read(m) >> i); } - N N::operator-(const N& n) const { - return N{write_decimal(read_num(*this) - read_num(n))}; + string operator&(const string &m, const string& n) { + if (!m.valid()) throw std::invalid_argument{"invalid dec string"}; + if (!n.valid()) throw std::invalid_argument{"invalid dec string"}; + return decimal::write(math::N_bytes::read(m) & math::N_bytes::read(n)); } - N N::operator*(const N& n) const { - return N{write_decimal(read_num(*this) * read_num(n))}; + string operator|(const string &m, const string& n) { + if (!m.valid()) throw std::invalid_argument{"invalid dec string"}; + if (!n.valid()) throw std::invalid_argument{"invalid dec string"}; + return decimal::write(math::N_bytes::read(m) | math::N_bytes::read(n)); + } + + math::division divide(const string &n, const N &x) { + if (x == 0) throw math::division_by_zero{}; + // it is important to have this optimization. + // I can't say why or I'll be embarrassed. + if (x == 10) { + int last = n.size() - 1; + return math::division{n.size() == 1 ? string{} : string(n.substr(0, last)), N(digit(n[last]))}; + } + + math::division div = math::number::natural::divide(N::read(n), x); + + return math::division{decimal::write(div.Quotient), div.Remainder}; + } + + math::division string::divide(uint64 x) const { + math::division div = decimal::divide(*this, N{x}); + return math::division{div.Quotient, uint64(div.Remainder)}; + } + + string operator/(const string &m, const string &x) { + return decimal::write(math::number::natural::divide(N::read(m), N::read(x)).Quotient); + } + + string operator%(const string &m, const string &x) { + return decimal::write(math::number::natural::divide(N::read(m), N::read(x)).Remainder); + } + + bool string::operator==(uint64 x) const { + return *this == string{x}; + } + + std::strong_ordering string::operator<=>(uint64 x) const { + return *this <=> string{x}; + } + + string::operator double() const { + return double(N::read(*this)); + } + + string string::read(string_view x) { + return decimal::write(N::read(x)); } - N& N::operator++() { - return *this = *this + 1; + signed_decimal::string operator-(const string &x) { + signed_decimal::string z; + z.resize(x.size() + 1); + z[0] = '-'; + std::copy(x.begin(), x.end(), z.begin() + 1); + return z; } + + } + + namespace signed_decimal { - N& N::operator--() { - return *this = *this - 1; + string::string(int64 x) : string{signed_decimal::write(x)} {} + + // TODO it should be possible to compare decimal strings + // with basic functions in math::arithmetic. + std::strong_ordering operator<=>(const string& m, const string& n) { + if (!m.valid() || !n.valid()) throw std::invalid_argument{"invalid hexidecimal string"}; + math::sign na = sign(m); + math::sign nb = sign(n); + + return na != nb ? na <=> nb : + na == math::negative && nb == math::negative ? + decimal::N_compare(string_view{n.data() + 1, n.size() - 1}, string_view{m.data() + 1, m.size() - 1}) : + decimal::N_compare(string_view{m.data(), m.size()}, string_view{n.data(), n.size()}); + } - N N::operator++(int) { - N n = *this; - ++(*this); - return n; + string &operator++(string &x) { + if (math::number::is_negative(x)) { + auto z = decimal::string{x.substr(1)}; + return x = -string{--z}; + } + + auto z = decimal::string{x}; + return x = string{++z}; } - N N::operator--(int) { - N n = *this; - --(*this); - return n; + string &operator--(string &x) { + if (!x.valid()) throw std::invalid_argument{"invalid +/-dec string"}; + + if (!nonzero(x)) return x = string{"-1"}; + + if (positive(x)) { + auto z = decimal::string{x}; + return x = string{--z}; + } + + auto z = decimal::string{x.substr(1)}; + return x = -string{++z}; } - N N::operator<<(int i) const { - return N{write_decimal(read_num(*this) << i)}; + string operator+(const string &m, const string& n) { + if (!m.valid()) throw std::invalid_argument{"invalid +/-dec string"}; + if (!n.valid()) throw std::invalid_argument{"invalid +/-dec string"}; + return signed_decimal::write(Z::read(m) + Z::read(n)); } - N N::operator>>(int i) const { - return N{write_decimal(read_num(*this) >> i)}; + string operator-(const string &m, const string& n) { + if (!m.valid()) throw std::invalid_argument{"invalid +/-dec string"}; + if (!n.valid()) throw std::invalid_argument{"invalid +/-dec string"}; + return signed_decimal::write(Z::read(m) - Z::read(n)); } - N& N::operator+=(const N& n) { - return *this = *this + n; + string operator*(const string &m, const string& n) { + if (!m.valid()) throw std::invalid_argument{"invalid +/-dec string"}; + if (!n.valid()) throw std::invalid_argument{"invalid +/-dec string"}; + return signed_decimal::write(Z::read(m) * Z::read(n)); } - N& N::operator-=(const N& n) { - return *this = *this - n; + string operator<<(const string &m, int i) { + if (!m.valid()) throw std::invalid_argument{"invalid +/-dec string"}; + return signed_decimal::write(Z::read(m) << i); } - N& N::operator*=(const N& n) { - return *this = *this * n; + string operator>>(const string &m, int i) { + if (!m.valid()) throw std::invalid_argument{"invalid +/-dec string"}; + return signed_decimal::write(Z::read(m) >> i); } - N& N::operator<<=(int i) { - return *this = *this << i; + string operator&(const string &m, const string& n) { + if (!m.valid()) throw std::invalid_argument{"invalid +/-dec string"}; + if (!n.valid()) throw std::invalid_argument{"invalid +/-dec string"}; + throw method::unimplemented{"signed_dec &"}; } - N& N::operator>>=(int i) { - return *this = *this >> i; + string operator|(const string &m, const string& n) { + if (!m.valid()) throw std::invalid_argument{"invalid +/-dec string"}; + if (!n.valid()) throw std::invalid_argument{"invalid +/-dec string"}; + throw method::unimplemented{"signed_dec |"}; } - math::division N::divide(uint64 x) const { - if (x == 0) throw math::division_by_zero{}; - // it is important to have this optimization. - if (x == 10) { - int last = string::size() - 1; - return math::division{ - N{string::substr(0, last)}, - static_cast(digit(string::operator[](last)))}; + bool string::operator==(int64 x) const { + return *this == string{x}; + } + + std::strong_ordering string::operator<=>(int64 x) const { + return *this <=> string{x}; + } + + string::operator double() const { + return double(N::read(*this)); + } + + string operator-(const string &n) { + string x; + if (negative(n)) { + x.resize(n.size() - 1); + std::copy(n.begin() + 1, n.end(), x.begin()); + } if (positive(n)) { + x[0] = '-'; + x.resize(n.size() + 1); + std::copy(n.begin(), n.end(), x.begin() + 1); } - - math::division div = read_num(*this).divide(nat{x}); - return math::division{write_decimal(div.Quotient), uint64(div.Remainder)}; + return x; + } + + string string::read(string_view x) { + return signed_decimal::write(Z::read(x)); } } @@ -137,10 +298,6 @@ namespace data::encoding { using nat = math::N; - N::N() : string{"0x"} {} - - N::N(const string& x) : string{hexidecimal::valid(x) ? x : ""} {} - template std::string write_hexidecimal(const N& n) { static std::string Characters = hex::characters_lower(); @@ -149,165 +306,116 @@ namespace data::encoding { if ((p.size() % 2) == 1) return std::string{"0x0"} + p; return std::string{"0x"} + p; } - - N::N(uint64 x) : string{write_hexidecimal(nat{x})} {} - - inline nat read_num(const N& n) { - return read_base(n.substr(2), 16, &digit); - } - - bool N::operator==(const N& n) const { - return read_num(*this) == read_num(n); + + std::weak_ordering N_compare_same_size(string_view a, string_view b) { + for (int i = 0; i < a.size(); i++) + if (digit(a[i]) > digit(b[i])) return std::weak_ordering::greater; + else if (digit(a[i]) < digit(b[i])) return std::weak_ordering::less; + + return std::weak_ordering::equivalent; } - bool N::operator!=(const N& n) const { - return read_num(*this) != read_num(n); + std::weak_ordering N_compare(string_view a, string_view b) { + if (a.size() < b.size()) return 0 <=> N_compare(b, a); + size_t size_difference = a.size() - b.size(); + for (int i = 0; i < size_difference; i++) if (a[i] != '0') return std::weak_ordering::greater; + return N_compare_same_size(a.substr(size_difference, a.size()), b); } - bool N::operator<=(const N& n) const { - return read_num(*this) <= read_num(n); + bool string::operator==(const string &b) const { + return (*this <=> b) == 0; } - - bool N::operator>=(const N& n) const { - return read_num(*this) >= read_num(n); + + std::weak_ordering string::operator<=>(const string &b) const { + if (!this->valid() || !b.valid()) throw std::invalid_argument{"invalid hexidecimal string"}; + return N_compare(string_view{this->data() + 2, this->size() - 2}, string_view{b.data() + 2, b.size() - 2}); } - bool N::operator<(const N& n) const { - return read_num(*this) < read_num(n); - } + string::string(uint64 x) : std::string{write_hexidecimal(nat{x})} {} - bool N::operator>(const N& n) const { - return read_num(*this) > read_num(n); + inline nat read_num(const std::string& n) { + return read_base(n.substr(2), 16, &digit); } - N N::operator+(const N& n) const { - return N{write_hexidecimal(read_num(*this) + read_num(n))}; + string string::operator+(const string& n) const { + return string{write_hexidecimal(read_num(*this) + read_num(n))}; } - N N::operator-(const N& n) const { - return N{write_hexidecimal(read_num(*this) - read_num(n))}; + string string::operator-(const string& n) const { + return string{write_hexidecimal(read_num(*this) - read_num(n))}; } - N N::operator*(const N& n) const { - return N{write_hexidecimal(read_num(*this) * read_num(n))}; + string string::operator*(const string& n) const { + return string{write_hexidecimal(read_num(*this) * read_num(n))}; } - N& N::operator++() { + string& string::operator++() { return *this = *this + 1; } - N& N::operator--() { + string& string::operator--() { return *this = *this - 1; } - N N::operator++(int) { - N n = *this; + string string::operator++(int) { + string n = *this; ++(*this); return n; } - N N::operator--(int) { - N n = *this; + string string::operator--(int) { + string n = *this; --(*this); return n; } - N N::operator<<(int i) const { - return N{write_hexidecimal(read_num(*this) << i)}; + string string::operator<<(int i) const { + return string{write_hexidecimal(read_num(*this) << i)}; } - N N::operator>>(int i) const { - return N{write_hexidecimal(read_num(*this) >> i)}; + string string::operator>>(int i) const { + return string{write_hexidecimal(read_num(*this) >> i)}; } - N& N::operator+=(const N& n) { + string& string::operator+=(const string& n) { return *this = *this + n; } - N& N::operator-=(const N& n) { + string& string::operator-=(const string& n) { return *this = *this - n; } - N& N::operator*=(const N& n) { + string& string::operator*=(const string& n) { return *this = *this * n; } - N& N::operator<<=(int i) { + string& string::operator<<=(int i) { return *this = *this << i; } - N& N::operator>>=(int i) { + string& string::operator>>=(int i) { return *this = *this >> i; } - math::division N::divide(uint64 x) const { + math::division string::divide(uint64 x) const { if (x == 0) throw math::division_by_zero{}; // it is important to have this optimization. if (x == 16) { int last = string::size() - 1; - return math::division{ - N{std::string{"0x0"} + string::substr(2, last - 2)}, + return math::division{ + string{std::string{"0x0"} + string::substr(2, last - 2)}, static_cast(digit(string::operator[](last)))}; } math::division div = read_num(*this).divide(nat{x}); - return math::division{write_hexidecimal(div.Quotient), uint64(div.Remainder)}; - } - - std::ostream &write(std::ostream &o, const math::Z_bytes &z) { - return o << "0x" << hex::write(z.words().reverse()); - } - - std::ostream &write(std::ostream &o, const math::Z_bytes &z) { - return o << "0x" << hex::write(z.words().reverse()); - } - - } - - namespace integer { - - std::ostream &write(std::ostream &, const math::Z_bytes &) { - throw "incomplete method"; + return math::division{string{write_hexidecimal(div.Quotient)}, uint64(div.Remainder)}; } - std::ostream &write(std::ostream &, const math::Z_bytes &) { - throw "incomplete method"; + string string::read(string_view x) { + return hexidecimal::write(N::read(x)); } } - /* - namespace natural { - - ptr read(string_view s, endian::order r) { - if (!valid(s)) return nullptr; - if (hexidecimal::valid(s)) return hexidecimal::read(s, r); - return decimal::read(s, r); - } - - } - - namespace integer { - - ptr read(string_view s, endian::order r) { - //std::cout << "reading in integer string \"" << s << "\"" << std::endl; - if (!valid(s)) return nullptr; - if (hexidecimal::valid(s)) return hexidecimal::read(s, r); - if (negative(s)) { - //std::cout << "reading in negative decimal integer string \"" << s << "\"" << std::endl; - math::number::Z z{s}; - //std::cout << "reading in Z " << z << std::endl; - math::number::Z_bytes n{z}; - //std::cout << "reading in Z_bytes " << n << std::endl; - if (r == endian::big) std::reverse(n.begin(), n.end()); - //std::cout << "reading in negative decimal integer string ; about to return" << std::endl; - return std::make_shared(bytes_view(n)); - } - return decimal::read(s, r); - } - - }*/ - } - diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 67d79c52..88777976 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -53,6 +53,7 @@ package_add_test(testAbs testAbs.cpp) package_add_test(testBounded testBounded.cpp) package_add_test(testBase58 testBase58.cpp) package_add_test(testStringNumbers testStringNumbers.cpp) +package_add_test(testDecimal testDecimal.cpp) package_add_test(testExtendedEuclidian testExtendedEuclidian.cpp) package_add_test(testEratosthenes testEratosthenes.cpp) package_add_test(testFiniteField testFiniteField.cpp) diff --git a/test/testAbs.cpp b/test/testAbs.cpp index 47244b13..21e6df61 100644 --- a/test/testAbs.cpp +++ b/test/testAbs.cpp @@ -2,9 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "data/math/abs.hpp" -#include "data/data.hpp" -#include +#include "data/numbers.hpp" #include "gtest/gtest.h" namespace data { @@ -87,7 +85,8 @@ namespace data { using test_case = test_case_negative, int_big<10>, int_big<11>, int_big<20>, - int_little<9>, int_little<10>, int_little<11>, int_little<20>>; + int_little<9>, int_little<10>, int_little<11>, int_little<20>, + dec_int>; test_case{0, 0}; test_case{-1, 1}; @@ -117,7 +116,7 @@ namespace data { TEST(AbsTest, TestAbs) { using test_case = test_case_abs< - int64, uint64, + int64, uint64, Z, N, int_big<20>, uint_big<20>, int_big<9>, uint_big<9>, int_big<10>, uint_big<10>, @@ -126,9 +125,9 @@ namespace data { int_little<9>, uint_little<9>, int_little<10>, uint_little<10>, int_little<11>, uint_little<11>, - Z, N, Z_bytes_little, N_bytes_little, - Z_bytes_big, N_bytes_big>; + Z_bytes_big, N_bytes_big, + dec_int, dec_uint>; test_case{0, 0u}; test_case{1, 1u}; diff --git a/test/testDecimal.cpp b/test/testDecimal.cpp new file mode 100644 index 00000000..520f8830 --- /dev/null +++ b/test/testDecimal.cpp @@ -0,0 +1,203 @@ +// Copyright (c) 2022 Daniel Krawisz +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include "gtest/gtest.h" + +namespace data { + + void test_decrement_signed(const string &given, const string &expected) { + + dec_int g(given); + dec_int e(expected); + + EXPECT_EQ(decrement(g), e); + EXPECT_EQ(decrement(Z::read(g)), Z::read(e)); + EXPECT_EQ(decrement(Z_bytes_little::read(g)), Z_bytes_little::read(e)); + EXPECT_EQ(decrement(Z_bytes_big::read(g)), Z_bytes_big::read(e)); + } + + void test_decrement_unsigned(const string &given, const string &expected) { + + dec_uint g(given); + dec_uint e(expected); + + EXPECT_EQ(decrement(g), e); + EXPECT_EQ(decrement(N::read(g)), N::read(e)); + + EXPECT_EQ(decrement(N_bytes_little::read(g)), N_bytes_little::read(e)); + EXPECT_EQ(decrement(N_bytes_big::read(g)), N_bytes_big::read(e)); + + } + + void test_increment_signed_final(const dec_int &g, const dec_int &e) { + + EXPECT_EQ(increment(g), e); + EXPECT_EQ(increment(Z::read(g)), Z::read(e)); + + EXPECT_EQ(increment(Z_bytes_little::read(g)), Z_bytes_little::read(e)); + EXPECT_EQ(increment(Z_bytes_big::read(g)), Z_bytes_big::read(e)); + + } + + void test_increment_signed(const string &given, const string &expected) { + + dec_int g(given); + dec_int e(expected); + + test_increment_signed_final(g, e); + test_decrement_signed(e, g); + + test_increment_signed_final(-e, -g); + test_decrement_signed(-g, -e); + } + + void test_increment_unsigned(const string &given, const string &expected) { + dec_uint g(given); + dec_uint e(expected); + + EXPECT_EQ(increment(g), e); + EXPECT_EQ(increment(N::read(g)), N::read(e)); + EXPECT_EQ(increment(N_bytes_little::read(g)), N_bytes_little::read(e)); + EXPECT_EQ(increment(N_bytes_big::read(g)), N_bytes_big::read(e)); + + test_decrement_unsigned(expected, given); + test_increment_signed(given, expected); + } + + TEST(DecimalTest, TestDecimalIncrement) { + + test_decrement_unsigned("0", "0"); + + test_increment_unsigned("0", "1"); + test_increment_unsigned("1", "2"); + test_increment_unsigned("9", "10"); + test_increment_unsigned("10", "11"); + test_increment_unsigned("99999999999", "100000000000"); + test_increment_unsigned("102939030347", "102939030348"); + test_increment_unsigned("98980987676898761029390303474536547398", "98980987676898761029390303474536547399"); + test_increment_unsigned("98980987676898761029390303474536547399", "98980987676898761029390303474536547400"); + + } + + void test_add_signed(const string &left, const string &right, const string &expected) { + dec_int l(left); + dec_int r(right); + dec_int e(expected); + + EXPECT_EQ(l + r, e); + EXPECT_EQ(Z::read(l) + Z::read(r), Z::read(e)); + EXPECT_EQ(Z_bytes_little::read(l) + Z_bytes_little::read(r), Z_bytes_little::read(e)); + EXPECT_EQ(Z_bytes_big::read(l) + Z_bytes_big::read(r), Z_bytes_big::read(e)); + + } + + void test_add_unsigned(const string &left, const string &right, const string &expected) { + + dec_uint l(left); + dec_uint r(right); + dec_uint e(expected); + + EXPECT_EQ(l + r, e); + EXPECT_EQ(N::read(l) + N::read(r), N::read(e)); + EXPECT_EQ(N_bytes_little::read(l) + N_bytes_little::read(r), N_bytes_little::read(e)); + EXPECT_EQ(N_bytes_big::read(l) + N_bytes_big::read(r), N_bytes_big::read(e)); + + test_add_signed(left, right, expected); + } + + TEST(DecimalTest, TestDecimalAdd) { + test_add_unsigned("0", "0", "0"); + test_add_unsigned("0", "1", "1"); + test_add_unsigned("1", "1", "2"); + test_add_unsigned("231938875480", "397027301409876", "397259240285356"); + test_add_unsigned("23173210900987658780938875480", "39702733535456767789001409876", "62875944436444426569940285356"); + + test_add_signed("-1", "0", "-1"); + test_add_signed("-23173210900987658780938875480", "23173210900987658780938875480", "0"); + } + + void test_subtract_unsigned(const string &left, const string &right, const string &expected) { + + dec_uint l(left); + dec_uint r(right); + dec_uint e(expected); + + EXPECT_EQ(l - r, e); + EXPECT_EQ(N::read(l) - N::read(r), N::read(e)); + EXPECT_EQ(N_bytes_little::read(l) - N_bytes_little::read(r), N_bytes_little::read(e)); + EXPECT_EQ(N_bytes_big::read(l) - N_bytes_big::read(r), N_bytes_big::read(e)); + } + + void test_subtract_signed(const string &left, const string &right, const string &expected) { + dec_int l(left); + dec_int r(right); + dec_int e(expected); + + EXPECT_EQ(l - r, e); + EXPECT_EQ(Z::read(l) - Z::read(r), Z::read(e)); + EXPECT_EQ(Z_bytes_little::read(l) - Z_bytes_little::read(r), Z_bytes_little::read(e)); + EXPECT_EQ(Z_bytes_big::read(l) - Z_bytes_big::read(r), Z_bytes_big::read(e)); + } + + TEST(DecimalTest, TestDecimalSubtract) { + test_subtract_unsigned("0", "0", "0"); + test_subtract_signed("0", "0", "0"); + + test_subtract_unsigned("0", "0", "0"); + test_subtract_unsigned("1", "0", "1"); + test_subtract_unsigned("1", "1", "0"); + + test_subtract_unsigned("37", "12", "25"); + test_subtract_unsigned("4502938948920982780930898389", "4502938948920982780930898389", "0"); + + test_subtract_signed("0", "0", "0"); + test_subtract_signed("1", "0", "1"); + test_subtract_signed("1", "1", "0"); + + test_subtract_signed("37", "12", "25"); + test_subtract_signed("4502938948920982780930898389", "4502938948920982780930898389", "0"); + + test_subtract_unsigned("4502938948920982780930898389", "4502938948920982780930898390", "0"); + test_subtract_signed("4502938948920982780930898389", "4502938948920982780930898390", "-1"); + + } + + void test_multiply_signed(const string &left, const string &right, const string &expected) { + dec_int l(left); + dec_int r(right); + dec_int e(expected); + + EXPECT_EQ(l * r, e); + EXPECT_EQ(Z::read(l) * Z::read(r), Z::read(e)); + EXPECT_EQ(Z_bytes_little::read(l) * Z_bytes_little::read(r), Z_bytes_little::read(e)); + EXPECT_EQ(Z_bytes_big::read(l) * Z_bytes_big::read(r), Z_bytes_big::read(e)); + } + + void test_multiply_unsigned(const string &left, const string &right, const string &expected) { + + dec_uint l(left); + dec_uint r(right); + dec_uint e(expected); + + EXPECT_EQ(l * r, e); + EXPECT_EQ(N::read(l) * N::read(r), N::read(e)); + EXPECT_EQ(N_bytes_little::read(l) * N_bytes_little::read(r), N_bytes_little::read(e)); + EXPECT_EQ(N_bytes_big::read(l) * N_bytes_big::read(r), N_bytes_big::read(e)); + + test_multiply_signed(left, right, expected); + } + + TEST(DecimalTest, TestDecimalMultiply) { + + test_multiply_unsigned("0", "0", "0"); + test_multiply_unsigned("0", "1", "0"); + test_multiply_unsigned("1", "1", "1"); + test_multiply_unsigned("1", "2", "2"); + test_multiply_unsigned("23173210900987658780938875480", "39702733535456767789001409876", + "920039817562855061210426612476533348173557348698006240480"); + + } + +} diff --git a/test/testEratosthenes.cpp b/test/testEratosthenes.cpp index a7b6f49d..7ecf1154 100644 --- a/test/testEratosthenes.cpp +++ b/test/testEratosthenes.cpp @@ -40,6 +40,8 @@ namespace data { eratosthenes_test(); eratosthenes_test(); eratosthenes_test(); + eratosthenes_test(); + eratosthenes_test(); //eratosthenes_test(); } diff --git a/test/testExtendedEuclidian.cpp b/test/testExtendedEuclidian.cpp index d44148a5..f35795f4 100644 --- a/test/testExtendedEuclidian.cpp +++ b/test/testExtendedEuclidian.cpp @@ -37,6 +37,7 @@ namespace data { test_extended_euclidian, uint_big<10>>{}; test_extended_euclidian, uint_big<11>>{}; test_extended_euclidian, uint_big<20>>{}; + test_extended_euclidian{}; } diff --git a/test/testRoot.cpp b/test/testRoot.cpp index 140d7d5e..190ca17f 100644 --- a/test/testRoot.cpp +++ b/test/testRoot.cpp @@ -8,8 +8,8 @@ namespace data::mat { - template void test_root() { - + template void test_root_N() { + auto root_17_0 = root<0>(N::read("17")); auto root_25_0 = root<0>(N::read("25")); auto root_422_1 = root<1>(N::read("422")); @@ -41,13 +41,13 @@ namespace data::mat { EXPECT_TRUE(data::empty(root_1798307508862833999690304313948111955510002315423096853_18)); EXPECT_TRUE(data::empty(root_1798307508862833999690304313948111955510002315423096851_19)); - bool contains_422_1 = contains(root_422_1, N("422")); - bool contains_4_2 = contains(root_4_2, N("2")); - bool contains_16_2 = contains(root_16_2, N("4")); - bool contains_25_2 = contains(root_25_2, N("5")); - bool contains_125_3 = contains(root_125_3, N("5")); - bool contains_128_7 = contains(root_128_7, N("2")); - bool contains_xxxx = contains(root_1798307508862833999690304313948111955510002315423096853_19, N("717")); + bool contains_422_1 = contains(root_422_1, N::read("422")); + bool contains_4_2 = contains(root_4_2, N::read("2")); + bool contains_16_2 = contains(root_16_2, N::read("4")); + bool contains_25_2 = contains(root_25_2, N::read("5")); + bool contains_125_3 = contains(root_125_3, N::read("5")); + bool contains_128_7 = contains(root_128_7, N::read("2")); + bool contains_xxxx = contains(root_1798307508862833999690304313948111955510002315423096853_19, N::read("717")); EXPECT_TRUE(contains_422_1); EXPECT_TRUE(contains_4_2); @@ -59,9 +59,36 @@ namespace data::mat { }; + template void test_root_Z() { + test_root_N(); + + auto root_9_2 = root<2>(Z::read("9")); + bool contains_9_2 = contains(root_9_2, Z::read("3")); + bool contains_9_n2 = contains(root_9_2, Z::read("-3")); + + EXPECT_TRUE(contains_9_2); + EXPECT_TRUE(contains_9_n2); + + auto root_8_3 = root<3>(Z::read("8")); + bool contains_8_3 = contains(root_8_3, Z::read("2")); + bool contains_8_n3 = contains(root_8_3, Z::read("-2")); + + EXPECT_TRUE(contains_8_3); + EXPECT_FALSE(contains_8_n3); + + }; + TEST(RootsTest, TestRoots) { - test_root(); - test_root(); - test_root(); + test_root_N(); + test_root_N(); + test_root_N(); + test_root_N(); + test_root_N(); + test_root_N(); + + test_root_Z(); + test_root_Z(); + test_root_Z(); + test_root_Z(); } } diff --git a/test/testSign.cpp b/test/testSign.cpp index 268f796f..ebfcd109 100644 --- a/test/testSign.cpp +++ b/test/testSign.cpp @@ -2,10 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "data/data.hpp" -#include "data/math/number/bytes/N.hpp" -#include "data/math/number/bytes/Z.hpp" -#include "data/math/number/bounded/bounded.hpp" +#include "data/numbers.hpp" #include "gtest/gtest.h" namespace data { @@ -42,70 +39,38 @@ namespace data { typedef uint_little<11> ul11; typedef uint_little<20> ul20; - TEST(SignTest, TestSign) { - EXPECT_EQ(sign(int64{0}), math::zero); - EXPECT_EQ(sign(int64{1}), math::positive); - EXPECT_EQ(sign(int64{-1}), math::negative); - EXPECT_EQ(sign(int64{2}), math::positive); - EXPECT_EQ(sign(int64{-2}), math::negative); - EXPECT_EQ(sign(int64{7076852110923542}), math::positive); - EXPECT_EQ(sign(int64{-7076852110923542}), math::negative); - - EXPECT_EQ(sign(double{0}), math::zero); - EXPECT_EQ(sign(double{1}), math::positive); - EXPECT_EQ(sign(double{-1}), math::negative); - EXPECT_EQ(sign(double{2}), math::positive); - EXPECT_EQ(sign(double{-2}), math::negative); + template void test_N_sign() { - EXPECT_EQ(sign(float{0}), math::zero); - EXPECT_EQ(sign(float{1}), math::positive); - EXPECT_EQ(sign(float{-1}), math::negative); - EXPECT_EQ(sign(float{2}), math::positive); - EXPECT_EQ(sign(float{-2}), math::negative); + EXPECT_EQ(sign(N{0}), math::zero); + EXPECT_EQ(sign(N{1}), math::positive); + EXPECT_EQ(sign(N{2}), math::positive); + EXPECT_EQ(sign(N{7076852110923542}), math::positive); - EXPECT_EQ(sign(uint64{0}), math::zero); - EXPECT_EQ(sign(uint64{1}), math::positive); - EXPECT_EQ(sign(uint64{2}), math::positive); - EXPECT_EQ(sign(uint64{7076852110923542}), math::positive); + }; + + template void test_Z_sign() { + test_N_sign(); - EXPECT_EQ(sign(Z{0}), math::zero); - EXPECT_EQ(sign(Z{1}), math::positive); - EXPECT_EQ(sign(Z{-1}), math::negative); - EXPECT_EQ(sign(Z{2}), math::positive); - EXPECT_EQ(sign(Z{-2}), math::negative); - EXPECT_EQ(sign(Z{7076852110923542}), math::positive); - EXPECT_EQ(sign(Z{-7076852110923542}), math::negative); + EXPECT_EQ(sign(int64{-1}), math::negative); + EXPECT_EQ(sign(int64{-2}), math::negative); + EXPECT_EQ(sign(int64{-7076852110923542}), math::negative); - EXPECT_EQ(sign(N{0}), math::zero); - EXPECT_EQ(sign(N{1}), math::positive); - EXPECT_EQ(sign(N{2}), math::positive); - EXPECT_EQ(sign(N{7076852110923542}), math::positive); + }; + + TEST(SignTest, TestSign) { + test_Z_sign(); - EXPECT_EQ(sign(Z_bytes_little{0}), math::zero); - EXPECT_EQ(sign(Z_bytes_little{1}), math::positive); - EXPECT_EQ(sign(Z_bytes_little{-1}), math::negative); - EXPECT_EQ(sign(Z_bytes_little{2}), math::positive); - EXPECT_EQ(sign(Z_bytes_little{-2}), math::negative); - EXPECT_EQ(sign(Z_bytes_little{7076852110923542}), math::positive); - EXPECT_EQ(sign(Z_bytes_little{-7076852110923542}), math::negative); + test_Z_sign(); + test_N_sign(); - EXPECT_EQ(sign(N_bytes_little{0}), math::zero); - EXPECT_EQ(sign(N_bytes_little{1}), math::positive); - EXPECT_EQ(sign(N_bytes_little{2}), math::positive); - EXPECT_EQ(sign(N_bytes_little{7076852110923542}), math::positive); + test_Z_sign(); + test_N_sign(); - EXPECT_EQ(sign(Z_bytes_big{0}), math::zero); - EXPECT_EQ(sign(Z_bytes_big{1}), math::positive); - EXPECT_EQ(sign(Z_bytes_big{-1}), math::negative); - EXPECT_EQ(sign(Z_bytes_big{2}), math::positive); - EXPECT_EQ(sign(Z_bytes_big{-2}), math::negative); - EXPECT_EQ(sign(Z_bytes_big{7076852110923542}), math::positive); - EXPECT_EQ(sign(Z_bytes_big{-7076852110923542}), math::negative); + test_N_sign(); + test_N_sign(); - EXPECT_EQ(sign(N_bytes_big{0}), math::zero); - EXPECT_EQ(sign(N_bytes_big{1}), math::positive); - EXPECT_EQ(sign(N_bytes_big{2}), math::positive); - EXPECT_EQ(sign(N_bytes_big{7076852110923542}), math::positive); + test_N_sign(); + test_N_sign(); EXPECT_EQ(sign(Q{0}), math::zero); EXPECT_EQ(sign(Q{1}), math::positive); @@ -115,107 +80,30 @@ namespace data { EXPECT_EQ(sign(Q{2, 3}), math::positive); EXPECT_EQ(sign(Q{-2, 3}), math::negative); - EXPECT_EQ(sign(b09(0)), math::zero); - EXPECT_EQ(sign(b10(0)), math::zero); - EXPECT_EQ(sign(b11(0)), math::zero); - EXPECT_EQ(sign(b20(0)), math::zero); - EXPECT_EQ(sign(l09(0)), math::zero); - EXPECT_EQ(sign(l10(0)), math::zero); - EXPECT_EQ(sign(l11(0)), math::zero); - EXPECT_EQ(sign(l20(0)), math::zero); - - EXPECT_EQ(sign(ub09(0)), math::zero); - EXPECT_EQ(sign(ub10(0)), math::zero); - EXPECT_EQ(sign(ub11(0)), math::zero); - EXPECT_EQ(sign(ub20(0)), math::zero); - EXPECT_EQ(sign(ul09(0)), math::zero); - EXPECT_EQ(sign(ul10(0)), math::zero); - EXPECT_EQ(sign(ul11(0)), math::zero); - EXPECT_EQ(sign(ul20(0)), math::zero); - - auto x = b20(-1); - std::cout << std::hex << x << std::endl; - - EXPECT_EQ(sign(b20(1)), math::positive); - EXPECT_EQ(sign(b11(1)), math::positive); - EXPECT_EQ(sign(b10(1)), math::positive); - EXPECT_EQ(sign(b09(1)), math::positive); - EXPECT_EQ(sign(l20(1)), math::positive); - EXPECT_EQ(sign(l11(1)), math::positive); - EXPECT_EQ(sign(l10(1)), math::positive); - EXPECT_EQ(sign(l09(1)), math::positive); - - EXPECT_EQ(sign(ub09(1)), math::positive); - EXPECT_EQ(sign(ub10(1)), math::positive); - EXPECT_EQ(sign(ub11(1)), math::positive); - EXPECT_EQ(sign(ub20(1)), math::positive); - EXPECT_EQ(sign(ul09(1)), math::positive); - EXPECT_EQ(sign(ul10(1)), math::positive); - EXPECT_EQ(sign(ul11(1)), math::positive); - EXPECT_EQ(sign(ul20(1)), math::positive); - - EXPECT_EQ(sign(b09(-1)), math::negative); - EXPECT_EQ(sign(b10(-1)), math::negative); - EXPECT_EQ(sign(b11(-1)), math::negative); - EXPECT_EQ(sign(b20(-1)), math::negative); - EXPECT_EQ(sign(l09(-1)), math::negative); - EXPECT_EQ(sign(l10(-1)), math::negative); - EXPECT_EQ(sign(l11(-1)), math::negative); - EXPECT_EQ(sign(l20(-1)), math::negative); - - EXPECT_EQ(sign(b09(2)), math::positive); - EXPECT_EQ(sign(b10(2)), math::positive); - EXPECT_EQ(sign(b11(2)), math::positive); - EXPECT_EQ(sign(b20(2)), math::positive); - EXPECT_EQ(sign(l09(2)), math::positive); - EXPECT_EQ(sign(l10(2)), math::positive); - EXPECT_EQ(sign(l11(2)), math::positive); - EXPECT_EQ(sign(l20(2)), math::positive); - - EXPECT_EQ(sign(ub09(2)), math::positive); - EXPECT_EQ(sign(ub10(2)), math::positive); - EXPECT_EQ(sign(ub11(2)), math::positive); - EXPECT_EQ(sign(ub20(2)), math::positive); - EXPECT_EQ(sign(ul09(2)), math::positive); - EXPECT_EQ(sign(ul10(2)), math::positive); - EXPECT_EQ(sign(ul11(2)), math::positive); - EXPECT_EQ(sign(ul20(2)), math::positive); - - EXPECT_EQ(sign(b09(-2)), math::negative); - EXPECT_EQ(sign(b10(-2)), math::negative); - EXPECT_EQ(sign(b11(-2)), math::negative); - EXPECT_EQ(sign(b20(-2)), math::negative); - EXPECT_EQ(sign(l09(-2)), math::negative); - EXPECT_EQ(sign(l10(-2)), math::negative); - EXPECT_EQ(sign(l11(-2)), math::negative); - EXPECT_EQ(sign(l20(-2)), math::negative); - - EXPECT_EQ(sign(b09(7076852110923542)), math::positive); - EXPECT_EQ(sign(b10(7076852110923542)), math::positive); - EXPECT_EQ(sign(b11(7076852110923542)), math::positive); - EXPECT_EQ(sign(b20(7076852110923542)), math::positive); - EXPECT_EQ(sign(b09(7076852110923542)), math::positive); - EXPECT_EQ(sign(b10(7076852110923542)), math::positive); - EXPECT_EQ(sign(b11(7076852110923542)), math::positive); - EXPECT_EQ(sign(b20(7076852110923542)), math::positive); - - EXPECT_EQ(sign(ub09(7076852110923542)), math::positive); - EXPECT_EQ(sign(ub10(7076852110923542)), math::positive); - EXPECT_EQ(sign(ub11(7076852110923542)), math::positive); - EXPECT_EQ(sign(ub20(7076852110923542)), math::positive); - EXPECT_EQ(sign(ul09(7076852110923542)), math::positive); - EXPECT_EQ(sign(ul10(7076852110923542)), math::positive); - EXPECT_EQ(sign(ul11(7076852110923542)), math::positive); - EXPECT_EQ(sign(ul20(7076852110923542)), math::positive); - - EXPECT_EQ(sign(b09(-7076852110923542)), math::negative); - EXPECT_EQ(sign(b10(-7076852110923542)), math::negative); - EXPECT_EQ(sign(b11(-7076852110923542)), math::negative); - EXPECT_EQ(sign(b20(-7076852110923542)), math::negative); - EXPECT_EQ(sign(l09(-7076852110923542)), math::negative); - EXPECT_EQ(sign(l10(-7076852110923542)), math::negative); - EXPECT_EQ(sign(l11(-7076852110923542)), math::negative); - EXPECT_EQ(sign(l20(-7076852110923542)), math::negative); + test_Z_sign(); + test_Z_sign(); + test_Z_sign(); + test_Z_sign(); + + test_N_sign(); + test_N_sign(); + test_N_sign(); + test_N_sign(); + + test_Z_sign(); + test_Z_sign(); + test_Z_sign(); + test_Z_sign(); + + test_N_sign(); + test_N_sign(); + test_N_sign(); + test_N_sign(); + + test_Z_sign(); + test_N_sign(); + test_N_sign(); + test_N_sign(); } } diff --git a/test/testStringNumbers.cpp b/test/testStringNumbers.cpp index 5dae1960..946900da 100644 --- a/test/testStringNumbers.cpp +++ b/test/testStringNumbers.cpp @@ -2,82 +2,81 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "data/encoding/integer.hpp" +#include "data/numbers.hpp" #include "data/encoding/base58.hpp" #include "gtest/gtest.h" namespace data::encoding { - using dec_number = decimal::N; - using hex_number = hexidecimal::N; - using b58_number = base58::string; TEST(StringNumbersTest, TestConstructStringNumbers) { - EXPECT_EQ(dec_number{}, "0"); - EXPECT_EQ(hex_number{}, "0x"); - EXPECT_EQ(b58_number{}, "1"); + EXPECT_EQ(dec_uint{}, "0"); + EXPECT_EQ(hex_uint{}, "0x"); + EXPECT_EQ(base58_uint{}, "1"); - EXPECT_EQ(dec_number{}, dec_number{0}); - EXPECT_EQ(hex_number{}, hex_number{0}); - EXPECT_EQ(b58_number{}, b58_number{0}); + EXPECT_EQ(dec_uint{}, dec_uint{0}); + EXPECT_EQ(hex_uint{}, hex_uint{0}); + EXPECT_EQ(base58_uint{}, base58_uint{0}); - EXPECT_EQ(dec_number{1}, "1"); - EXPECT_EQ(hex_number{1}, "0x01"); - EXPECT_EQ(b58_number{1}, "2"); + EXPECT_EQ(dec_uint{1}, "1"); + EXPECT_EQ(hex_uint{1}, "0x01"); + EXPECT_EQ(base58_uint{1}, "2"); - EXPECT_EQ(dec_number{27}, "27"); - EXPECT_EQ(hex_number{27}, "0x1b"); - EXPECT_EQ(b58_number{27}, "U"); + EXPECT_EQ(dec_uint{27}, "27"); + EXPECT_EQ(hex_uint{27}, "0x1b"); + EXPECT_EQ(base58_uint{27}, "U"); } TEST(StringNumbersTest, TestAddStringNumbers) { - EXPECT_EQ(dec_number{1} + dec_number{2}, "3"); - EXPECT_EQ(hex_number{1} + hex_number{2}, "0x03"); - EXPECT_EQ(b58_number{1} + b58_number{2}, "4"); + EXPECT_EQ(dec_uint{1} + dec_uint{2}, "3"); + EXPECT_EQ(hex_uint{1} + hex_uint{2}, "0x03"); + EXPECT_EQ(base58_uint{1} + base58_uint{2}, "4"); } TEST(StringNumbersTest, TestSubtractStringNumbers) { - EXPECT_EQ(dec_number{2} - dec_number{1}, "1"); - EXPECT_EQ(hex_number{2} - hex_number{1}, "0x01"); - EXPECT_EQ(b58_number{2} - b58_number{1}, "2"); + EXPECT_EQ(dec_uint{2} - dec_uint{1}, "1"); + EXPECT_EQ(hex_uint{2} - hex_uint{1}, "0x01"); + EXPECT_EQ(base58_uint{2} - base58_uint{1}, "2"); - EXPECT_EQ(dec_number{1} - dec_number{2}, "0"); - EXPECT_EQ(hex_number{1} - hex_number{2}, "0x"); - EXPECT_EQ(b58_number{1} - b58_number{2}, "1"); + EXPECT_EQ(dec_uint{1} - dec_uint{2}, "0"); + EXPECT_EQ(hex_uint{1} - hex_uint{2}, "0x"); + EXPECT_EQ(base58_uint{1} - base58_uint{2}, "1"); } TEST(StringNumbersTest, TestMultiplyStringNumbers) { - EXPECT_EQ(dec_number{27} * dec_number{25}, "675"); - EXPECT_EQ(hex_number{27} * hex_number{25}, hex_number{675}); - EXPECT_EQ(b58_number{27} * b58_number{25}, b58_number{675}); + EXPECT_EQ(dec_uint{27} * dec_uint{25}, "675"); + EXPECT_EQ(hex_uint{27} * hex_uint{25}, hex_uint{675}); + EXPECT_EQ(base58_uint{27} * base58_uint{25}, base58_uint{675}); } TEST(StringNumbersTest, TestDivideStringNumbers) { + uint64 num = 432; - auto hex_div_16 = hex_number{num}.divide(16); + auto hex_div_16 = hex_uint{num}.divide(16); + + math::division dec_expected_10{43, 2}; + math::division hex_expected_16{27, 0}; + math::division b58_expected_58{7, 26}; - math::division dec_expected_10{43, 2}; - math::division hex_expected_16{27, 0}; - math::division b58_expected_58{7, 26}; + math::division dec_expected_9{48, 0}; + math::division hex_expected_15{28, 12}; + math::division b58_expected_57{7, 33}; - math::division dec_expected_9{48, 0}; - math::division hex_expected_15{28, 12}; - math::division b58_expected_57{7, 33}; + EXPECT_EQ(dec_uint{num}.divide(10), dec_expected_10); + EXPECT_EQ(hex_div_16, hex_expected_16); + EXPECT_EQ(base58_uint{num}.divide(58), b58_expected_58); - EXPECT_EQ(dec_number{num}.divide(10), dec_expected_10); - EXPECT_EQ(hex_div_16, hex_expected_16); - EXPECT_EQ(b58_number{num}.divide(58), b58_expected_58); + EXPECT_EQ(dec_uint{num}.divide(9), dec_expected_9); + EXPECT_EQ(hex_uint{num}.divide(15), hex_expected_15); + EXPECT_EQ(base58_uint{num}.divide(57), b58_expected_57); - EXPECT_EQ(dec_number{num}.divide(9), dec_expected_9); - EXPECT_EQ(hex_number{num}.divide(15), hex_expected_15); - EXPECT_EQ(b58_number{num}.divide(57), b58_expected_57); } }