
Andras Erdei wrote: I'm sorry I haven't got around to looking at your code yet. I've been swamped with other stuff -- but that's not a good excuse to have put it off this long.
i've started to work on the variants that were brought up in a previous discussion about boost::rational<>
the current code can be found at www.ccg.hu/pub/src/rat
atm it is only for getting the calculations right, so no templates, optimizations, boostification, nice interface etc, and i only tested it with MSVC 7.1
there is also no implementation yet geared towards an unlimited precision representation
the variants are:
- legacy boost (no rounding, silently gives wrong results) - exceptions are thrown if the result overflows or cannot be represented - rounding - rounding & maintaining an exactness indicator
is there anything missing from the list?
We might want to allow different rounding policies. Also, we might want assertion failures instead of exceptions.
there is also a simple test-bed, it runs the four basic operations 10000 times on random inputs, and collects some statistics:
addition and substraction overflowed 0 times, and the result was exactly representable 44 times; the average error of the legacy code is 475%, and of the rounding code is 0.005% (the exception-throwing variant throws, so there is no error figure for that)
The "legacy" code doesn't do too well. Before I was insisting that the current behavior be the default, for backward compatibility. Now I'm open to changing the default behavior, depending on what we can discover about how rational is actually being used.
multiplication and division overflowed once, and the result was exactly representable 79 times; the average error of the legacy code is 2025%, and of the rounding code is 0.01%
it would be nice to get some advice on how the final interface should look like (and of course regarding everything else, including whether there is a point to continue the work):
Definitely it is worthwhile.
- any ideas for naming the variants?
- how should the parameters of rational<> look like?
The most obvious signature would be template< typename Elem, typename Rounding = use_default, typename Checking = use_default > class rational; However, it may be that if we want to avoid sticking all the arithmetic calulations in policy member functions, the only reasonable rounding policy is the one you suggested before. In that case it would just look like template<typename Elem, typename Checking = use_default> class rational;
my favourite would be rational<prec,method> where prec is the maximum absolute value allowed for numerators and denominators, and method is one of the variants from above, e.g. rational<10000,round> would be a rounding rational with four decimal digits for the numerator and denominator.
I don't like this. Shouldn't rational<Elem> make sense for any type Elem for which the Euclidean algorithm makes sense? I think you can get the effect of restricting the absolute value of the numerator and denominator by passing user defined types as Elem. Using a little metaprogramming rational<> could be made to use int in signatures of member functions such as numerator() and denominator(). Something like template<int Max> struct restricted_int { typedef int element_type; restricted_int(int); opertator int() const; ... }; Then you could get the effect you were describing by using rational< restricted_int<1000>, ...> If this seems akward, a restrcted_rational could be built as a thin layer on top off rational. It could even be generalized by allowing the underlying type to vary. ps: i have tried to search the archive for past discussions about
rational<> to avoid repeating old stuff, but with very limited success (only the latest posts seem to be accessible) -- any hints?
Searching my local archives I get lots of messages, going back to Paul's first proposal in 1999. So one way is to download all the old messages with a newsreader. They also seem to be accessible via Google. E.g., search for "I was amazed to find that there isn't a basic rational numbers class" Jonathan