Boost logo

Boost :

From: Moore, Paul (paul.moore_at_[hidden])
Date: 2000-10-19 05:17:42

From: Herve Bronnimann [mailto:hbr_at_[hidden]]
> On Wed, Oct 18, 2000 at 03:47:30PM +0100, Moore, Paul wrote:
> > This gives rise to a question - is there
> > any real-world need to access the numerator
> > or denominator of a rational number, in
> > general? (And if so, should there be a
> > normalisation guarantee? At present the
> > results are normalised, but that's not
> > necessary...)
> My .02: if you don't make the normalization
> guarantee, you'll have to document the
> invalidation rules everywhere. Suppose I call
> denominator(), then an operation which performs
> renormalization, then numerator(), I might have
> a bad surprise if you haven't told me there was
> a possibility of a renormalization.
> This seems to indicate that always normalizing
> is the right thing to do.

Given that I don't 100% accept that keeping the internal representation
normalised at all times is the right thing to do (and regardless, it isn't
something that the user has any right to be able to determine from looking
at the external representation), you are saying that numerator() and
denominator() should be documented to always return the normalised values.
Fair enough.

> When you speak about numerator() and
> denominator(), you may want to document that
> these are const member functions, i.e. they
> can't be used to modify the value of the
> rational.

That's not what const means. That they return values, not references, is the
reason they cannot be used to modify the rational.

But as to whether they should be const functions - yes, they almost
certainly should, but if they are (and they have the normalisation
guarantee) they would have to normalise every call. This makes them pretty
inefficient. You couldn't normalise the rational and then just return the
value, as that would involve modifying the rational, hence violating
const-ness. OK, you could make the members mutable, but then we have the
strange situation of a class with 2 data members, both of which are mutable.
This seems odd...

> Finally: one reason you want to provide (at
> least) denominator: how do I test if a rational
> is an integer, other than by denominator()==1 ?

You're arguing for an is_whole() method. And you've explained how you would
implement it, given that I haven't.

I'm not disagreeing with you, just pointing out that exposing the internals
means that people can do whatever they want, rather than looking at whether
the interface is complete.

By the way, if you look at my posting in response to Dave, you'll see that
an alternative internal representation could be int+num/den. In this case,
numerator()==0 would be a test for whole-ness...

> And given that the test succeeds, simply taking
> numerator() instead of making a conversion to an
> integral type seems more efficient. This would
> also argue for the presence of numerator() as
> well.

Actually, rational_cast<int>(rat) really should be efficient enough for you.
And it's not representation-dependent. [[Actually, this currently does
(int)num/den, which if den is 1, should optimise to pretty much just num,
maybe with the is_whole() test repeated]].

I'm not against numerator() and denominator() methods - you'll note that
they exist and currently do exactly what you expect - but there are genuine
issues with them, and that is why I put the warnings in the documentation
around them. Until I'm convinced that no other representation is credible or
useful, I will retain the warnings (and the right to change things that goes
with them).

But I'll put an is_whole() method on the TODO list for the next revision.


Boost list run by bdawes at, gregod at, cpdaniel at, john at