Boost logo

Boost :

From: Moore, Paul (Paul.Moore_at_[hidden])
Date: 1999-12-03 09:34:28


Hi,
I was amazed to find that there isn't a basic rational numbers class
available anywhere on the net. It strikes me as pretty fundamental, like
complex.

Attached is a first draft of such a beast. The file implements

      template <class Int> Int gcd(Int n, Int m)
      template <class Int> Int lcm(Int n, Int m)
      template <class Int> class rational { ... }

The gcd/lcm functions are there as convenience - I needed GCD for the
rational implementation, and LCM is trivial based on GCD.

The rational class is parameterised on an integer type (similar to complex)
so you can have rational<int>, rational<unsigned int>, rational<long long>,
or whatever.

Implementation details:

1. Rationals are stored as normalised (numerator, denominator) pairs. This
has
   the advantage of simplicity. I don't see the normalisation cost as
critical, but
   I'm willing to listen to arguments.
2. As a consequence, range is limited, in a fairly complex way. In a 32-bit
setup,
   unsigned rationals with denominator of 1 can go up to 2^32 - 1, whereas
with
   a denominator of 2^32 - 1, they can only reach 1. An alternative
implementation
   would be integer part plus fraction, but is this worth it?

I would appreciate comments. In particular -

1. Zero denominators throw an error - a placeholder string for now. Is there
a boost
   policy on what to throw? Should I throw a subclass of std::exception?
[Actually,
   I could implement infinity and NaN, but is this worth it? It makes
problems for
   comparability, apart from anything else...]
2. The only implicit conversions I have are base-integer-type to rational.
Is this OK?
   Does this cover things well enough?
3. I implement input and output operators. This pulls in the <iostream>
header. Is this
   correct? Is it the right approach?
4. I expose numerator() and denominator() member functions. Is this a good
thing?

What other issues need considering? How about a to_float (to_double)
function? What
about from_float/from_double? Is there a good algorithm for the latter?
Other functions?
pow? modulus? ....?

The intention is that this should be a relatively light-weight value class
for people who want to use (exact) fractions, but who don't expect to do any
really heavy numerical processing. As such, I don't think it needs to get
too complicated. [But this is the root of my concern about the effective
range of the type above - can I describe this well enough to make sense to
class users?]

I ought to point out that I've not designed a value-based class like this
before - I hope I haven't made any basic mistakes! On that note, would it be
useful to have a boost "samples" directory - containing template
implementations of concepts which can be fleshed out for real cases. I
imagine a basic numeric type (reimplementing int, say), a trivial smart
pointer, and a basic STL container (encapsulate a C array, maybe, or just a
null container which never contains anything), as a starter.

Hope this is of interest,
Paul Moore

 <<rational.hpp>>




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