Boost logo

Boost :

From: Daryle Walker (darylew_at_[hidden])
Date: 2000-07-18 16:09:35


on 7/18/00 1:03 PM, Paul A. Bristow at pbristow_at_[hidden] wrote:

> I am working on Daryle Suggestion
>
>> -----Original Message-----
>> From: Daryle Walker [mailto:darylew_at_[hidden]]
>> Sent: Friday, July 14, 2000 10:59 PM
>> To: boost_at_[hidden]
>> Subject: Re: Standard Math Constants?
>
> but have some queries:
>
> 1 // Unspecialised does NOT throw - is this intended and why?

I just put it in there for conceptual purposes. Of course, for a general
type, these operations may throw. So, we should remove the throw
specifications entirely (since anything may be potentially thrown). We also
have to consider the talk in this list of the pessimization of throw
specifications.

I somewhat based my system on std::numeric_limits, and the methods there
don't throw. That's were I got the 'is_specialized' idea from (do you guys
like that?). The unspecialized std::numeric_limits sets all the constants
as zero/false and leaves the methods unimplemented; should we leave the
unspecialized math_const like that too?

> 2 I think the rationale of this needs to be stated.
> (I for one (novice) do not see why this
>
> static T one() { T t = zero(); return ++t; }
>
> is better than:
>
> static T one() ( return static_cast<T>(1.)}

It isn't. I'm just using this as an example. The point of my message was
to suggest using (inline) functions to get the constants instead of declared
static const members. AFAIK, inline static const members only work for the
integral types, and not the floating (which means that the original sample
is wrong) nor user-defined types.

I used operator++ for this implementation since it can represent the
conceptual "successor" operation, and one follows zero. It also doesn't
require T to be convertible from a double.

> 3 I think the assumtions need to be specified in the documentation:
>
> static T zero() { return T(); } // Assumes default constructor?

As mentioned above, this is just a sample. Implementers are free to use
different code (as long as the answer is the same). Since the built-in
numeric types make the default constructor give zero, it would be bad form
for a user-defined numeric type not to have a default constructor or to have
one that doesn't result in zero.

> static T one() { T t = zero(); return ++t; } // assumes operator++ ?
> static T two() { T t = one(); return ++t; }
>
> static T one_half() { return one() / two(); } // Assumes operator/ ?
>
> 4
> static T radian_per_degree() { return pi() / static_cast<T>(180); }
> static T degree_per_radian() { return one() / radian_per_degree(); }
> // Why not use explicit values? 0.017453292519943295769237L

These are also samples; they can be done differently. So, the presented
operators don't have to be defined (they should for numeric types, though).
Explicit values can work if there's a conversion from float/(long)double to
T.

> 5
>
> Is it better to specialise like this
>
> static T pi() { return
> static_cast<T>(3.141592653589793238462643383279502884197L); }
>
> or like this?
>
> static T pi() { return 3.141592653589793238462643383279502884197F); }
>
> 6 OR Should ALL constants end with L ? (as suggested desirable by Jens
> Maurer)

I would pick whichever kind that can convert to T the best, if any. If T is
float, double, or long double, you should use that exact type. If none
convert, you have to use some alternate means to generate the result.


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