
* mln/value/intsub.hh: Improve class. * tests/value/intsub.cc: Add more tests. --- milena/ChangeLog | 8 + milena/mln/value/intsub.hh | 399 +++++++++++++++++------------------------- milena/tests/value/intsub.cc | 31 ++++ 3 files changed, 204 insertions(+), 234 deletions(-) diff --git a/milena/ChangeLog b/milena/ChangeLog index b7e9506..c9a02a4 100644 --- a/milena/ChangeLog +++ b/milena/ChangeLog @@ -1,5 +1,13 @@ 2012-10-04 Guillaume Lazzara <z@lrde.epita.fr> + Improve value::intsub class. + + * mln/value/intsub.hh: Improve class. + + * tests/value/intsub.cc: Add more tests. + +2012-10-04 Guillaume Lazzara <z@lrde.epita.fr> + * mln/value/builtin/ops.hh: Handle all the comparison operators. 2012-10-04 Guillaume Lazzara <z@lrde.epita.fr> diff --git a/milena/mln/value/intsub.hh b/milena/mln/value/intsub.hh index fc269a8..897215c 100644 --- a/milena/mln/value/intsub.hh +++ b/milena/mln/value/intsub.hh @@ -33,10 +33,12 @@ # include <cstdlib> # include <iostream> # include <sstream> +# include <algorithm> +# include <mln/core/routine/ops.hh> +# include <mln/value/ops.hh> +# include <mln/value/builtin/ops.hh> # include <mln/value/internal/value_like.hh> -# include <mln/value/internal/encoding.hh> -# include <mln/value/internal/limits.hh> -# include <mln/value/concept/integer.hh> +# include <mln/value/concept/floating.hh> # include <mln/value/iota.hh> # include <mln/value/prev.hh> # include <mln/value/succ.hh> @@ -65,13 +67,13 @@ namespace mln { private: typedef mln::value::intsub<n> self_; - typedef typename mln::value::internal::encoding_signed_<32>::ret enc_; + typedef int enc_; public: enum constants_ { dim = 1, nbits = 32, - card = mln_value_card_from_(32/n) // FIXME: Really? + card = mln_value_card_from_(32) / n }; typedef trait::value::nature::integer nature; @@ -103,12 +105,12 @@ namespace mln { template <unsigned n> - class intsub - : public Integer< intsub<n> >, - public internal::value_like_< int, // Equivalent. - typename internal::encoding_signed_<32>::ret, // Enc. - int, // Interoperation. - intsub<n> > // Exact. + class intsub : + public value::Floating< intsub<n> >, + public value::internal::value_like_< float, // Equivalent. + int, // Enc. + float, // Interoperation. + intsub<n> > // Exact. { public: intsub(); @@ -116,9 +118,13 @@ namespace mln /// Construct an intsub with value : \p int_part + 1 / \p denominator. intsub(int int_part, unsigned denominator); intsub(int i); + intsub(float i); + intsub(double i); intsub<n>& operator=(const intsub<n>& rhs); intsub<n>& operator=(int i); + intsub<n>& operator=(float i); + intsub<n>& operator=(double i); /// Is an integer value. bool is_integer() const; @@ -143,92 +149,61 @@ namespace mln /*!\internal Construct a intsub using an encoding value. */ static intsub<n> make_from_enc_(int enc); + /// Conversion to a float. + operator float() const; + /// Unary operator minus. intsub<n> operator-() const; + /// Explicit conversion towards equivalent type. + float to_equiv() const; + + /// Explicit conversion towards interoperation type. + float to_interop() const; }; // Safety template <> struct intsub<0>; -// rounding + // rounding + /// Re-implementation of the floor function. \sa math::floor template <unsigned n> - intsub<n> floor(const intsub<n>& i); + intsub<n> floor_(const intsub<n>& i); + /// Re-implementation of the ceil function. \sa math::ceil template <unsigned n> - intsub<n> ceil(const intsub<n>& i); - + intsub<n> ceil_(const intsub<n>& i); -// comparison + // Other ops (overloads of generic ones) + /// Re-implementation of the min function. \sa math::min template <unsigned n> - bool operator==(const intsub<n>& l, const intsub<n>& r); - template <unsigned n, typename V> - bool operator==(const intsub<n>& l, const V& r); - template <unsigned n> - bool operator<=(const intsub<n>& l, const intsub<n>& r); - template <unsigned n> - bool operator!=(const intsub<n>& l, const intsub<n>& r); + intsub<n> min_(const intsub<n>& u1, const intsub<n>& u2); + /// Re-implementation of the max function. \sa math::max template <unsigned n> - bool operator>=(const intsub<n>& l, const intsub<n>& r); - template <unsigned n> - bool operator>(const intsub<n>& l, const intsub<n>& r); - template <unsigned n> - bool operator<(const intsub<n>& l, const intsub<n>& r); - -// arithmetics + intsub<n> max_(const intsub<n>& u1, const intsub<n>& u2); + /// Specific implementation of the mean function. template <unsigned n> - intsub<n> operator+(const intsub<n>& l, const intsub<n>& r); - template <unsigned n, typename O> - intsub<n> operator+(const intsub<n>& l, const O& r); - template <typename O, unsigned n> - intsub<n> operator+(const O& r, const intsub<n>& l); - template <unsigned n> - void operator+=(intsub<n>& l, const intsub<n>& r); - template <unsigned n, typename O> - void operator+=(intsub<n>& l, const O& r); + intsub<2*n> mean(const intsub<n>& v1, const intsub<n>& v2); + /// Specific implementation of the mean function. template <unsigned n> - intsub<n> operator-(const intsub<n>& l, const intsub<n>& r); - template <unsigned n, typename O> - intsub<n> operator-(const intsub<n>& l, const O& r); - template <typename O, unsigned n> - intsub<n> operator-(const O& r, const intsub<n>& l); - template <unsigned n> - void operator-=(intsub<n>& l, const intsub<n>& r); - template <unsigned n, typename O> - void operator-=(intsub<n>& l, const O& r); + intsub<4*n> mean(const intsub<n>& v1, const intsub<n>& v2, + const intsub<n>& v3, const intsub<n>& v4); + /// Specific implementation of the median function. template <unsigned n> - intsub<n> operator*(const intsub<n>& l, const intsub<n>& r); - template <unsigned n, typename O> - intsub<n> operator*(const intsub<n>& l, const O& r); - template <typename O, unsigned n> - intsub<n> operator*(const O& r, const intsub<n>& l); - template <unsigned n> - void operator*=(intsub<n>& l, const intsub<n>& r); - template <unsigned n, typename O> - void operator*=(intsub<n>& l, const O& r); - -// other ops + intsub<2*n> median(const intsub<n>& v1, const intsub<n>& v2); + /// Specific implementation of the median function. template <unsigned n> - intsub<n> min(const intsub<n>& u1, const intsub<n>& u2); - template <unsigned n> - intsub<n> max(const intsub<n>& u1, const intsub<n>& u2); - template <unsigned n> - intsub<n> mean(const intsub<n>& v1, const intsub<n>& v2); - template <unsigned n> - intsub<n> mean(const intsub<n>& v1, const intsub<n>& v2, - const intsub<n>& v3, const intsub<n>& v4); + intsub<4*n> median(const intsub<n>& v1, const intsub<n>& v2, + const intsub<n>& v3, const intsub<n>& v4); -// << - template <unsigned n> - std::ostream& - operator<<(std::ostream& ostr, const intsub<n>& i); + // Iota template <unsigned n> struct iota<intsub<n> > @@ -236,6 +211,11 @@ namespace mln static intsub<n> value(); }; + typedef intsub<1> intsub1; + typedef intsub<2> intsub2; + typedef intsub<4> intsub4; + + } // end of namespace mln::value extern const value::intsub<2> half; @@ -243,7 +223,6 @@ namespace mln # ifndef MLN_INCLUDE_ONLY - // half # ifndef MLN_WO_GLOBAL_VARS @@ -258,6 +237,27 @@ namespace mln namespace value { + namespace internal + { + + /// \internal Test if (f * v) is an integer; an error less than + /// epsilon is ok + bool + mult_is_integer(float f, int v) + { + float a = f * v; + float b = float(unsigned(a)); + const float epsilon = 0.00001f; + + if (a > b) + return a - b < epsilon; + else + return b - a < epsilon; + } + + } // end of namespace mln::value::internal + + template <unsigned n> intsub<n>::intsub() { @@ -276,12 +276,24 @@ namespace mln } template <unsigned n> - intsub<n>::intsub(int int_part, unsigned denominator) + intsub<n>::intsub(float i) { - // FIXME: better error handling ? - if (denominator > n) - std::abort(); + mln_precondition(internal::mult_is_integer(i, n)); + this->v_ = n * i; + } + template <unsigned n> + intsub<n>::intsub(double i) + { + mln_precondition(internal::mult_is_integer(i, n)); + this->v_ = n * i; + } + + + template <unsigned n> + intsub<n>::intsub(int int_part, unsigned denominator) + { + mln_precondition(denominator <= n); this->v_ = int_part * n + denominator / n; } @@ -303,6 +315,25 @@ namespace mln } template <unsigned n> + intsub<n>& + intsub<n>::operator=(float i) + { + mln_precondition(internal::mult_is_integer(i, n)); + this->v_ = n * i; + return *this; + } + + template <unsigned n> + intsub<n>& + intsub<n>::operator=(double i) + { + mln_precondition(internal::mult_is_integer(i, n)); + this->v_ = n * i; + return *this; + } + + + template <unsigned n> intsub<n> intsub<n>::make_from_enc_(int enc) { intsub<n> i; @@ -321,10 +352,8 @@ namespace mln template <unsigned m> intsub<n>::operator intsub<m>() { - // FIXME: better error handling ? - if (n > m) - std::abort(); - return intsub<m>::make_from_enc_(this->v_ * (m / n)); + mln_precondition(n <= m); + return intsub<m>::make_from_enc_(this->v_ * m / n); } template <unsigned n> @@ -349,215 +378,117 @@ namespace mln } template <unsigned n> - intsub<n> - intsub<n>::operator-() const + intsub<n>::operator float() const { - return intsub<n>::make_from_enc_(this->v_ * -1); + return to_equiv(); } - // Iota template <unsigned n> intsub<n> - iota<intsub<n> >::value() - { - return intsub<n>(0,n); - } - - -// rounding - - - template <unsigned n> - intsub<n> floor(const intsub<n>& i) - { - return i.is_integer() ? i : value::prev(i); - } - - template <unsigned n> - intsub<n> ceil(const intsub<n>& i) - { - return i.is_integer() ? i : value::succ(i); - } - - - -// comparison - - template <unsigned n> - bool operator==(const intsub<n>& l, const intsub<n>& r) - { - return l.to_enc() == r.to_enc(); - } - - template <unsigned n> - bool operator==(const intsub<n>& l, const int& r) - { - return l == intsub<n>(r); - } - - template <unsigned n> - bool operator<=(const intsub<n>& l, const intsub<n>& r) - { - return l.to_enc() <= r.to_enc(); - } - - template <unsigned n> - bool operator!=(const intsub<n>& l, const intsub<n>& r) - { - return ! (l == r); - } - - template <unsigned n> - bool operator>=(const intsub<n>& l, const intsub<n>& r) - { - return r <= l; - } - - template <unsigned n> - bool operator>(const intsub<n>& l, const intsub<n>& r) - { - return ! (l <= r); - } - - template <unsigned n> - bool operator<(const intsub<n>& l, const intsub<n>& r) - { - return r > l; - } - - -// arithmetics - - template <unsigned n> - intsub<n> operator+(const intsub<n>& l, const intsub<n>& r) - { - return intsub<n>::make_from_enc_(l.to_enc() + r.to_enc()); - } - - template <unsigned n> - intsub<n> operator+(const intsub<n>& l, int r) - { - return l + intsub<n>(r); - } - - template <unsigned n> - intsub<n> operator+(int l, const intsub<n>& r) - { - return r + l; - } - - template <unsigned n> - void operator+=(intsub<n>& l, const intsub<n>& r) + intsub<n>::operator-() const { - l = l + r; + return intsub<n>::make_from_enc_(this->v_ * -1); } template <unsigned n> - void operator+=(intsub<n>& l, int r) + float + intsub<n>::to_equiv() const { - l = l + intsub<n>(r); + return float(this->v_) / float(n); } template <unsigned n> - intsub<n> operator-(const intsub<n>& l, const intsub<n>& r) + float + intsub<n>::to_interop() const { - return intsub<n>::make_from_enc_(l.to_enc() - r.to_enc()); + return float(this->v_) / float(n); } - template <unsigned n> - intsub<n> operator-(const intsub<n>& l, int r) - { - return l - intsub<n>(r); - } + // Iota template <unsigned n> - intsub<n> operator-(int l, const intsub<n>& r) + intsub<n> + iota<intsub<n> >::value() { - return - r + l; + return intsub<n>(0,n); } - template <unsigned n> - void operator-=(intsub<n>& l, const intsub<n>& r) - { - l = l - r; - } - template <unsigned n> - void operator-=(intsub<n>& l, int r) - { - l = l - intsub<n>(r); - } + // rounding template <unsigned n> - intsub<n> operator*(const intsub<n>& l, const intsub<n>& r) + intsub<n> floor_(const intsub<n>& i) { - return intsub<n>::make_from_enc_(l.to_enc() * r.to_enc() / n); + return i.is_integer() ? i : value::prev(i); } template <unsigned n> - intsub<n> operator*(const intsub<n>& l, int r) + intsub<n> ceil_(const intsub<n>& i) { - return l * intsub<n>(r); + return i.is_integer() ? i : value::succ(i); } - template <unsigned n> - intsub<n> operator*(int l, const intsub<n>& r) - { - return r * l; - } - template <unsigned n> - void operator*=(intsub<n>& l, const intsub<n>& r) - { - l = l * r; - } + // Other operators (overloads of generic ones) template <unsigned n> - void operator*=(intsub<n>& l, int r) + intsub<n> min_(const intsub<n>& v1, const intsub<n>& v2) { - l = l * intsub<n>(r); + return intsub<n>::make_from_enc_(v1.to_enc() < v2.to_enc() ? v1.to_enc() : v2.to_enc()); } - -// other ops - template <unsigned n> - intsub<n> min(const intsub<n>& v1, const intsub<n>& v2) + intsub<n> max_(const intsub<n>& v1, const intsub<n>& v2) { - return intsub<n>::make_from_enc_(v1.to_enc() < v2.to_enc() ? v1.to_enc() : v2.to_enc()); + return intsub<n>::make_from_enc_(v1.to_enc() > v2.to_enc() ? v1.to_enc() : v2.to_enc()); } + // FIXME: Make use of mean_() overloads with math::mean. Require + // to fix an issue with the return type which differs according to + // the overload : with 2 (intsub<2*n>) or 4 (intsub<4*n>) + // arguments. template <unsigned n> - intsub<n> max(const intsub<n>& v1, const intsub<n>& v2) + intsub<2*n> mean(const intsub<n>& v1, const intsub<n>& v2) { - return intsub<n>::make_from_enc_(v1.to_enc() > v2.to_enc() ? v1.to_enc() : v2.to_enc()); + return intsub<2*n>::make_from_enc_((v1.to_enc() + v2.to_enc())); } + // FIXME: Make use of mean_() overloads with math::mean. Require + // to fix an issue with the return type which differs according to + // the overload : with 2 (intsub<2*n>) or 4 (intsub<4*n>) + // arguments. template <unsigned n> - intsub<n> mean(const intsub<n>& v1, const intsub<n>& v2) + intsub<4*n> mean(const intsub<n>& v1, const intsub<n>& v2, + const intsub<n>& v3, const intsub<n>& v4) { - return intsub<n>::make_from_enc_((v1.to_enc() + v2.to_enc()) / 2); + return mean_(mean_(v1, v2), mean_(v3, v4)); } + // FIXME: Make use of median_() overloads with + // math::median. Require to fix an issue with the return type + // which differs according to the overload : with 2 (intsub<2*n>) + // or 4 (intsub<4*n>) arguments. template <unsigned n> - intsub<n> mean(const intsub<n>& v1, const intsub<n>& v2, - const intsub<n>& v3, const intsub<n>& v4) + intsub<2*n> median(const intsub<n>& v1, const intsub<n>& v2) { - return intsub<n>::make_from_enc_((v1.to_enc() + v2.to_enc() - + v3.to_enc() + v4.to_enc()) / 4); + return mean(v1, v2); } - -// << - + // FIXME: Make use of median_() overloads with + // math::median. Require to fix an issue with the return type + // which differs according to the overload : with 2 (intsub<2*n>) + // or 4 (intsub<4*n>) arguments. template <unsigned n> - std::ostream& - operator<<(std::ostream& ostr, const intsub<n>& i) + intsub<4*n> median(const intsub<n>& v1, const intsub<n>& v2, + const intsub<n>& v3, const intsub<n>& v4) { - if (i.is_integer()) - return ostr << i.to_int(); - else - return ostr << floor(i).to_int() << ".5"; + std::vector<intsub<n> > vec(4); + vec.push_back(v1); + vec.push_back(v2); + vec.push_back(v3); + vec.push_back(v4); + std::sort(vec.begin(), vec.end()); + return mean(vec[1], vec[2]); } # endif // ! MLN_INCLUDE_ONLY diff --git a/milena/tests/value/intsub.cc b/milena/tests/value/intsub.cc index e324fe3..82a87fb 100644 --- a/milena/tests/value/intsub.cc +++ b/milena/tests/value/intsub.cc @@ -26,12 +26,16 @@ /// \file #include <cassert> +#include <mln/math/mean.hh> #include <mln/value/intsub.hh> #include <mln/value/inc.hh> #include <mln/value/dec.hh> #include <mln/value/succ.hh> #include <mln/value/prev.hh> #include <mln/math/mean.hh> +#include <mln/math/min.hh> +#include <mln/math/ceil.hh> +#include <mln/math/floor.hh> int main() { @@ -48,6 +52,10 @@ int main() // (2.5 + 0.5) / 2 == 1.5 mln_assertion(mean(i, half) == 1 + half); + // (2.5 + 2) / 2 = 2.25 + intsub<4> res = mean(i, intsub<2>(2)); + mln_assertion(res == 2.25); + // i == 3 inc(i); mln_assertion(i == intsub<2>(3)); @@ -75,4 +83,27 @@ int main() inc(j); mln_assertion(j == 6 + quarter); + // k = 10.25 + intsub<8> k(10.25); + mln_assertion(k == 10 + quarter); + + // sum(j,k,2) == 18.5 + mln_assertion(j + k + 2 == 18.5); + + // min(i,l) == 2.5 + intsub<2> l(2.5); + mln_assertion(mln::math::min(i, l) == 2.5); + + // mean(6,2,2.5,3) = 3.375 + mln_assertion(mean(i, intsub<2>(2), l, intsub<2>(3)) == 3.375); + + // ceil(2.5) + mln_assertion(math::ceil(l) == 3); + mln_assertion(math::floor(l) == 2); + + // median(6,2,2.5,3) = 2.75 + mln_assertion(median(i, intsub<2>(2), l, intsub<2>(3)) == 2.75); + + // median(6,2) = 4 + mln_assertion(median(i, intsub<2>(2)) == 4); } -- 1.7.2.5