Boost logo

Boost :

From: Guillaume Melquiond (gmelquio_at_[hidden])
Date: 2002-09-08 03:21:35


On Sun, 8 Sep 2002, Joerg Walter wrote:

> > IMHO, the issue is more about the usefulness of the implicit type
> > conversion in the scope of interval arithmetic, compared to the
> > interface complication.
>
> Are you talking about a possible interface complication when using
> promote_traits? If yes, then I'm not sure how such an interface change would
> be visible for a user (apart from the fact, that he could use mixed
> precision operations then ;-).

When we designed the library, we didn't even think about mixed operations.
Indeed, we didn't find a nice way of doing interval conversions, so we
didn't get any further in the handling of intervals with different base
types.

So, here is the problem: we need to convert 'interval<T1, P1>' to
'interval<T2, P2>'. If all elements of T1 are exactly representable by
elements of T2, there is no problem: a cast is enough. But what if an
element of T1 can't be represented? We need to convert it and respect the
inclusion property of interval arithmetic.

Somebody could probably object that with 'promote_traits', we always are
in the first case if 'promote_traits' is correctly built. But, in my
opinion, if an interval can never get back to a less precise type, all the
mixed operations stuff is useless. I'm not sure to clearly explain what I
mean; I will say it another way: if all the operations (being mixed or
not) produce 'interval<double>' thanks to 'promote_traits', what's the
point of having mixed operations able to handle 'interval<float>' since,
after a few operations, only 'interval<double>' will remain.

I hope I was able to explain we wanted to do conversions in the two
directions. And here come the interface complications. Where can we put
these conversions?

First idea, to define them globally by something like:

  template<class Src, class Dest>
  struct conversion {
    Dest convert_up (const Src&);
    Dest convert_down(const Src&);
  };

But now, it will conflict with the 'Rounding' policy of the interval class
which is supposed to handle all the dirty work (aka handling the
computation on the base type). So this is clearly not a solution.

So, since 'Rounding' is here to handle this kind of stuff, why doesn't
this policy do it? We could just add:

  struct my_rounding {
    ... // all the previous stuff
    template<class Dest> Dest convert_up (const T&);
    template<class Dest> Dest convert_down(const T&);
  };

That's a solution. Another solution would be to have the conversion the
other way around: 'template<class Src> T convert_...(const Src&);'. But
these solutions suffer from the same drawback: when an user wants to add a
new conversion to an existing policy, it's suddenly become less trivial
(in my opinion).

If the library was only meant to be used with float, double and long
double (following the example of std::complex), we would have added such
conversions. But because we wanted to be able to use it with a lot more
type (rational, multi-precision numbers, etc), we didn't do it.

Maybe there is a nice way to handle all of this, but unfortunately, it
didn't occur to us.

Regards,

Guillaume

PS: I'm not doing a kind of systematic opposition on this subject. It's
true that we didn't think about mixed operations; but we really wanted to
be able to do safe conversions from one interval type to another, and we
unfortunately didn't find a way to do it.


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