* 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 1a5f831..3d191ab 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,13 @@
2012-10-04 Guillaume Lazzara <z(a)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(a)lrde.epita.fr>
+
* mln/value/builtin/ops.hh: Handle all the comparison operators.
2012-10-04 Guillaume Lazzara <z(a)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