
Boost : 
From: Moore, Paul (paul.moore_at_[hidden])
Date: 20010123 10:58:06
I think I'm close to the point where I can release an updated version of
rational.hpp. Most of the issues are now sorted.
Only one big outstanding issue remains, which is that without Koenig lookup,
the implementation of abs() is irretrievably broken. In the case of
rational<IntType> where IntType is a userdefined type in its own namespace,
with an abs() function defined in that namespace, I can't see any way for
abs(rational<IntType>) to locate abs(IntType) in the absence of Koenig
lookup. After all, that's the problem Koenig lookup was designed to solve...
With a fully implemented Koenig lookup, the following should work:
template <typename IntType> rational<IntType> abs(rational<IntType> r)
{
using std::abs; // [1] For builtin types...
return rational<IntType>(abs(r.numerator()), r.denominator());
}
I dislike the need for the incantation at [1], though. First, because it
feels clumsy. Effectively, it is attempting to add a few more names into the
pot for when the compiler tries to find an abs() function  specifically for
the case where IntType is a builtin. But Koenig lookup is effectively a "do
the right thing" type of rule  which doesn't work without help for builtin
types?!?? As I say, it just "feels clumsy".
More importantly, the impression I get is that too many compilers are broken
with respect to the using statement at [1]. Either they don't put abs() into
std::, or (gcc) they ignore using statements at function scope. There's also
the question of whether std::abs() is available for all builtin types. The
standard only mandates std::abs(int) and std::abs(long)  while I can't see
anyone wanting rational<char> or rational<short>, I certainly can see a case
for rational<long long> or rational<__int64> or whatever. And I could
imagine compilers "forgetting" std::abs(long) and just leaving std::labs for
that case (I know MSVC does this, but as it doesn't have Koenig lookup, the
point is moot.)
Overall, I feel that worrying about all of these issues for a relatively
uncommon, nonperformancecritical function such as abs() just isn't worth
it.
I'm pretty sure that what I'll do is to implement rational abs() as
template <typename IntType> rational<IntType> abs(rational<IntType> r)
{
IntType num = r.numerator();
if (num < IntType(0))
num = num;
return rational<IntType>(num, r.denominator());
}
I apologise in advance to implementers of unlimitedprecision integer types
who take care to write a highly tuned abs() function which does a simple bit
operation.
[[Actually, I will probably work a bit harder at this to minimise copying of
IntTypes. That's probably a more important optimisation than worrying about
abs vs compare/negate]].
Paul.
PS There's probably scope here for a boost/numeric_ops.hpp header, which
takes a traitslike approach to standard numeric operations like
signtesting. The default implementation would be comparison against zero,
but implementers of numeric types could specialise to provide optimised
versions. This is somewhat related to the Number/Algebraic concepts thread,
but taking a less theoretical and more practical approach.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk