diff --git a/include/data/encoding/base58.hpp b/include/data/encoding/base58.hpp index cc482fa7..109c0c46 100644 --- a/include/data/encoding/base58.hpp +++ b/include/data/encoding/base58.hpp @@ -167,6 +167,14 @@ namespace data::math { bool is_zero (const base58_uint &); bool is_negative (const base58_uint &); bool is_positive (const base58_uint &); + + template <> + struct divide { + division operator () (const base58_uint &v, const base58_uint &z) { + auto d = divide {} (N (v), N (z)); + return {encoding::base58::encode (d.Quotient), encoding::base58::encode (d.Remainder)}; + } + }; } diff --git a/include/data/encoding/endian/arithmetic.hpp b/include/data/encoding/endian/arithmetic.hpp index d7fcbaf1..6cc60a9d 100644 --- a/include/data/encoding/endian/arithmetic.hpp +++ b/include/data/encoding/endian/arithmetic.hpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace data::endian { @@ -264,6 +265,30 @@ namespace data::math { return x > 0; } + template + struct divide, endian::arithmetic> { + division, endian::arithmetic> operator () + (const endian::arithmetic &v, const endian::arithmetic &z) { + return {v / z, v % z}; + } + }; + + template + struct divide, endian::arithmetic> { + division, endian::arithmetic> operator () + (const endian::arithmetic &v, const endian::arithmetic &z) { + return {v / z, v % z}; + } + }; + + template + struct divide, endian::arithmetic> { + division, endian::arithmetic> operator () + (const endian::arithmetic &v, const endian::arithmetic &z) { + return {v / z, v % z}; + } + }; + } namespace data { diff --git a/include/data/encoding/integer.hpp b/include/data/encoding/integer.hpp index 4020afe4..e5901d40 100644 --- a/include/data/encoding/integer.hpp +++ b/include/data/encoding/integer.hpp @@ -443,6 +443,16 @@ namespace data::math { template struct abs> { hex::int2 operator () (const hex::int2 &); }; + + template <> struct times { + dec_int operator () (const dec_int &, const dec_int &); + nonzero operator () (const nonzero &, const nonzero &); + }; + + template struct times> { + hex::integer operator () (const hex::integer &, const hex::integer &); + nonzero> operator () (const nonzero> &, const nonzero> &); + }; template <> struct commutative, dec_uint> {}; template <> struct associative, dec_uint> {}; @@ -490,6 +500,38 @@ namespace data::math { template bool is_negative_zero (const hex::int2 &); + + template <> struct divide { + division operator () (const dec_uint &, const dec_uint &); + }; + + template <> struct divide { + division operator () (const dec_int &, const dec_int &); + }; + + template <> struct divide { + division operator () (const dec_int &, const dec_uint &); + }; + + template + struct divide, hex::uint> { + division, hex::uint> operator () (const hex::uint &, const hex::uint &); + }; + + template + struct divide, hex::int1> { + division, hex::uint> operator () (const hex::int1 &, const hex::int1 &); + }; + + template + struct divide, hex::uint> { + division, hex::uint> operator () (const hex::int1 &, const hex::uint &); + }; + + template + struct divide, hex::int2> { + division, hex::int2> operator () (const hex::int2 &, const hex::int2 &); + }; } @@ -576,6 +618,7 @@ namespace data::encoding::decimal { explicit operator double () const; explicit operator uint64 () const; + explicit operator math::N () const; }; signed_decimal::string operator - (const string &); @@ -621,6 +664,7 @@ namespace data::encoding::signed_decimal { explicit operator double () const; explicit operator int64 () const; + explicit operator math::Z () const; }; template @@ -662,6 +706,8 @@ namespace data::encoding::hexidecimal { integer operator + (int64) const; integer operator - (int64) const; integer operator * (int64) const; + + explicit operator math::Z () const; }; template @@ -677,6 +723,8 @@ namespace data::encoding::hexidecimal { data::hex::uint operator + (uint64) const; data::hex::uint operator - (uint64) const; data::hex::uint operator * (uint64) const; + + explicit operator math::N () const; }; template @@ -995,9 +1043,17 @@ namespace data::encoding::signed_decimal { 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)}; + + string inline operator / (const string &v, const decimal::string &z) { + return math::divide {} (v, z).Quotient; + } + + string inline operator / (const string &v, const string &z) { + return math::divide {} (v, z).Quotient; + } + + decimal::string inline operator % (const string &v, const decimal::string &z) { + return math::divide {} (v, z).Remainder; } string inline operator ++ (string &x, int) { diff --git a/include/data/encoding/words.hpp b/include/data/encoding/words.hpp index 29bc6033..6d7462cd 100644 --- a/include/data/encoding/words.hpp +++ b/include/data/encoding/words.hpp @@ -16,6 +16,9 @@ namespace data::encoding { + // words is for iterating over digits that have an endian order. + // Using words, you will always iterate from least to most + // significant digits. Reverse iteration will go from most to least. template struct words; template struct words { diff --git a/include/data/float.hpp b/include/data/float.hpp index ea2c4897..39c42176 100644 --- a/include/data/float.hpp +++ b/include/data/float.hpp @@ -6,7 +6,7 @@ #define DATA_FLOAT #include -#include +#include #include #include @@ -120,6 +120,18 @@ namespace data::math { return x * x; } }; + + template struct times { + X operator () (const X &a, const X &b) { + return a * b; + } + + // technically, it is not true that there are no zero divisors but + // we use floats as an approximation for real numbers. + nonzero operator () (const nonzero &a, const nonzero &b) { + return a * b; + } + }; template struct commutative, X> {}; template struct commutative, X> {}; @@ -143,6 +155,12 @@ namespace data::math { return b - a; } }; + + template struct inverse, X> { + nonzero operator () (const nonzero &a, const nonzero &b) { + return b / a; + } + }; } diff --git a/include/data/functional/queue.hpp b/include/data/functional/queue.hpp index f972232b..f27cb76a 100644 --- a/include/data/functional/queue.hpp +++ b/include/data/functional/queue.hpp @@ -15,19 +15,19 @@ namespace data::interface { template concept has_queue_constructor = requires (list x, element e) { - { list{x, e} } -> std::same_as; + { list {x, e} } -> std::same_as; } && requires (element e) { - { list{e} } -> std::same_as; + { list {e} } -> std::same_as; }; template concept has_append_method = requires (list x, element e) { - { x.append(e) } -> std::convertible_to; + { x.append (e) } -> std::convertible_to; }; template concept has_sort_method = requires (list x) { - { x.sort() } -> std::convertible_to; + { x.sort () } -> std::convertible_to; }; } @@ -35,35 +35,35 @@ namespace data::interface { namespace data { template requires interface::has_append_method - inline list append(const list& x, const elem& e) { - return x.append(e); + inline list append (const list &x, const elem &e) { + return x.append (e); } } namespace data::functional { - template ().first())> + template ().first())> concept queue = sequence && interface::has_append_method && interface::has_queue_constructor && std::default_initializable; template - list take_queue(const list &x, size_t n, const list &z = {}); + list take_queue (const list &x, size_t n, const list &z = {}); template list join_queue(const list&a, const list& b) { - if (data::empty(b)) return a; - return join_queue(append(a, first(b)), rest(b)); + if (data::empty (b)) return a; + return join_queue (append(a, first(b)), rest(b)); } template requires ordered> - L merge_queue(const L &a, const L &b, const L &n = {}) { - if (data::empty(a) && data::empty(b)) return reverse(n); - if (data::empty(a)) return merge_queue(a, rest(b), prepend(n, first(b))); - if (data::empty(b)) return merge_queue(rest(a), b, prepend(n, first(a))); - return first(a) < first(b) ? - merge_queue(rest(a), b, prepend(n, first(a))): - merge_queue(a, rest(b), prepend(n, first(b))); + L merge_queue (const L &a, const L &b, const L &n = {}) { + if (data::empty (a) && data::empty(b)) return reverse(n); + if (data::empty (a)) return merge_queue(a, rest(b), prepend(n, first(b))); + if (data::empty (b)) return merge_queue(rest(a), b, prepend(n, first(a))); + return first (a) < first(b) ? + merge_queue (rest (a), b, prepend(n, first(a))): + merge_queue (a, rest(b), prepend(n, first(b))); } } @@ -71,46 +71,46 @@ namespace data::functional { namespace data { template - list select(list l, function)> satisfies, list found = {}) { - if (data::empty(l)) return found; - auto f0 = first(l); - if (satisfies(f0)) select(rest(l), satisfies, append(found, f0)); - return select(rest(l), satisfies, found); + list select (list l, function)> satisfies, list found = {}) { + if (data::empty (l)) return found; + auto f0 = first (l); + if (satisfies (f0)) select (rest (l), satisfies, append (found, f0)); + return select (rest (l), satisfies, found); } template - L rotate_left(const L x) { - size_t s = size(x); + L rotate_left (const L x) { + size_t s = size (x); if (s == 0 || s == 1) return x; - return append(rest(x), first(x)); + return append (rest (x), first (x)); } template - L rotate_left(const L x, uint32 n) { + L rotate_left (const L x, uint32 n) { if (n == 0) return x; - size_t s = size(x); + size_t s = size (x); if (s == 0 || s == 1) return x; - if (n > s) return rotate_left(x, n % s); - return rotate_left(rotate_left(x, n - 1)); + if (n > s) return rotate_left (x, n % s); + return rotate_left (rotate_left (x, n - 1)); } template - inline L rotate_right(const L x) { - return reverse(rotate_left(reverse(x))); + inline L rotate_right (const L x) { + return reverse (rotate_left (reverse (x))); } template - L rotate_right(const L x, uint32 n) { + L rotate_right (const L x, uint32 n) { if (n == 0) return x; - size_t s = size(x); + size_t s = size (x); if (s == 0 || s == 1) return x; - if (n > s) return rotate_right(x, n % s); - return rotate_right(rotate_right(x, n - 1)); + if (n > s) return rotate_right (x, n % s); + return rotate_right (rotate_right (x, n - 1)); } } diff --git a/include/data/functional/stack.hpp b/include/data/functional/stack.hpp index 06331991..a1d3d8a5 100644 --- a/include/data/functional/stack.hpp +++ b/include/data/functional/stack.hpp @@ -20,42 +20,42 @@ namespace data::interface { template concept has_stack_constructor = requires (list x, element e) { - { list{e, x} } -> std::same_as; + { list {e, x} } -> std::same_as; } && requires (element e) { - { list{e} } -> std::same_as; + { list {e} } -> std::same_as; }; template concept has_prepend_method = requires (list x, element e) { - { x.prepend(e) } -> std::convertible_to; + { x.prepend (e) } -> std::convertible_to; }; } namespace data { template requires interface::has_prepend_method - inline list prepend(const list& x, const elem& e) { - return x.prepend(e); + inline list prepend (const list &x, const elem &e) { + return x.prepend (e); } } namespace data::functional { - template ().first())>> + template ().first ())>> concept stack = sequence && interface::has_prepend_method && interface::has_stack_constructor && std::default_initializable; template - list take_stack(const list &x, size_t n, const list &z = {}); + list take_stack (const list &x, size_t n, const list &z = {}); template - list join_stack(const list&a, const list& b); + list join_stack (const list&a, const list& b); template requires ordered> - L merge_stack(const L &a, const L &b, const L &n = {}); + L merge_stack (const L &a, const L &b, const L &n = {}); template - value inner(times t, L1 l1, L2 l2, plus p); + value inner (times t, L1 l1, L2 l2, plus p); } namespace data { @@ -67,28 +67,28 @@ namespace data { namespace data::functional { template - list join_stack(const list&a, const list& b) { - if (data::empty(a)) return b; - return prepend(join_stack(rest(a), b), first(a)); + list join_stack (const list &a, const list &b) { + if (data::empty (a)) return b; + return prepend (join_stack (rest (a), b), first (a)); } template requires ordered> - L merge_stack(const L &a, const L &b, const L &n) { - if (data::empty(a) && data::empty(b)) return reverse(n); - if (data::empty(a)) return merge_stack(a, rest(b), prepend(n, first(b))); - if (data::empty(b)) return merge_stack(rest(a), b, prepend(n, first(a))); - return first(a) < first(b) ? - merge_stack(rest(a), b, prepend(n, first(a))): - merge_stack(a, rest(b), prepend(n, first(b))); + L merge_stack (const L &a, const L &b, const L &n) { + if (data::empty (a) && data::empty(b)) return reverse(n); + if (data::empty (a)) return merge_stack (a, rest (b), prepend (n, first (b))); + if (data::empty (b)) return merge_stack (rest (a), b, prepend (n, first (a))); + return first (a) < first (b) ? + merge_stack(rest(a), b, prepend (n, first (a))): + merge_stack (a, rest(b), prepend (n, first (b))); } template - value inner(times t, L1 l1, L2 l2, plus p) { - uint32 size = l1.size(); - if (size != l2.size()) exception{"lists must be the same size"}; - if (size == 0) return value{}; + value inner (times t, L1 l1, L2 l2, plus p) { + uint32 size = l1.size (); + if (size != l2.size ()) exception {"lists must be the same size"}; + if (size == 0) return value {}; - return p(t(l1.first(), l2.first()), inner(t, rest(l1), rest(l2), p)); + return p (t (l1.first (), l2.first ()), inner (t, rest (l1), rest (l2), p)); } // This is a node that you could perhaps use to make a list. @@ -98,49 +98,49 @@ namespace data::functional { Y Rest; size_t Size; - stack_node(X x, Y r); - stack_node(X x); + stack_node (X x, Y r); + stack_node (X x); - X& first(); + X& first (); const X& first() const; - Y rest() const; + Y rest () const; - bool valid() const; - size_t size() const; - bool contains(X x) const; + bool valid () const; + size_t size () const; + bool contains (X x) const; }; template - inline stack_node::stack_node(X x, Y r) : First(x), Rest(r), Size{data::size(r) + 1} {} + inline stack_node::stack_node (X x, Y r) : First (x), Rest(r), Size {data::size (r) + 1} {} template - inline stack_node::stack_node(X x) : First(x), Rest{}, Size{1} {} + inline stack_node::stack_node (X x) : First (x), Rest {}, Size {1} {} template - inline const X& stack_node::first() const { + inline const X& stack_node::first () const { return First; } template - inline Y stack_node::rest() const { + inline Y stack_node::rest () const { return Rest; } template - inline bool stack_node::valid() const { - return data::valid(First) && data::valid(Rest); + inline bool stack_node::valid () const { + return data::valid (First) && data::valid (Rest); } template - inline size_t stack_node::size() const { + inline size_t stack_node::size () const { return Size; } template - inline bool stack_node::contains(X x) const { + inline bool stack_node::contains (X x) const { if (x == First) return true; - return data::functional::contains(Rest, x); + return data::functional::contains (Rest, x); } } diff --git a/include/data/math.hpp b/include/data/math.hpp index 3da232b9..ad08114a 100644 --- a/include/data/math.hpp +++ b/include/data/math.hpp @@ -5,17 +5,20 @@ #ifndef DATA_MATH #define DATA_MATH -#include #include +#include +#include namespace data { + // fractions + template ()))> using fraction = math::fraction; + // permutations - template - using permutation = data::math::permutation; + template using permutation = math::permutation; - template - using fraction = data::math::fraction; + // Polynomials + template using polynomial = math::polynomial; } diff --git a/include/data/math/algebra.hpp b/include/data/math/algebra.hpp index bb034231..bbae5a18 100644 --- a/include/data/math/algebra.hpp +++ b/include/data/math/algebra.hpp @@ -5,33 +5,42 @@ #ifndef DATA_MATH_ALGEBRA #define DATA_MATH_ALGEBRA -#include +#include -namespace data::interface { - // TODO - - /* - template - struct algebra : public linear::space { - x times(x a, x b) const { - return a ^ b; +namespace data::math { + + template struct identity; + template struct inverse; + + template struct plus { + X operator () (const X &a, const X &b) { + return a + b; } }; - - template - struct division_algebra : public algebra { - x divide(x a, x b) const { - return a / b; + + template struct identity, X> { + X operator () () { + return X {0}; } }; - - template - struct normed_division_algebra : public ring { - nonnegative norm(x a) const { - return a.norm(); + + template struct times { + X operator () (const X &a, const X &b) { + return a * b; + } + }; + + template struct identity, X> { + X operator () () { + return X {1}; + } + }; + + template struct inverse, X> { + X operator () (X a, X b) { + return b - a; } }; - */ } diff --git a/include/data/math/algebra/finite_field.hpp b/include/data/math/algebra/finite_field.hpp index 7866503f..ccddb8b8 100644 --- a/include/data/math/algebra/finite_field.hpp +++ b/include/data/math/algebra/finite_field.hpp @@ -16,31 +16,28 @@ namespace data::math::algebra { template struct prime_field_element; template - bool operator==(const prime_field_element &, const prime_field_element &); - - template - bool operator!=(const prime_field_element &, const prime_field_element &); + bool operator == (const prime_field_element &, const prime_field_element &); template struct prime_field; template struct prime_field_element : ptr> { - prime_field_element operator+(const prime_field_element &) const; - prime_field_element operator-(const prime_field_element &) const; - prime_field_element operator*(const prime_field_element &) const; - prime_field_element operator/(const prime_field_element &) const; + prime_field_element operator + (const prime_field_element &) const; + prime_field_element operator - (const prime_field_element &) const; + prime_field_element operator * (const prime_field_element &) const; + prime_field_element operator / (const prime_field_element &) const; - prime_field_element inverse() const; + prime_field_element inverse () const; - bool valid() const { - return *this != nullptr && (*this)->valid(); + bool valid () const { + return *this != nullptr && (*this)->valid (); } private: - prime_field_element() : ptr>{} {} + prime_field_element() : ptr> {} {} template - prime_field_element(X... x) : ptr>(std::make_shared>(x...)) {} + prime_field_element (X... x) : ptr> (std::make_shared> (x...)) {} friend struct prime_field; }; @@ -48,19 +45,19 @@ namespace data::math::algebra { template struct prime_field { number::prime Modulus; - prime_field(number::prime p) : Modulus{p.Prime == N(P) ? p : number::prime{}} {} + prime_field (number::prime p) : Modulus {p.Prime == N (P) ? p : number::prime {}} {} - bool valid() const { - return Modulus.valid() && Modulus.Prime == N(P); + bool valid () const { + return Modulus.valid () && Modulus.Prime == N (P); } template - prime_field_element make(X... x); + prime_field_element make (X... x); }; template - inline std::ostream& operator<<(std::ostream& o, const prime_field_element& m) { - return o << "f<"<{"<Value<<"}"; + std::ostream inline &operator << (std::ostream &o, const prime_field_element &m) { + return o << "f<" << P << ">{" << m->Value << "}"; } } @@ -82,7 +79,7 @@ namespace data::math { struct commutative< times>, algebra::prime_field_element> - : commutative, N> {};; + : commutative, N> {}; template struct associative< @@ -95,8 +92,8 @@ namespace data::math { plus>, algebra::prime_field_element> : identity, N> { - static const algebra::prime_field_element value() { - return {identity, N>::value()}; + static const algebra::prime_field_element value () { + return {identity, N>::value ()}; } }; @@ -105,8 +102,8 @@ namespace data::math { times>, algebra::prime_field_element> : identity, N> { - static const algebra::prime_field_element value() { - return {identity, N>::value()}; + static const algebra::prime_field_element value () { + return {identity, N>::value ()}; } }; @@ -115,61 +112,56 @@ namespace data::math { namespace data::math::algebra { template - bool inline operator==(const prime_field_element &a, const prime_field_element &b) { - if (static_cast>>(a) == static_cast>>(b)) return true; - return *static_cast>>(a) == *static_cast>>(b); - } - - template - bool inline operator!=(const prime_field_element &a, const prime_field_element &b) { - return !(a == b); + bool inline operator == (const prime_field_element &a, const prime_field_element &b) { + if (static_cast>> (a) == static_cast>> (b)) return true; + return *static_cast>> (a) == *static_cast>> (b); } template prime_field_element inline - prime_field_element::operator+( + prime_field_element::operator + ( const prime_field_element &e) const { if (*this == nullptr || e == nullptr) return {}; - return {*this->get() + *e.get()}; + return {*this->get () + *e.get ()}; } template prime_field_element inline - prime_field_element::operator-(const prime_field_element& e) const { + prime_field_element::operator - (const prime_field_element &e) const { if (*this == nullptr || e == nullptr) return {}; - return {*this->get() - *e.get()}; + return {*this->get () - *e.get ()}; } template prime_field_element inline - prime_field_element::operator*(const prime_field_element& e) const { + prime_field_element::operator * (const prime_field_element &e) const { if (*this == nullptr || e == nullptr) return {}; - return {*this->get() * *e.get()}; + return {*this->get () * *e.get ()}; } template prime_field_element prime_field_element::inverse() const { - if (*this == nullptr || *this == prime_field_element{0}) return {}; - Z bt = number::euclidian::extended::algorithm(N{P}, - this->get()->Value).BezoutT; - if (bt < 0) bt += N{P}; - return prime_field_element{math::abs{}(bt)}; + if (*this == nullptr || *this == prime_field_element {0}) return {}; + Z bt = number::euclidian::extended::algorithm (N {P}, + this->get ()->Value).BezoutT; + if (bt < 0) bt += N {P}; + return prime_field_element {math::abs {} (bt)}; } template inline prime_field_element - prime_field_element::operator/(const prime_field_element& e) const { + prime_field_element::operator / (const prime_field_element &e) const { if (*this == nullptr || e == nullptr) return {}; - if (e == prime_field_element{0}) throw division_by_zero{}; - return *this * e.inverse(); + if (e == prime_field_element {0}) throw division_by_zero {}; + return *this * e.inverse (); } template template - inline prime_field_element prime_field::make(X... x) { - if (!valid()) return {}; - return prime_field_element(x...); + inline prime_field_element prime_field::make (X... x) { + if (!valid ()) return {}; + return prime_field_element (x...); } } diff --git a/include/data/math/arithmetic.hpp b/include/data/math/arithmetic.hpp index c85b7512..eaf0c8bf 100644 --- a/include/data/math/arithmetic.hpp +++ b/include/data/math/arithmetic.hpp @@ -16,45 +16,6 @@ namespace data::math { return X {0}; } }; - - template struct identity; - template struct inverse; - - template struct plus { - X operator () (const X &a, const X &b) { - return a + b; - } - }; - - template struct identity, X> { - X operator () () { - return X {0}; - } - }; - - template struct times { - X operator () (const X &a, const X &b) { - return a * b; - } - }; - - template struct identity, X> { - X operator () () { - return X {1}; - } - }; - - template <> struct inverse, int8_t> { - int8_t operator () (const int8_t &a, const int8_t &b) { - return b - a; - } - }; - - template struct inverse, X> { - X operator () (X a, X b) { - return b - a; - } - }; } diff --git a/include/data/math/associative.hpp b/include/data/math/associative.hpp index c09f9c00..8726ad68 100644 --- a/include/data/math/associative.hpp +++ b/include/data/math/associative.hpp @@ -5,10 +5,15 @@ #ifndef DATA_MATH_ASSOCIATIVE #define DATA_MATH_ASSOCIATIVE +#include + namespace data::math { template struct associative; + template using associative_plus = associative, x>; + template using associative_times = associative, x>; + } #endif diff --git a/include/data/math/commutative.hpp b/include/data/math/commutative.hpp index dce449db..c3311cc5 100644 --- a/include/data/math/commutative.hpp +++ b/include/data/math/commutative.hpp @@ -5,10 +5,15 @@ #ifndef DATA_MATH_COMMUTATIVE #define DATA_MATH_COMMUTATIVE +#include + namespace data::math { template struct commutative; + template using commutative_plus = commutative, x>; + template using commutative_times = commutative, x>; + } #endif diff --git a/include/data/math/field.hpp b/include/data/math/field.hpp index fc9dc78b..5403b36b 100644 --- a/include/data/math/field.hpp +++ b/include/data/math/field.hpp @@ -12,10 +12,12 @@ namespace data::math { template , typename times = math::times> - concept field = math::ring && abelian && - requires (const elem &a, const math::nonzero &b) { + concept field = integral_domain && + requires (const elem &a, const elem &b) { {a / b} -> std::same_as; - } && math::abelian, times>; + } && requires (const nonzero &a, const nonzero &b) { + {inverse {} (a, b)} -> std::convertible_to>; + }; } diff --git a/include/data/math/fraction.hpp b/include/data/math/fraction.hpp index 73e6f8a7..bb5840ab 100644 --- a/include/data/math/fraction.hpp +++ b/include/data/math/fraction.hpp @@ -20,6 +20,54 @@ namespace data::math { template std::weak_ordering operator <=> (const fraction &, const fraction &); + template fraction operator - (const fraction &); + template fraction operator + (const fraction &, const fraction &); + template fraction operator - (const fraction &, const fraction &); + template fraction operator * (const fraction &, const fraction &); + + template + struct commutative>, fraction> : commutative, Z> {}; + + template + struct associative>, fraction> : associative, Z> {}; + + template + struct commutative>, fraction> : commutative, Z> {}; + + template + struct associative>, fraction> : associative, Z> {}; + + template + struct identity>, fraction> : identity, Z> { + fraction operator () (); + }; + + template + struct identity>, fraction> : identity, Z> { + fraction operator () (); + }; + + template + struct inverse>, fraction> : inverse, Z> { + fraction operator () (const fraction &a, const fraction &b); + }; + + template struct inverse>, fraction> : inverse, Z> { + fraction operator () (const fraction &a, const fraction &b); + }; + + template struct times> { + fraction operator () (const fraction &, const fraction &); + nonzero> operator () (const nonzero> &, const nonzero> &); + }; + + template struct inverse>, fraction> { + nonzero> operator () (const nonzero> &); + nonzero> operator () (const nonzero> &, const nonzero> &); + }; + + template fraction operator / (const fraction &, const fraction &); + template std::ostream &operator << (std::ostream &o, const fraction &x); @@ -44,6 +92,8 @@ namespace data::math { return number::euclidian::extended::algorithm (a, b).GCD; } + public: + // reduce to lowest terms. static fraction divide (Z n, N d) { if (d == 0) return fraction {Z {0}, nonzero {N {0u}}}; // Invalid value. if (n == 0) return fraction {Z {0}, nonzero {N {1u}}}; @@ -51,23 +101,17 @@ namespace data::math { return fraction (n / Z (gcd_ab), nonzero (d / gcd_ab)); } - public: fraction (); - fraction (Z n); - fraction (Z n, N d); + + template fraction (ZZ n); + + template fraction (ZZ n, NN d); bool operator == (const Z &z) const; - - static maybe inverse (const fraction &f); - - fraction operator - () const; - fraction operator + (const fraction &f) const; + fraction operator + (const Z &z) const; - fraction operator - (const fraction &f) const; fraction operator - (const Z &z) const; - fraction operator * (const fraction &f) const; fraction operator * (const Z &z) const; - fraction operator / (const nonzero &f) const; fraction operator / (const Z &z) const; fraction &operator += (const fraction &f); @@ -75,39 +119,15 @@ namespace data::math { fraction &operator *= (const fraction &f); fraction &operator /= (const fraction &f); + friend class inverse>, fraction>; + }; template std::ostream inline &operator << (std::ostream &o, const fraction &x) { - return o << "fraction {" << x.Numerator << ", " << x.Denominator.Value << "}"; + if (x.Denominator.Value == 1) return o << x.Numerator; + return o << "(" << x.Numerator << " / " << x.Denominator.Value << ")"; } - - template - struct commutative>, fraction> : commutative, Z> {}; - - template - struct associative>, fraction> : associative, Z> {}; - - template - struct commutative>, fraction> : commutative, Z> {}; - - template - struct associative>, fraction> : associative, Z> {}; - - template - struct identity>, fraction> : identity, Z> { - fraction operator () (); - }; - - template - struct identity>, fraction> : identity, Z> { - fraction operator () (); - }; - - template - struct inverse>, fraction> : inverse, Z> { - fraction operator () (const fraction &a, const fraction &b); - }; template struct abs> { @@ -123,10 +143,17 @@ namespace data::math { inline fraction::fraction () : Numerator {0}, Denominator {1u} {} template - inline fraction::fraction (Z n, N d) : fraction (divide (n, d)) {} + template + inline fraction::fraction (ZZ n, NN d) : fraction (divide (Z (n), N (d))) {} template - inline fraction::fraction (Z n) : Numerator {n}, Denominator {uint64 {1}} {} + template + inline fraction::fraction (ZZ n) : Numerator {Z (n)}, Denominator {1u} {} + + template + bool inline operator == (const fraction &a, const fraction &b) { + return a <=> b == 0; + } template std::weak_ordering inline operator <=> (const fraction &a, const fraction &b) { @@ -134,58 +161,61 @@ namespace data::math { } template - bool inline operator == (const fraction &a, const fraction &b) { - return a <=> b == 0; + bool inline fraction::operator == (const Z &z) const { + return *this == fraction {z}; } - template - maybe> inline fraction::inverse (const fraction &f) { - if (f == 0) return nullptr; - return std::make_shared ( - fraction {Z {f.Denominator} * data::sign (f.Numerator), nonzero {data::abs (f.Numerator)}}); + template + fraction inline operator - (const fraction &x) { + auto z = x; + z.Numerator = -z.Numerator; + return z; } - template - fraction inline fraction::operator - () const { - return {-Numerator, Denominator}; + template + fraction inline operator + (const fraction &a, const fraction &b) { + return fraction::divide (b.Numerator * a.Denominator.Value + a.Numerator * b.Denominator.Value, + a.Denominator.Value * b.Denominator.Value); } - template - fraction inline fraction::operator + (const fraction &f) const { - return divide (f.Numerator * Denominator.Value + Numerator * f.Denominator.Value, - Denominator.Value * f.Denominator.Value); + template + fraction inline operator - (const fraction &a, const fraction &b) { + return a + (-b); } - template - fraction inline fraction::operator + (const Z &z) const { - return operator + (fraction {z}); + template + fraction inline operator * (const fraction &a, const fraction &b) { + return fraction {a.Numerator * b.Numerator, a.Denominator.Value * b.Denominator.Value}; } - template - fraction inline fraction::operator - (const fraction &f) const { - return (*this) + (-f); + template + nonzero> inverse>, fraction>::operator () (const nonzero> &x) { + if (x.Value.Numerator == 0) throw division_by_zero {}; + return nonzero {fraction {Z (x.Value.Denominator) * data::sign (x.Value.Numerator), nonzero {data::abs (x.Value.Numerator)}}}; } - template - fraction fraction::operator - (const Z &z) const { - return operator - (fraction {z}); + template + nonzero> inverse>, fraction>::operator () (const nonzero> &a, const nonzero> &b) { + return nonzero {b.Value / a.Value}; + } + + template fraction operator / (const fraction &a, const fraction &b) { + return a * inverse>, fraction> {} (nonzero {b}).Value; } template - fraction inline fraction::operator * (const fraction &f) const { - return fraction {Numerator * f.Numerator, Denominator * f.Denominator}; + fraction inline fraction::operator + (const Z &z) const { + return operator + (fraction {z}); } template - fraction inline fraction::operator * (const Z &z) const { - return *this * fraction {z}; + fraction fraction::operator - (const Z &z) const { + return operator - (fraction {z}); } template - fraction inline fraction::operator / (const nonzero &f) const { - auto ii = inverse (f); - if (!bool (ii)) throw division_by_zero {}; - return (*this) * *ii; + fraction inline fraction::operator * (const Z &z) const { + return *this * fraction {z}; } template diff --git a/include/data/math/nonnegative.hpp b/include/data/math/nonnegative.hpp index 4c7a842d..11be91ac 100644 --- a/include/data/math/nonnegative.hpp +++ b/include/data/math/nonnegative.hpp @@ -10,140 +10,111 @@ namespace data::math { + template struct nonnegative; + template struct nonzero; + + template bool operator <=> (const nonnegative &, const nonnegative &); + template bool operator <=> (const nonzero &, const nonzero &); + + template nonnegative operator + (const nonnegative &m, const nonnegative &n); + template nonnegative operator * (const nonnegative &m, const nonnegative &n); + + template nonzero operator * (const nonzero &m, const nonzero &n); + template struct nonnegative { R Value; - explicit nonnegative(const R& n) : Value{n} {} - explicit nonnegative(R&& n) : Value{n} {} - nonnegative() : Value{-1} {} + explicit nonnegative (const R& n) : Value {n} {} + explicit nonnegative (R &&n) : Value {n} {} + nonnegative () : Value {-1} {} - bool valid() { - return data::valid(Value) && Value >= R(0); + bool valid () { + return data::valid (Value) && Value >= R (0); } - operator R() const { + operator R () const { return Value; } + + nonnegative &operator = (const R &n) { + Value = n; + return *this; + } + + nonnegative &operator = (R &&n) { + Value = n; + return *this; + } - nonnegative& operator++(); - nonnegative operator++(int); + nonnegative &operator ++ (); + nonnegative operator ++ (int); }; template struct nonzero { R Value; - explicit nonzero(const R &n) : Value{n} {} - explicit nonzero(R &&n) : Value{n} {} - nonzero() : Value{0} {} + explicit nonzero (const R &n) : Value {n} {} + explicit nonzero (R &&n) : Value {n} {} + nonzero () : Value {0} {} - bool valid() const { - return data::valid(Value) && Value != R(0); + bool valid () const { + return data::valid (Value) && Value != R (0); } - operator R() const { + operator R () const { return Value; } - nonzero& operator=(const R &n) { + nonzero &operator = (const R &n) { Value = n; return *this; } - nonzero& operator=(R &&n) { + nonzero &operator = (R &&n) { Value = n; return *this; } }; template - nonzero(const R &) -> nonzero; - - template - inline nonnegative operator+(const nonnegative& m, const nonnegative& n) { - return nonnegative{m.Value + n.Value}; - } - - template - inline nonnegative operator*(const nonnegative& m, const nonnegative& n) { - return nonnegative{m.Value * n.Value}; - } - - template - inline bool operator==(const nonnegative& m, const nonnegative& n) { - return m.Value == n.Value; - } + nonzero (const R &) -> nonzero; template - inline bool operator!=(const nonnegative& m, const nonnegative& n) { - return m.Value != n.Value; + bool inline operator <=> (const nonnegative &m, const nonnegative &n) { + return m.Value <=> n.Value; } template - inline bool operator>(const nonnegative& m, const nonnegative& n) { - return m.Value > n.Value; + bool inline operator <=> (const nonzero &m, const nonzero &n) { + return m.Value <=> n.Value; } template - inline bool operator>=(const nonnegative& m, const nonnegative& n) { - return m.Value >= n.Value; + nonnegative inline operator + (const nonnegative &m, const nonnegative &n) { + return nonnegative {m.Value + n.Value}; } template - inline bool operator<(const nonnegative& m, const nonnegative& n) { - return m.Value < n.Value; + nonnegative inline operator * (const nonnegative &m, const nonnegative &n) { + return nonnegative {m.Value * n.Value}; } template - inline bool operator<=(const nonnegative& m, const nonnegative& n) { - return m.Value <= n.Value; + nonzero inline operator * (const nonzero &m, const nonzero &n) { + return nonzero {m.Value * n.Value}; } - template nonnegative& nonnegative::operator++() { + template nonnegative inline &nonnegative::operator ++ () { ++Value; return *this; } - template nonnegative nonnegative::operator++(int) { + template nonnegative inline nonnegative::operator ++ (int) { nonnegative n = *this; ++Value; return n; } - template - inline nonzero operator*(const nonzero& m, const nonzero& n) { - return nonzero{m.Value * n.Value}; - } - - template - inline bool operator==(const nonzero& m, const nonzero& n) { - return m.Value == n.Value; - } - - template - inline bool operator!=(const nonzero& m, const nonzero& n) { - return m.Value != n.Value; - } - - template - inline bool operator>(const nonzero& m, const nonzero& n) { - return m.Value > n.Value; - } - - template - inline bool operator>=(const nonzero& m, const nonzero& n) { - return m.Value >= n.Value; - } - - template - inline bool operator<(const nonzero& m, const nonzero& n) { - return m.Value < n.Value; - } - - template - inline bool operator<=(const nonzero& m, const nonzero& n) { - return m.Value <= n.Value; - } - } #endif diff --git a/include/data/math/number/bounded.hpp b/include/data/math/number/bounded.hpp index 28b599b9..9a399225 100644 --- a/include/data/math/number/bounded.hpp +++ b/include/data/math/number/bounded.hpp @@ -12,9 +12,9 @@ #include namespace data::math::number { - + template bounded inline operator / (const bounded &a, const bounded &b) { - return divide> (a, b).Quotient; + return divide> {} (a, b).Quotient; } template uint inline operator / (const uint &a, uint64 b) { @@ -50,6 +50,26 @@ namespace data::math::number { } } +namespace data::math { + template + division, uint> inline divide, uint>::operator () (const uint &v, const uint &z) { + auto d = divide, N_bytes> {} (v, z); + return {uint {d.Quotient}, uint {d.Remainder}}; + } + + template + division, uint> inline divide, sint>::operator () (const sint &v, const sint &z) { + auto d = divide, Z_bytes> {} (v, z); + return {sint {d.Quotient}, uint {d.Remainder}}; + } + + template + division, uint> inline divide, uint>::operator () (const sint &v, const uint &z) { + auto d = divide, N_bytes> {} (v, z); + return {sint {d.Quotient}, uint {d.Remainder}}; + } +} + namespace data::encoding::hexidecimal { template diff --git a/include/data/math/number/bounded/bounded.hpp b/include/data/math/number/bounded/bounded.hpp index 32300a8d..7988c3d7 100644 --- a/include/data/math/number/bounded/bounded.hpp +++ b/include/data/math/number/bounded/bounded.hpp @@ -150,7 +150,19 @@ namespace data::math { template bool is_positive (const uint &); template bool is_positive (const sint &); - + + template struct divide, uint> { + division, uint> operator () (const uint &, const uint &); + }; + + template struct divide, sint> { + division, uint> operator () (const sint &, const sint &); + }; + + template struct divide, uint> { + division, uint> operator () (const sint &, const uint &); + }; + } namespace data { @@ -421,7 +433,6 @@ namespace data::math::number { explicit operator int64 () const; - private: explicit bounded (const Z_bytes &z) { if (z.size () <= size) { std::copy (z.words ().begin (), z.words ().end (), this->words ().begin ()); diff --git a/include/data/math/number/bytes.hpp b/include/data/math/number/bytes.hpp index 57bfed9d..b6e08156 100644 --- a/include/data/math/number/bytes.hpp +++ b/include/data/math/number/bytes.hpp @@ -99,6 +99,31 @@ namespace data::math::number { } +namespace data::math { + + + template + division, N_bytes> inline divide, N_bytes>::operator () (const N_bytes &v, const N_bytes &z) { + return number::natural::divide (v, z); + } + + template + division, N_bytes> inline divide, Z_bytes>::operator () (const Z_bytes &v, const Z_bytes &z) { + return number::integer::divide (v, z); + } + + template + division, N_bytes> inline divide, N_bytes>::operator () (const Z_bytes &v, const N_bytes &z) { + return number::integer::divide (v, Z_bytes (r) (z)); + } + + template + division, Z_bytes_twos> inline divide, Z_bytes_twos>::operator () + (const Z_bytes_twos &v, const Z_bytes_twos &z) { + return number::integer::divide (v, z); + } +} + #include #include diff --git a/include/data/math/number/bytes/Z.hpp b/include/data/math/number/bytes/Z.hpp index f2124a11..6cf0041c 100644 --- a/include/data/math/number/bytes/Z.hpp +++ b/include/data/math/number/bytes/Z.hpp @@ -435,6 +435,18 @@ namespace data::math { std::copy (z.begin (), z.end (), n.begin ()); return n; } + + template + number::Z_bytes inline times>::operator () + (const number::Z_bytes &a, const number::Z_bytes &b) { + return a * b; + } + + template + nonzero> inline times>::operator () + (const nonzero> &a, const nonzero> &b) { + return a * b; + } template N_bytes inline quadrance>::operator () (const N_bytes &x) { return x * x; @@ -981,8 +993,8 @@ namespace data::math::number { template N_bytes::operator N () const { N x {}; - for (const byte &b : this->words ()) { - x << 8; + for (const byte &b : this->words ().reverse ()) { + x <<= 8; x += b; } @@ -998,8 +1010,8 @@ namespace data::math::number { auto ab = data::abs (*this); N x {}; - for (const byte &b : ab.words ()) { - x << 8; + for (const byte &b : ab.words ().reverse ()) { + x <<= 8; x += b; } diff --git a/include/data/math/number/bytes/bytes.hpp b/include/data/math/number/bytes/bytes.hpp index 598a1e1a..dc0ea8ea 100644 --- a/include/data/math/number/bytes/bytes.hpp +++ b/include/data/math/number/bytes/bytes.hpp @@ -202,6 +202,11 @@ namespace data::math { template struct abs> { N_bytes operator () (const number::Z_bytes &); }; + + template struct times> { + number::Z_bytes operator () (const number::Z_bytes &a, const number::Z_bytes &b); + nonzero> operator () (const nonzero> &a, const nonzero> &b); + }; template struct abs> { number::Z_bytes operator () (const number::Z_bytes &); @@ -245,6 +250,22 @@ namespace data::math { return b - a; } }; + + template struct divide, N_bytes> { + division, N_bytes> operator () (const N_bytes &, const N_bytes &); + }; + + template struct divide, Z_bytes> { + division, N_bytes> operator () (const Z_bytes &, const Z_bytes &); + }; + + template struct divide, N_bytes> { + division, N_bytes> operator () (const Z_bytes &, const N_bytes &); + }; + + template struct divide, Z_bytes_twos> { + division, Z_bytes_twos> operator () (const Z_bytes_twos &, const Z_bytes_twos &); + }; } diff --git a/include/data/math/number/gmp/N.hpp b/include/data/math/number/gmp/N.hpp index c4c9a497..139c0395 100644 --- a/include/data/math/number/gmp/N.hpp +++ b/include/data/math/number/gmp/N.hpp @@ -98,7 +98,7 @@ namespace data::math::number::GMP { } uint64 inline operator % (const N &a, uint64 b) { - return uint64 (a.divide(b).Remainder); + return uint64 (a.divide (b).Remainder); } uint64 inline operator % (const Z &a, uint64 b) { @@ -365,6 +365,14 @@ namespace data::math { __gmp_abs_function::eval (n.Value.MPZ, i.MPZ); return n; } + + N inline times::operator () (const N &a, const N &b) { + return a * b; + } + + nonzero inline times::operator () (const nonzero &a, const nonzero &b) { + return a * b; + } } namespace data::math::number { @@ -406,10 +414,6 @@ 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; } diff --git a/include/data/math/number/gmp/Z.hpp b/include/data/math/number/gmp/Z.hpp index a58002a7..ee2f7a4f 100644 --- a/include/data/math/number/gmp/Z.hpp +++ b/include/data/math/number/gmp/Z.hpp @@ -147,6 +147,12 @@ namespace data::math::number::GMP { } +namespace data { + math::sign inline sign (const math::Z &z) { + return math::number::GMP::sign (z.MPZ[0]); + } +} + namespace data::math { Z inline identity, Z>::operator () () { @@ -160,6 +166,14 @@ namespace data::math { Z inline inverse, Z>::operator () (const Z &a, const Z &b) { return b - a; } + + Z inline times::operator () (const Z &a, const Z &b) { + return a * b; + } + + nonzero inline times::operator () (const nonzero &a, const nonzero &b) { + return a * b; + } } namespace data::encoding::hexidecimal { diff --git a/include/data/math/number/gmp/gmp.hpp b/include/data/math/number/gmp/gmp.hpp index 3c8dfca5..9d608afc 100644 --- a/include/data/math/number/gmp/gmp.hpp +++ b/include/data/math/number/gmp/gmp.hpp @@ -8,4 +8,82 @@ #include #include +namespace data::math { + + division inline divide::operator () (const N &v, const N &z) { + return number::natural::divide (v, z); + } + + division inline divide::operator () (const Z &v, const Z &z) { + return number::integer::divide (v, z); + } + + division inline divide::operator () (const Z &v, const N &z) { + return number::integer::divide (v, Z (z)); + } + + division inline divide::operator () (const dec_uint &v, const dec_uint &z) { + auto d = divide {} (N (v), N (z)); + return {encoding::decimal::write (d.Quotient), encoding::decimal::write (d.Remainder)}; + } + + division inline divide::operator () (const dec_int &v, const dec_uint &z) { + auto d = divide {} (Z (v), N (z)); + return {encoding::signed_decimal::write (d.Quotient), encoding::decimal::write (d.Remainder)}; + } + + division inline divide::operator () (const dec_int &v, const dec_int &z) { + auto d = divide {} (Z (v), Z (z)); + return {encoding::signed_decimal::write (d.Quotient), encoding::decimal::write (d.Remainder)}; + } + + template + division, hex::uint> divide, hex::uint>::operator () (const hex::uint &v, const hex::uint &z) { + auto d = divide {} (N (v), N (z)); + return {encoding::hexidecimal::write (d.Quotient), encoding::hexidecimal::write (d.Remainder)}; + } + + template + division, hex::uint> divide, hex::int1>::operator () (const hex::int1 &v, const hex::int1 &z) { + auto d = divide {} (Z (v), N (z)); + return {encoding::hexidecimal::write (d.Quotient), encoding::hexidecimal::write (d.Remainder)}; + } + + template + division, hex::uint> divide, hex::uint>::operator () (const hex::int1 &v, const hex::uint &z) { + auto d = divide {} (Z (v), N (z)); + return {encoding::hexidecimal::write (d.Quotient), encoding::hexidecimal::write (d.Remainder)}; + } + + template + division, hex::int2> divide, hex::int2>::operator () (const hex::int2 &v, const hex::int2 &z) { + auto d = divide {} (Z (v), Z (z)); + return {encoding::hexidecimal::write (d.Quotient), + encoding::hexidecimal::write (d.Remainder)}; + } +} + +namespace data::encoding::decimal { + inline string::operator math::N () const { + return math::N::read (*this); + } +} + +namespace data::encoding::signed_decimal { + inline string::operator math::Z () const { + return math::Z::read (*this); + } +} + +namespace data::encoding::hexidecimal { + + template inline complemented_string::operator math::Z () const { + return math::Z (math::Z_bytes_twos::read (*this)); + } + + template inline complemented_string::operator math::N () const { + return math::N::read (*this); + } +} + #endif diff --git a/include/data/math/number/gmp/mpz.hpp b/include/data/math/number/gmp/mpz.hpp index b6156965..402a3491 100644 --- a/include/data/math/number/gmp/mpz.hpp +++ b/include/data/math/number/gmp/mpz.hpp @@ -166,6 +166,16 @@ namespace data::math { template <> struct abs { N operator () (const Z &); }; + + template <> struct times { + N operator () (const N &a, const N &b); + nonzero operator () (const nonzero &a, const nonzero &b); + }; + + template <> struct times { + Z operator () (const Z &a, const Z &b); + nonzero operator () (const nonzero &a, const nonzero &b); + }; template <> struct commutative, N> {}; template <> struct associative, N> {}; @@ -196,6 +206,22 @@ namespace data::math { template <> struct inverse, Z> { Z operator () (const Z &a, const Z &b); }; + + template <> struct inverse, Z> { + nonzero operator () (const nonzero &a, const nonzero &b); + }; + + template <> struct divide { + division operator () (const N &, const N &); + }; + + template <> struct divide { + division operator () (const Z &, const Z &); + }; + + template <> struct divide { + division operator () (const Z &, const N &); + }; bool is_zero (const N&); bool is_zero (const Z&); @@ -237,7 +263,7 @@ namespace data::encoding::hexidecimal { template struct integer; template integer write (const math::N&); - template integer write(const math::Z&); + template integer write (const math::Z&); std::ostream &write (std::ostream &, const math::N &, hex_case = hex_case::lower); std::ostream &write (std::ostream &, const math::Z &, hex_case = hex_case::lower, complement = complement::ones); diff --git a/include/data/math/polynomial.hpp b/include/data/math/polynomial.hpp index a76fa4bb..10e1c820 100644 --- a/include/data/math/polynomial.hpp +++ b/include/data/math/polynomial.hpp @@ -9,114 +9,168 @@ #include #include #include +#include namespace data::math { - template struct polynomial; + template struct polynomial; + + template + bool operator == (const polynomial, const polynomial); + + template + polynomial operator - (const polynomial); + + template + polynomial operator + (const polynomial, const polynomial); + + template + polynomial operator - (const polynomial, const polynomial); + + template + polynomial operator * (const polynomial, const polynomial); + + // the other operations work if A is a ring, but for division we need A to be a field. + template + struct divide> { + division> operator () (const polynomial, const nonzero>); + }; template std::ostream &operator << (std::ostream &o, const polynomial &p); + template + struct commutative>, polynomial> : commutative_plus {}; + + template + struct associative>, polynomial> : associative_plus {}; + + template + struct commutative>, polynomial> : commutative_times{}; + + template + struct associative>, polynomial> : associative_times {}; + + template + struct identity>, polynomial> : identity, A> { + polynomial operator () (); + }; + + template + struct identity>, polynomial> : identity, A> { + polynomial operator () (); + }; + template struct variable {}; template - std::ostream inline &operator << (std::ostream &o, const variable &x) { - return o << name; - } - - template + bool operator == (variable, variable); + + template + std::ostream &operator << (std::ostream &o, const variable &x); + + template struct polynomial { - struct term { - A Coefficient; - power, N> Power; - - term (A, N); - - bool operator == (const term &) const; - bool operator == (const A &) const; - - bool operator != (const term &) const; - bool operator != (const A &) const; - - A operator () (const A) const; - polynomial operator () (const polynomial) const; - - term operator * (const term &) const; - term operator * (const A) const; - polynomial operator * (const polynomial) const; - }; polynomial (); polynomial (const A a); - polynomial (const term t); - - constexpr static polynomial unit (); + + bool valid () const; constexpr static polynomial zero (); + constexpr static polynomial unit (); + constexpr static polynomial var (); uint32 degree () const; static bool equal (const polynomial, const polynomial); - - bool operator == (const polynomial) const; - bool operator != (const polynomial) const; - - static polynomial plus (const polynomial, const term); - static polynomial plus (const polynomial, const A); + static polynomial negative (const polynomial); static polynomial plus (const polynomial, const polynomial); + static polynomial minus (const polynomial, const polynomial); + static polynomial times (const polynomial, const polynomial); + static polynomial pow (const polynomial, const N &); + + bool operator == (const A &) const; - polynomial operator + (const term) const; polynomial operator + (const A) const; - polynomial operator + (const polynomial &) const; - polynomial operator += (const term); polynomial operator += (const A); polynomial operator += (const polynomial &); polynomial operator * (const A) const; - polynomial operator * (const term) const; - polynomial operator * (const polynomial) const; - - polynomial operator ^ (const N) const; + polynomial operator *= (const A) const; + polynomial operator *= (const polynomial) const; + polynomial operator () (const A) const; polynomial operator () (const polynomial) const; - - bool operator == (const polynomial &); - - bool operator != (const polynomial &); - - division divide (const polynomial Dividend, const polynomial Divisor); - - division operator / (const polynomial) const; - - polynomial derivative () const; + + polynomial operator ^ (const N &n) const; bool operator > (const polynomial) const; bool operator < (const polynomial) const; bool operator <= (const polynomial) const; bool operator >= (const polynomial) const; - - template - static polynomial make (P... rest); + + polynomial derivative () const; + + static division divide (const polynomial, const polynomial); private: - // for ordering terms in the polynomial by power. - struct ordering { - term Term; + // remove any terms that are equal to zero. + polynomial normalize () const; + + using power = math::power, N>; + + // a term in a polynomial is the part like A (x ^ N). + struct term { + A Coefficient; + power Power; - ordering (term t); + explicit term () : Coefficient {0}, Power {{}, 1} {} + explicit term (A, const N &n); + + // cannot have 0 ^ 0. + bool valid () const { + return Coefficient != 0 || Power.Exponent != 0u; + } + + bool operator == (const term &) const; + bool operator == (const A &) const; + + A operator () (const A) const; + polynomial operator () (const polynomial) const; - bool operator == (const ordering &) const; - bool operator > (const ordering &) const; - bool operator < (const ordering &) const; - bool operator <= (const ordering &) const; - bool operator >= (const ordering &) const; + term operator - () const { + return term {-Coefficient, Power.Exponent}; + } + + term operator * (const term &) const; + term operator * (const A) const; + polynomial operator * (const polynomial) const; - division operator / (const ordering &) const; + // used for ordering terms so the fact that one term < another + // does not mean that it is actually numerically bigger. + std::weak_ordering operator <=> (const term &o) const { + return Coefficient == 0 && o.Coefficient == 0 || Power.Exponent == 0u && o.Power.Exponent == 0u ? std::weak_ordering::equivalent : + Power.Exponent == o.Power.Exponent ? Coefficient <=> o.Coefficient : o.Power.Exponent <=> Power.Exponent; + } + + term derivative () const { + if (Power.Exponent == 0) return term {}; + return term {Coefficient * Power.Exponent, Power.Exponent - 1}; + } }; - using terms = ordered_list; + polynomial (const term t); + + polynomial operator + (const term t) const; + + polynomial operator += (const term t); + + polynomial operator * (const term t) const; + + using terms = ordered_list; terms Terms; @@ -124,49 +178,39 @@ namespace data::math { polynomial rest () const; - polynomial (const terms l); - polynomial (const list l); - - friend std::ostream &operator << (std::ostream &, const polynomial &); + friend std::ostream &operator << (std::ostream &, const polynomial &); polynomial insert (const term) const; polynomial insert (const terms) const; - polynomial insert (const polynomial p) const; - static polynomial build (const polynomial p); - - template - static polynomial build (const polynomial p, const A, P... rest); - - template - static polynomial build (const polynomial p, const term, P... rest); + explicit polynomial (const terms t, void*) : Terms {t} {} }; - - template - struct commutative>, polynomial> : commutative, A> {}; - - template - struct associative>, polynomial> : associative, A> {}; - - template - struct commutative>, polynomial> : commutative, A>{}; - - template - struct associative>, polynomial> : associative, A> {}; template - struct identity>, polynomial> : identity, A> { - static const polynomial value () { - return identity, A>::value (); - } - }; + polynomial inline identity>, polynomial>::operator () () { + return identity, A>::value (); + } template - struct identity>, polynomial> : identity, A> { - static const polynomial value () { - return identity, A>::value (); - } - }; + polynomial inline identity>, polynomial>::operator () () { + return identity, A>::value (); + } + + template + bool inline operator == (variable, variable) { + return true; + } + + template + std::ostream inline &operator << (std::ostream &o, const variable &x) { + return o << name; + } + + template + division> inline divide>::operator () + (const polynomial a, const nonzero> b) { + return polynomial::divide (a, b); + } template std::ostream &operator << (std::ostream &o, const polynomial &p) { @@ -174,226 +218,198 @@ namespace data::math { if (!p.Terms.empty ()) { typename polynomial::terms z = p.Terms; while (true) { - typename polynomial::term t = z.first ().Term; - o << t.Coefficient << " " << t.Power; + typename polynomial::term t = z.first (); + if (t.Power.Exponent == 0) o << t.Coefficient; + else { + if (t.Coefficient != 1) o << t.Coefficient << " "; + o << t.Power; + } z = z.rest (); if (z.empty ()) break; o << " + "; } - } + } else o << "0"; return o << "}"; } - - template - inline bool polynomial::term::operator == (const term &t) const { - return Coefficient == t.Coefficient && Power.Exponent == t.Power.Exponent; + + template + bool inline operator == (const polynomial a, const polynomial b) { + return polynomial::equal (a, b); } - - template - inline bool polynomial::term::operator == (const A &a) const { - return operator == (term {a, 0}); + + template + polynomial inline operator - (const polynomial p) { + return polynomial::negative (p); } - - template - bool inline polynomial::term::operator != (const term &t) const { - return !operator == (t); + + template + polynomial inline operator + (const polynomial a, const polynomial b) { + return polynomial::plus (a, b); } - - template - bool inline polynomial::term::operator != (const A &a) const { - return !operator == (term {a, 0}); + + template + polynomial inline operator - (const polynomial a, const polynomial b) { + return polynomial::minus (a, b); } - - template - A inline polynomial::term::operator () (const A f) const{ - return (f ^ Power) * Coefficient; + + template + polynomial inline operator * (const polynomial a, const polynomial b) { + return polynomial::times (a, b); } - - template - polynomial inline polynomial::term::operator () (const polynomial p) const { - return (p ^ Power.Exponent) * Coefficient; + + template + polynomial inline polynomial::operator ^ (const N &n) const { + return polynomial::pow (*this, n); } - - template - typename polynomial::term inline polynomial::term::operator * (const term &z) const { - return term {Coefficient * z.Coefficient, Power.Exponent + z.Power.Exponent}; + + template + polynomial inline polynomial::pow (const polynomial p, const N &n) { + return data::pow (p, n); + //throw 0; } - - template - typename polynomial::term inline polynomial::term::operator * (const A z) const { - return term {Coefficient * z, Power.Exponent}; + + template + bool polynomial::valid () const { + return Terms.valid (); } template - polynomial inline polynomial::term::operator * (const polynomial p) const { - return polynomial {for_each ([this] (ordering o) -> term { - return this->operator * (o.Term); - }, p.Terms)}; + bool inline polynomial::term::operator == (const term &t) const { + return *this <=> t == 0; } - - template - inline polynomial::term::term (A a, N p) : Coefficient {a}, Power {variable {}, p} {} - - template - inline polynomial::ordering::ordering (term t) : Term{t} {} template - inline bool polynomial::ordering::operator == (const ordering &o) const { - return Term.Power.Exponent == o.Term.Power.Exponent; + bool inline polynomial::term::operator == (const A &a) const { + return operator == (term {a, 0}); } template - inline bool polynomial::ordering::operator > (const ordering &o) const { - return Term.Power.Exponent > o.Term.Power.Exponent; + A inline polynomial::term::operator () (const A f) const{ + return (f ^ Power) * Coefficient; } template - inline bool polynomial::ordering::operator < (const ordering &o) const { - return Term.Power.Exponent < o.Term.Power.Exponent; + polynomial inline polynomial::term::operator () (const polynomial p) const { + return (p ^ Power.Exponent) * Coefficient; } template - inline bool polynomial::ordering::operator <= (const ordering &o) const { - return Term.Power.Exponent <= o.Term.Power.Exponent; + typename polynomial::term inline polynomial::term::operator * (const term &t) const { + return term {Coefficient * t.Coefficient, Power.Exponent + t.Power.Exponent}; } - + template - inline bool polynomial::ordering::operator >= (const ordering &o) const { - return Term.Power.Exponent >= o.Term.Power.Exponent; + typename polynomial::term inline polynomial::term::operator * (const A a) const { + return term {Coefficient * a, Power.Exponent}; } template - division::ordering> - polynomial::ordering::operator / (const ordering &o) const { - if (o.Term == 0) throw division_by_zero {}; - if (Term.Power < o.Term.Power) return division {*this, o}; - return division { - ordering {term { - Term.Coefficient / o.Term.Coefficient, - Term.Power - o.Term.Power}}, - ordering {0}}; + polynomial inline polynomial::term::operator * (const polynomial p) const { + return fold ([this] (const polynomial &p, const term &t) -> polynomial { + return p + (*this * t); + }, polynomial {}, reverse (p.Terms)); } - - template - inline polynomial::polynomial (const terms l) : Terms {l} {} - + template - polynomial::polynomial (const list l) : Terms {} { - list t = l; - while (!t.empty ()) { - operator += (t.first ()); - t = t.rest (); - } - } + inline polynomial::term::term (A a, const N& n) : Coefficient {a}, Power {{}, n} {} template inline polynomial::polynomial () : Terms {} {} template - inline polynomial::polynomial (const A a) : Terms {terms {}.insert (ordering {term {a, 0}})} {} + inline polynomial::polynomial (const A a) : Terms {terms {}.insert (term {a, 0})} {} template - inline polynomial::polynomial (const term t) : Terms {terms {}.insert (ordering {t})} {} + inline polynomial::polynomial (const term t) : Terms {terms {}.insert (t)} {} template typename polynomial::term inline polynomial::first () const { - return Terms.first ().Term; + return Terms.first (); } template polynomial inline polynomial::rest () const { - return Terms.rest (); + return polynomial {Terms.rest (), nullptr}; } template constexpr polynomial inline polynomial::unit () { - return polynomial {term {A {1}, N {0}}}; + return polynomial {term {A {1}, 0}}; } template constexpr polynomial inline polynomial::zero () { - return polynomial {term {A {0}, N {0}}}; + return polynomial {term {A {0}, 0}}; } template - uint32 inline polynomial::degree () const { - if (Terms.empty ()) return 0; - return Terms.first ().Term.Power.Exponent; + constexpr polynomial inline polynomial::var () { + return polynomial (term {A (1), 1}); } template - bool polynomial::equal (const polynomial p, const polynomial q) { - if (p.degree () != q.degree ()) return false; - if (p.Terms.empty ()) return true; - if (p.first () != q.first ()) return false; - return equal (p.rest (), q.rest ()); + uint32 inline polynomial::degree () const { + auto p = normalize (); + if (p.Terms.empty ()) return 0; + return p.Terms.first ().Power.Exponent; } template - bool inline polynomial::operator == (const polynomial p) const { - return equal (*this, p); + bool inline polynomial::equal (const polynomial p, const polynomial q) { + return p.normalize ().Terms == q.normalize ().Terms; } - + template - bool inline polynomial::operator != (const polynomial p) const { - return !equal (*this, p); + bool inline polynomial::operator == (const A &p) const { + return equal (*this, polynomial {p}); } - + template - polynomial polynomial::insert (const term z) const { - if (Terms.empty ()) return z; - if (z == term {A {0}, N {0}}) return *this; - ordering first = Terms.first (); - if (first == ordering {z}) - return rest ().insert (term {z.Coefficient + first.Term.Coefficient, z.Power.Exponent}); - return Terms.insert (ordering {z}); + polynomial polynomial::insert (const term t) const { + if (t == term {}) return *this; + if (Terms.empty ()) return {t}; + term first = Terms.first (); + if (t.Power.Exponent > first.Power.Exponent) return polynomial {Terms.insert (t), nullptr}; + if (first.Power.Exponent == t.Power.Exponent) return rest ().insert (term {t.Coefficient + first.Coefficient, t.Power.Exponent}); + return rest ().insert (t).insert (first); } - + template polynomial inline polynomial::insert (terms t) const { - if (Terms.empty ()) return {t}; + if (Terms.empty ()) return polynomial {t, nullptr}; if (t.empty ()) return *this; - return insert (t.first ().Term).insert (t.rest ()); + return polynomial {insert (t.first ()).insert (t.rest ())}; } template - polynomial inline polynomial::insert (const polynomial p) const { - if (Terms.empty ()) return p; - return insert (p.Terms); + polynomial inline polynomial::operator + (const A a) const { + return insert (term {a, 0}); } template - polynomial inline polynomial::plus (const polynomial p, const term z) { - return p.insert (z); + polynomial inline polynomial::plus (const polynomial a, const polynomial b) { + return a.insert (b.Terms).normalize (); } - + template - polynomial inline polynomial::plus (const polynomial t, const A a) { - return plus (t, term {a, 0}); + polynomial inline polynomial::minus (const polynomial a, const polynomial b) { + return a + -b; } - + template - polynomial inline polynomial::plus (const polynomial a, const polynomial b) { - return a.insert (b.Terms); + polynomial inline polynomial::negative (const polynomial a) { + return fold ([] (const polynomial p, const term &t) -> polynomial { + return p + -t; + }, polynomial {}, reverse (a.Terms)); } template polynomial inline polynomial::operator + (const term t) const { - return plus (*this, t); + return insert (t); }; template - polynomial inline polynomial::operator + (const A a) const { - return plus (*this, a); - } - - template - polynomial inline polynomial::operator + (const polynomial& p) const { - return plus (*this, p); - } - - template - polynomial inline polynomial::operator += (const term t) { + inline polynomial polynomial::operator += (const term t) { return *this = *this + t; } @@ -406,36 +422,26 @@ namespace data::math { polynomial inline polynomial::operator += (const polynomial &p) { return *this = *this + p; } - + template polynomial inline polynomial::operator * (const A z) const { - return reduce (math::plus {}, - for_each ([z] (ordering o) -> polynomial { - return o.Term * z; - }, Terms)); + return fold ([z] (const polynomial p, const term &t) -> polynomial { + return p + t * z; + }, polynomial {}, reverse (Terms)); } - + template polynomial inline polynomial::operator * (const term z) const { - return reduce (math::plus {}, - for_each ([z] (ordering o) -> polynomial { - return o.Term * z; - }, Terms)); + return fold ([z] (const polynomial p, const term &t) -> polynomial { + return p + t * z; + }, polynomial {}, reverse (Terms)); } - - template - polynomial inline polynomial::operator * (const polynomial p) const { - return reduce (math::plus {}, - for_each ([p] (ordering o) -> polynomial { - return o.Term * p; - }, Terms)); - } - + template - polynomial inline polynomial::operator ^ (const N n) const { - if (n == 0) return unit (); - if (n == 1) return *this; - return operator * (*this) ^ (n - 1); + polynomial inline polynomial::times (const polynomial a, const polynomial b) { + return fold ([b] (const polynomial p, const term &t) -> polynomial { + return p + t * b; + }, polynomial {}, reverse (a.Terms)); } template @@ -447,65 +453,39 @@ namespace data::math { // inefficient as it computes powers repeatedly. template polynomial polynomial::operator () (const polynomial p) const { - return reduce (math::plus {}, - for_each ([p] (ordering o) -> polynomial { - return o.Term (p); - }, Terms)); - } - - template - bool inline polynomial::operator == (const polynomial &p) { - return equal (Terms, p.Terms); - } - - template - bool inline polynomial::operator != (const polynomial &p) { - return !operator == (p); + return fold ([p] (const polynomial n, const term &t) -> polynomial { + return n + t (p); + }, polynomial {}, reverse (Terms)); } - + template - division> inline polynomial::divide (const polynomial Dividend, const polynomial Divisor) { + division> polynomial::divide (const polynomial Dividend, const polynomial Divisor) { if (Divisor == 0) throw division_by_zero {}; - if (Divisor.degree () > Dividend.degree ()) return division {Dividend, Divisor}; - term z = Divisor.first () / Dividend.first (); - return polynomial {z} + divide (Dividend - Divisor * x, Divisor); + + function (const polynomial, const polynomial)> f = [&f] (const polynomial d, const polynomial s) { + if (s.degree () > d.degree ()) return division {polynomial::zero (), d}; + auto d1 = d.first (); + auto s1 = s.first (); + term t {d1.Coefficient / s1.Coefficient, d1.Power.Exponent - s1.Power.Exponent}; + division> div = f (d - s * t, s); + return division> {div.Quotient + t, div.Remainder}; + }; + + return f (Dividend.normalize (), Divisor.normalize ()); } - + template - division> inline polynomial::operator / (const polynomial p) const { - return divide (*this, p); + polynomial polynomial::normalize () const { + return polynomial {select (Terms, function {[] (const term &t) -> bool { + return t.Coefficient != 0; + }}), nullptr}; } - + template polynomial inline polynomial::derivative () const { - return reduce (math::plus {}, - for_each([] (ordering o)->polynomial { - if (o.Term.Power == 0) return zero (); - return polynomial {term {o.Term.Coefficient * o.Term.Power, o.Term.Power - 1}}; - }, Terms)); - } - - template - template - polynomial inline polynomial::make (P... rest) { - return build (polynomial {}, rest...); - } - - template - polynomial inline polynomial::build (const polynomial p) { - return p; - } - - template - template - polynomial inline polynomial::build (const polynomial p, const A z, P... rest) { - return build (p + z, rest...); - } - - template - template - polynomial inline polynomial::build (const polynomial p, const term z, P... rest) { - return build (p + z, rest...); + return fold ([] (const polynomial p, const term &t) -> polynomial { + return p + t.derivative (); + }, polynomial {}, reverse (Terms)).normalize (); } } diff --git a/include/data/math/power.hpp b/include/data/math/power.hpp index d54bb58b..dea1ca82 100644 --- a/include/data/math/power.hpp +++ b/include/data/math/power.hpp @@ -6,6 +6,7 @@ #define DATA_MATH_POWER #include +#include namespace data::math { @@ -21,7 +22,9 @@ namespace data::math { template std::ostream inline &operator << (std::ostream &o, const power &p) { - return o << p.Base << " ^ " << p.Exponent; + o << p.Base; + if (p.Exponent != 1) o << " ^ " << p.Exponent; + return o; } template @@ -29,19 +32,19 @@ namespace data::math { static X square (X x) { return x * x; } - - static X power (X so_far, X pow_2n, N p) { - if (p == 0) return so_far; - division d = data::divide (p, 2); - return pow (d.Remainder == 1 ? so_far + pow_2n : so_far, square (pow_2n), d.Quotient); + + // p is at least 2 + static X step (X so_far, X pow_2n, N p) { + X next_step = p & 1 == 1 ? so_far * pow_2n : so_far; + N n = p >> 1; + if (n == 0) return next_step; + return step (next_step, square (pow_2n), n); } public: X operator () (X x, N n) const { - if (n == 0) return 1; - if (n == 1) return x; - if (n == 2) return square (x); - return power (0, x, n); + if (n == 0) return X {1}; + return step (X {1}, x, n); } }; @@ -49,7 +52,7 @@ namespace data::math { namespace data { template - X inline pow (X x, N n) { + X inline pow (const X &x, const N &n) { return math::pow {} (x, n); } } diff --git a/include/data/math/ring.hpp b/include/data/math/ring.hpp index 4dc7bebd..d0919dbe 100644 --- a/include/data/math/ring.hpp +++ b/include/data/math/ring.hpp @@ -16,6 +16,13 @@ namespace data::math { } && requires (const elem &a, elem &b) { {times {} (a, b)} -> std::convertible_to; }; + + template , typename times = times> + concept integral_domain = ring && requires () { + typename math::commutative; + } && requires (const nonzero &a, const nonzero &b) { + {times {} (a, b)} -> std::convertible_to>; + }; } diff --git a/include/data/tools.hpp b/include/data/tools.hpp index 3c7b4f0d..d8a49773 100644 --- a/include/data/tools.hpp +++ b/include/data/tools.hpp @@ -84,6 +84,22 @@ namespace data { return X.contains (k) ? X.remove (k).insert (k, v) : X; } + template + stack reverse (const ordered_list x) { + stack n; + for (const elem &e : x) n <<= e; + return n; + } + + template + ordered_list select (const ordered_list x, function satisfies) { + stack n; + for (const elem &e : x) if (satisfies (e)) n <<= e; + ordered_list r; + for (const elem &e : n) r = r.insert (e); + return r; + } + } #endif diff --git a/src/data/encoding/base58.cpp b/src/data/encoding/base58.cpp index d00f674c..ac753ce4 100644 --- a/src/data/encoding/base58.cpp +++ b/src/data/encoding/base58.cpp @@ -139,7 +139,7 @@ namespace data::encoding::base58 { int last = string::size () - 1; return math::division { string {std::string::substr (0, last)}, - static_cast (digit (std::string::operator[] (last)))}; + static_cast (digit (std::string::operator [] (last)))}; } math::division div = decode (*this)->divide (nat {static_cast (x)}); @@ -149,5 +149,5 @@ namespace data::encoding::base58 { string string::read (const std::string &x) { return encode (nat::read (x)); } - } + diff --git a/test/testAbs.cpp b/test/testAbs.cpp index b80d2353..664e2b61 100644 --- a/test/testAbs.cpp +++ b/test/testAbs.cpp @@ -107,6 +107,8 @@ namespace data { int_little<11>, uint_little<11>, Z_bytes_little, N_bytes_little, Z_bytes_big, N_bytes_big, + Z_bytes_twos_big, Z_bytes_twos_big, + Z_bytes_twos_little, Z_bytes_twos_little, dec_int, dec_uint, hex_int, hex_uint, hex_int_twos, hex_int_twos>; diff --git a/test/testDivision.cpp b/test/testDivision.cpp index 8455d5f6..17647a7c 100644 --- a/test/testDivision.cpp +++ b/test/testDivision.cpp @@ -9,16 +9,20 @@ namespace data { template void test_division_natural_case (const N &numerator, const N &denominator, const N "ient, const N &remainder) { - auto div = math::number::natural::divide (numerator, denominator); - EXPECT_EQ (div.Quotient, quotient); - EXPECT_EQ (div.Remainder, remainder); + auto div = divide (numerator, math::nonzero {denominator}); + EXPECT_EQ (div.Quotient, quotient) + << "expected " << numerator << " / " << denominator << " = " << quotient << " but got " << div.Quotient; + EXPECT_EQ (div.Remainder, remainder) + << "expected " << numerator << " % " << denominator << " = " << remainder << " but got " << div.Remainder; } template void test_division_integer_case (const Z &numerator, const Z &denominator, const Z "ient, const N &remainder) { - auto div = math::number::integer::divide (numerator, denominator); - EXPECT_EQ (div.Quotient, quotient); - EXPECT_EQ (div.Remainder, remainder); + auto div = divide (numerator, math::nonzero {denominator}); + EXPECT_EQ (div.Quotient, quotient) + << "expected " << numerator << " / " << denominator << " = " << quotient << " but got " << div.Quotient; + EXPECT_EQ (div.Remainder, remainder) + << "expected " << numerator << " % " << denominator << " = " << remainder << " but got " << div.Remainder; } template diff --git a/test/testFraction.cpp b/test/testFraction.cpp index 95330636..439d4ccd 100644 --- a/test/testFraction.cpp +++ b/test/testFraction.cpp @@ -7,43 +7,49 @@ namespace data { - template void test_divide_by_zero () {} + template void test_divide_by_zero () { + + } + template void test_lowest_terms () {} template void test_compare () {} template void test_arithmetic () {} - template void test_fraction () { - using Q = math::fraction; + template + struct test_fraction { + void operator () () { + using Q = math::fraction; - EXPECT_TRUE (Q {0}.valid ()); - EXPECT_TRUE (Q {1}.valid ()); - EXPECT_TRUE (Q {-1}.valid ()); + EXPECT_TRUE (Q {0}.valid ()); + EXPECT_TRUE (Q {1}.valid ()); + EXPECT_TRUE (Q {-1}.valid ()); - test_divide_by_zero (); - test_lowest_terms (); - test_compare (); - test_arithmetic (); - } + test_divide_by_zero (); + test_lowest_terms (); + test_compare (); + test_arithmetic (); + } + }; TEST (FractionTest, TestFraction) { - test_fraction (); - test_fraction (); - test_fraction (); - test_fraction (); - test_fraction (); - test_fraction (); - test_fraction> (); - test_fraction> (); - test_fraction> (); - test_fraction> (); - test_fraction> (); - test_fraction> (); - test_fraction> (); - test_fraction> (); - test_fraction (); - test_fraction (); - test_fraction (); + test_fraction {} (); + test_fraction {} (); + test_fraction {} (); + test_fraction {} (); + test_fraction {} (); + test_fraction {} (); + test_fraction> {} (); + test_fraction> {} (); + test_fraction> {} (); + test_fraction> {} (); + test_fraction> {} (); + test_fraction> {} (); + test_fraction> {} (); + test_fraction> {} (); + test_fraction {} (); + test_fraction {} (); + test_fraction {} (); } diff --git a/test/testPolynomial.cpp b/test/testPolynomial.cpp index 4ac1fd28..66cc8c20 100644 --- a/test/testPolynomial.cpp +++ b/test/testPolynomial.cpp @@ -2,30 +2,162 @@ // 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/polynomial.hpp" -#include "data/math/number/rational.hpp" +// note: if the ordering of these next two includes is reversed, +// the program breaks. This is quite fragile and it is due to +// using overloads of data::sign. This is very bad. +#include +#include + #include "gtest/gtest.h" -TEST(PolynomialTest, TestPolynomial) { - using namespace data; - - using polynomial = data::math::polynomial, uint32, 'x'>; - using term = polynomial::term; - - polynomial p1 = polynomial::make (Z {1}, term {Z {1}, 2}); - polynomial p2 = polynomial::make (Z {2}, term {Z {3}, 1}); - - polynomial expected_sum = polynomial::make (Z {3}, term {Z {3}, 1}, term {Z {1}, 2}); - polynomial expected_product = polynomial::make (Z {2}, term {Z {3}, 1}, term {Z {2}, 2}, term {Z {3}, 3}); - polynomial expected_composition = polynomial::make(Z {5}, term{Z {12}, 1}, term {Z {9}, 2}); - - EXPECT_FALSE (p1 == p2); - EXPECT_TRUE (p1 + p2 == expected_sum); - EXPECT_TRUE (p1 * p2 == expected_product); - EXPECT_TRUE (p1(p2) == expected_composition); - - // TODO polynomial long division +using namespace data; + +template +struct test_polynomial { + using poly = polynomial; + + poly X; + poly P1; + poly P2; + + test_polynomial () : + X {poly::var ()}, + P1 {(X ^ 2) + 1}, + P2 {X * 3 + 2} { + EXPECT_EQ (X.degree (), 1); + EXPECT_EQ (P1.degree (), 2); + EXPECT_EQ (P2.degree (), 1); + + EXPECT_FALSE (P1 == P2); + + EXPECT_EQ ((X ^ 3).degree (), 3); + + auto sum = P1 + P2; + auto product = P1 * P2; + auto comp_right = P1 (P2); + auto comp_left = P2 (P1); + + auto expected_sum = (X ^ 2u) + X * 3u + 3u; + auto expected_product = (X ^ 3u) * 3u + (X ^ 2u) * 2u + X * 3u + 2u; + auto expected_comp_right = (X ^ 2u) * 9u + X * 12u + 5u; + auto expected_comp_left = (X ^ 2u) * 3u + 5u; + + EXPECT_TRUE (sum == expected_sum); + EXPECT_TRUE (product == expected_product) << "expected " << P1 << " * " << P2 << " -> " << expected_product << " but got " << product; + EXPECT_TRUE (comp_right == expected_comp_right); + EXPECT_TRUE (comp_left == expected_comp_left); + + poly expected_d_p1 = X * 2; + poly expected_d_p2 = poly {3}; + auto expected_d_sum = X * 2 + 3; + auto expected_d_product = (X ^ 2u) * 9u + X * 4u + 3u; + auto expected_d_comp_right = X * 18u + 12; + auto expected_d_comp_left = X * 6u; + + EXPECT_TRUE (P1.derivative () == expected_d_p1); + EXPECT_TRUE (P2.derivative () == expected_d_p2); + EXPECT_TRUE (sum.derivative () == expected_d_sum); + EXPECT_TRUE (product.derivative () == expected_d_product); + EXPECT_TRUE (comp_right.derivative () == expected_d_comp_right); + EXPECT_TRUE (comp_left.derivative () == expected_d_comp_left); + + } + + void test_polynomial_division () { + auto expected_quotient = X * Q {1, 3} + Q {2, 9}; + auto expected_remainder = Q {13, 9}; + + auto d = math::divide {} (P1, math::nonzero {P2}); + EXPECT_EQ (d.Quotient, expected_quotient); + EXPECT_EQ (d.Remainder, expected_remainder); + } +}; + +template requires math::field> +struct test_polynomial_division : test_polynomial { + test_polynomial_division () : test_polynomial {} { + test_polynomial::test_polynomial_division (); + } +}; + +TEST (PolynomialTest, TestPolynomial) { + test_polynomial {}; + test_polynomial> {}; + test_polynomial> {}; + test_polynomial> {}; + test_polynomial> {}; + test_polynomial> {}; + test_polynomial> {}; + test_polynomial> {}; + test_polynomial> {}; + test_polynomial {}; + + test_polynomial {}; + test_polynomial {}; + test_polynomial {}; + test_polynomial {}; + test_polynomial {}; + test_polynomial {}; + test_polynomial {}; + + test_polynomial> {}; + test_polynomial>> {}; + test_polynomial>> {}; + test_polynomial>> {}; + test_polynomial>> {}; + test_polynomial>> {}; + test_polynomial>> {}; + test_polynomial>> {}; + test_polynomial>> {}; + + test_polynomial_division {}; + test_polynomial_division {}; + test_polynomial_division {}; + test_polynomial_division {}; + test_polynomial_division {}; + test_polynomial_division> {}; + test_polynomial_division> {}; + test_polynomial_division> {}; + + // can't get complex numbers yet for some reason. + // quaternions and octonions are not a field so they don't work because of that. + // However, they ought to work with the right concepts. + /* + test_polynomial {}; + test_polynomial {}; + test_polynomial {};*/ + /* + test_polynomial_division {}; + test_polynomial_division {}; + test_polynomial_division {};*/ + + // can't test these as fields because can't reliably subtract + // two numbers that ought to be equal to get zero. + + // there is also a problem with using weak_ordering instead of partial_ordering. + // floats use partial_ordering. There ought to be a way to figure out the correct + // ordering. + + /*test_polynomial {}; + test_polynomial {}; + test_polynomial {}; + test_polynomial {}; + test_polynomial {}; + test_polynomial {}; + test_polynomial {}; + test_polynomial {};*/ + + // should be able to do finite fields eventually. + +/* + test_polynomial_division>; + test_polynomial_division>; + test_polynomial_division>; + test_polynomial_division>; + test_polynomial_division>; + test_polynomial_division>; + test_polynomial_division>; + test_polynomial_division>;*/ } diff --git a/test/testStringNumbers.cpp b/test/testStringNumbers.cpp index 28e26555..63426b3d 100644 --- a/test/testStringNumbers.cpp +++ b/test/testStringNumbers.cpp @@ -190,4 +190,30 @@ namespace data::encoding { EXPECT_EQ (base58_uint {num}.divide (57), b58_expected_57); } + + TEST (StringNumbersTest, TestConvertStringNumbers) { + EXPECT_EQ (N (dec_uint {1145}), N (1145)); + EXPECT_EQ (N (dec_uint {916}), N (916)); + EXPECT_EQ (N (dec_uint {229}), N (229)); + + EXPECT_EQ (Z (dec_int {1145}), Z (1145)); + EXPECT_EQ (Z (dec_int {916}), Z (916)); + EXPECT_EQ (Z (dec_int {229}), Z (229)); + + EXPECT_EQ (N (base58_uint {1145}), N (1145)); + EXPECT_EQ (N (base58_uint {916}), N (916)); + EXPECT_EQ (N (base58_uint {229}), N (229)); + + EXPECT_EQ (N (hex_uint {1145}), N (1145)); + EXPECT_EQ (N (hex_uint {916}), N (916)); + EXPECT_EQ (N (hex_uint {229}), N (229)); + + EXPECT_EQ (Z (hex_int {1145}), Z (1145)); + EXPECT_EQ (Z (hex_int {916}), Z (916)); + EXPECT_EQ (Z (hex_int {229}), Z (229)); + + EXPECT_EQ (Z (hex_int_twos {1145}), Z (1145)); + EXPECT_EQ (Z (hex_int_twos {916}), Z (916)); + EXPECT_EQ (Z (hex_int_twos {229}), Z (229)); + } } diff --git a/test/testZBytes.cpp b/test/testZBytes.cpp index 69f4a5ca..321bbfba 100644 --- a/test/testZBytes.cpp +++ b/test/testZBytes.cpp @@ -233,12 +233,34 @@ namespace data { Z_Bytes_to_Z (0); Z_Bytes_to_Z (1); Z_Bytes_to_Z (3); + Z_Bytes_to_Z (229); Z_Bytes_to_Z (767); + Z_Bytes_to_Z (916); + Z_Bytes_to_Z (1145); Z_Bytes_to_Z ("0x0f00000a00aabbccddeeffffffffffffffff"); Z_Bytes_to_Z ("0xf000000a00aabbccddeeffffffffffffffff"); } + TEST (ZBytesTest, TestZBytesOnesAndTwos) { + + EXPECT_EQ (Z_bytes_big (Z_bytes_twos_big (Z_bytes_big {1145})), Z_bytes_big {1145}); + EXPECT_EQ (Z_bytes_big (Z_bytes_twos_big (Z_bytes_big {916})), Z_bytes_big {916}); + EXPECT_EQ (Z_bytes_big (Z_bytes_twos_big (Z_bytes_big {229})), Z_bytes_big {229}); + + EXPECT_EQ (Z_bytes_little (Z_bytes_twos_little (Z_bytes_little {1145})), Z_bytes_little {1145}); + EXPECT_EQ (Z_bytes_little (Z_bytes_twos_little (Z_bytes_little {916})), Z_bytes_little {916}); + EXPECT_EQ (Z_bytes_little (Z_bytes_twos_little (Z_bytes_little {229})), Z_bytes_little {229}); + + EXPECT_EQ (Z_bytes_twos_big (Z_bytes_big (Z_bytes_twos_big {1145})), Z_bytes_twos_big {1145}); + EXPECT_EQ (Z_bytes_twos_big (Z_bytes_big (Z_bytes_twos_big {916})), Z_bytes_twos_big {916}); + EXPECT_EQ (Z_bytes_twos_big (Z_bytes_big (Z_bytes_twos_big {229})), Z_bytes_twos_big {229}); + + EXPECT_EQ (Z_bytes_twos_little (Z_bytes_little (Z_bytes_twos_little {1145})), Z_bytes_twos_little {1145}); + EXPECT_EQ (Z_bytes_twos_little (Z_bytes_little (Z_bytes_twos_little {916})), Z_bytes_twos_little {916}); + EXPECT_EQ (Z_bytes_twos_little (Z_bytes_little (Z_bytes_twos_little {229})), Z_bytes_twos_little {229}); + } + TEST (ZBytesTest, TestZBytesZero) { list ones_zeros {"0", "0x", "0x00", "0x0000"}; list twos_zeros {"0", "0x", "0x00", "0x0000", "0x80", "0x8000"};