Boost logo

Boost :

From: Greg Colvin (gcolvin_at_[hidden])
Date: 2001-10-25 15:26:08

From: Ed Brey <edbrey_at_[hidden]>
> From: "Greg Colvin" <gcolvin_at_[hidden]>
> ...
> > I'd prefer long double constants.
> I was thinking double in response to Peter Dimov's point about literals defaulting to double. Pi would do so for consistency.
One argument I can see to the contrary is that with literals, you often don't have enough digits to matter, and if you do it's quite
obvious that you have a whole lot of digits. Pi would silently lose precision when long double is used.
> However, besides consistency, a long double Pi has the problem that it will trigger loss-of-precision warnings when used in the
common case manner (if the platform has different representations for double and long double). This seems unacceptable.
> I wish I had a great answer. The closest I can think of is to put double, long double, and float constants each in its own
namespaces, although that has its own problems. On the other hand, it also solves a problem that hasn't been explicitly presented
> Suppose someone wrote a non-generic program, but used typedefs because he wasn't sure of the precision he'd need. For example:
> typedef double Real;
> using namespace boost::math;
> Real foo = 4./3. * pi * r * r * r; // and a bunch of other neat math stuff
> This works fine for a while. Then the user finds a case where he'd prefer to trade off some speed for accuracy, he might want to
change the first two lines to work with long doubles instead of doubles. His literals are small, and so don't have any value to be
long double, but that isn't the case for pi. Having to change this to pi_l would be undesirable.
> But wait. The literals really do need to change, since unsigned long(4./3.) is not the same as 4.L/3.L. So you really do need to
write the entire program with a given precision in mind, or wrap everything in casts like "Real(4)". But if one is going to do all
that, wrapping pi as "Real(pi_l)" isn't much by comparison. And this would leave plain old pi available as a warning-free double.

I don't see the need for three flavors of pi, so if double is the best
default then that is all we should provide for unadorned use.

If someone is serious about paramerizing their program on floating-point
type it seems they should do:

    typedef double Real;
    using namespace boost::math;
    Real foo = Real(4.)/Real(3.) * constant<Real>(pi) * r * r * r;

Or if they need to use these constants a lot:

    const Real Four_Thirds = Real(4) / Real(3);
    const Real Pi = constant<Real>(pi);

> > Of course Beman says "Please do not make any design decisions for math
> > constants based on brain-dead compilers."
> Agreed. Of course, the same techniques that break compilers also tend to fight the language. Using the operator double()
approach, gone is the obviousness of parentheses meaning function and no parentheses meaning variable. Instead, what looks like a
variable actually has the restrictions of a function. This may be one of those cases when an exception to the norm is a good thing,
but such exceptions need to be examined closely.

What restrictions of a function do you mean? In my design pi is an
object, not a function. You can pass it by address or by reference.

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