Boost logo

Boost :

From: Jan Langer (jan_at_[hidden])
Date: 2004-01-17 10:21:10


Deane Yang wrote:
>>> Is there an intent for any of these proposed dimensional and unit
>>> libraries to restrict the types of operations being performed
>>> according to
>>> the scale of measurement that the unit belongs to? e.g. 10 kelvins / 5
>>> kelvins gives 2 kelvins, but 10 degrees Celsius / 5 degrees Celsius
>>> gives
>>> not only 2 degrees Celsius but also a compiler warning? :-) (An error
>>> would be too severe -- it's pretty common for social scientists to take
>>> means of ordinal data.)
>
> As I've mentioned before, one simply needs to distinguish between
> absolute temperature measurements (even in kelvins) and
> relative temperature measurements (representing the difference between
> two absolute temperatures).
>
> Why even in kelvins? Two reasons:
> 1) For temperature differences, degrees Celsius should be regarded
> as being identical to degrees Kelvin
> 2) Temperature differences in degrees Kelvin are allowed to be negative.
> Absolute temperature in degrees Kelvin is not.

i still think this issue should not be dealt with by means of the core
dimensions lib. so i typed a little class which should be able to
restrict the operations allowed on absolute and relative values.

since all operations are allowed on relative types, there is imho no
need of a distinct type for them.

normally something like this could be plugged into the dimensions lib
and everything could work as expected:

   typedef ... kelvin;
   absolute <kelvin> freezing_point (273.15);
   absolute <kelvin> boiling_point = freezing_point + 100 * kelvin;
   kelvin temp_diff = boiling_point - freezing_point;

   freezing_point + boiling_point; // error

a similar approach should imho be followed to support the affine and
non-linear measures.

jan

-- 
jan langer ... jan_at_[hidden]
"pi ist genau drei"

#include <cassert>

template <typename T>
class absolute
{
  T value_;

public:
  typedef T value_type;

  absolute () : value_ (T ()) {}

  template <typename S>
  explicit absolute (S const &s)
    : value_ (s) {}
  
  template <typename S>
  absolute (absolute <S> const &a)
    : value_ (a.value ()) {}

  template <typename S>
  absolute &operator = (absolute <S> const &a)
  {
    value_ = a.value ();
    return *this;
  }

#define ARITH_ASSIGN_OP(SYMBOL) \
  template <typename S> \
  absolute &operator SYMBOL##= (S const &s) \
  { \
    value_ SYMBOL##= s; \
    return *this; \
  }
  ARITH_ASSIGN_OP(+)
  ARITH_ASSIGN_OP(-)
  ARITH_ASSIGN_OP(*)
  ARITH_ASSIGN_OP(/)
#undef ARITH_ASSIGN_OP

  absolute &operator ++ ()
  {
    ++value_;
    return *this;
  }
  absolute operator ++ (int)
  {
    absolute tmp (*this);
    ++*this;
    return tmp;
  }
  
  absolute &operator -- ()
  {
    --value_;
    return *this;
  }
  absolute operator -- (int)
  {
    absolute tmp (*this);
    --*this;
    return tmp;
  }

  T value () const
  { return value_; }
};

template <typename T>
absolute <T> make_absolute (T const &t)
{
  return absolute <T> (t);
}

#define COMPARE_OP(SYMBOL) \
template <typename T, typename S> \
bool operator SYMBOL (absolute <T> const &a1, absolute <S> const &a2) \
{ \
  return a1.value () SYMBOL a2.value (); \
}
COMPARE_OP(==)
COMPARE_OP(!=)
COMPARE_OP(>=)
COMPARE_OP(<=)
COMPARE_OP(>)
COMPARE_OP(<)
#undef COMPARE_OP

// the return type of the following operators
// actually needs to
// return typeof (T () SYMBOL S ())
// or something similar

#define ARITH_LEFT_OP(SYMBOL) \
template <typename T, typename S> \
absolute <T> \
operator SYMBOL (absolute <T> const &a1, S const &s2) \
{ \
  return make_absolute (a1.value () SYMBOL s2); \
}
#define ARITH_RIGHT_OP(SYMBOL) \
template <typename T, typename S> \
absolute <S> \
operator SYMBOL (T const &t1, absolute <S> const &a2) \
{ \
  return make_absolute (t1 SYMBOL a2.value ()); \
}
#define ARITH_BOTH_OP(SYMBOL) \
template <typename T, typename S> \
T \
operator SYMBOL (absolute <T> const &a1, absolute <S> const &a2) \
{ \
  return a1.value () SYMBOL a2.value (); \
}
ARITH_LEFT_OP(+)
ARITH_RIGHT_OP(+)
ARITH_LEFT_OP(-)
ARITH_BOTH_OP(-)
ARITH_LEFT_OP(*)
ARITH_RIGHT_OP(*)
ARITH_LEFT_OP(/)
ARITH_BOTH_OP(/)
#undef ARITH_LEFT_OP
#undef ARITH_RIGHT_OP
#undef ARITH_BOTH_OP

template <typename T, typename S>
T
operator % (absolute <T> const &a1, S const &s2)
{
  return a1.value () % s2;
}
 
int main ()
{
  absolute <double> const C0 (0);
  absolute <double> const C1 (1);
  absolute <double> const C4 (4);
  absolute <double> const C5 (5);
  absolute <double> const C20 (20);

  assert (make_absolute (20) == C20);
  
  assert (C4 + 16 == C20);
  assert (16 + C4 == C20);
  
  assert (C20 - 16 == C4);
  assert (C20 - C4 == 16);

  assert (C4 * 5 == C20);
  assert (5 * C4 == C20);

  assert (C20 / 5 == C4);
  assert (C20 / C4 == 5);

  assert (C20 % 5 == 0);

  assert (C0 != C20);
  assert (C0 <= C20);
  assert (C20 <= C20);
  assert (C0 < C20);
  assert (C20 >= C0);
  assert (C20 >= C20);
  assert (C20 > C0);

  absolute <double> c = C4;
  
  assert (c == C4);
  assert (++c == C5);
  assert (c == C5);
  assert (--c == C4);
  assert (c == C4);
  assert (c++ == C4);
  assert (c == C5);
  assert (c-- == C5);
  assert (c == C4);

  // iterator over range
  double i = 0;
  for (absolute <double> c = C0; c <= C20; ++c, ++i)
    assert (c.value () == i);

  // take mean
  {
    absolute <double> s = C0;
    
    for (absolute <double> c = C1; c <= C5; ++c)
      s += c - C0;
    s /= C5 - C1 + 1;
    assert (s == make_absolute (3));
  }

  assert (C20.value () == 20);
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk