Boost logo

Boost :

From: Paul A. Bristow (boost_at_[hidden])
Date: 2002-10-16 18:23:08


Thank you for clarification of initialisation of static const floats in class,
correctly disallowed by MSVC 7.0 C2864.

> -----Original Message-----
> From: boost-bounces_at_[hidden]
> [mailto:boost-bounces_at_[hidden]]On Behalf Of Guillaume Melquiond
> Sent: Wednesday, October 16, 2002 10:42 AM

 I have now found problems with the alternative 'switch' mechanism:

1 radix and digits must be from numeric_limits (and so must be specialised for
each floating point type - may be tricky for user defined types)

2 Need to check Floating point type to suffix correctly, F, nothing, or L.
Needs some form of typeof()?
3 Hinders/prevents extension to other floating point types (see quad_float
example above).

4 Values not available only reveal via NaN at run-time.

I gave up after getting to this :-(

template<typename FPtype>
const FPtype pi_lower()
{
        int digits = std::numeric_limits<FPtype>::digits; // significand binary digits.
        int radix = std::numeric_limits<FPtype>::radix; // only defined for radix 2, so
far.

        FPtype lower =
                (radix == 2) ?
                ( // Expected radix.
                (digits == 113) ?
3.141592653589793238462643383279502797479068098137295573004504331874296718662975
536062731407582759857177734375L
                // value for 113 bits.
                : (digits == 64) ?
3.14159265358979323829596852490908531763125210004425048828125L // value for
significand 64 bits.
                : (digits == 53) ? 3.141592653589793115997963468544185161590576171875 //
value for significand 53 bits.
                : (digits == 24) ?
                // Must test FPtype to find if value is a float, double or long double and
suffix is F, nothing or L.
                // Because value must be exactly representable, we MUST avoid conversion.
                (typeof(FPtype == float) ? 3.141592502593994140625F // value for float
significand 24 bits.
                        : typeof(FPtype == double) ? 3.141592502593994140625 // value for double
significand 24 bits.
                        : typeof(FPtype == double) ? 3.141592502593994140625L // value for long
double significand 24 bits.
                        : std::numeric_limits<FPtype>::quiet_NaN() // value for any other significand
24 bits.
                        // How to deal with other FP types?
                )
                : 3 // Unknown and/or unimplemented floating point significand
                )
                : std::numeric_limits<FPtype>::quiet_NaN(); // unknown and/or unimplemented
floating point radix!
        // BUT disadvantage is that it only shows at run-time, not compile time.
        return lower;
} // template<typename FPtype> const FPtype pi_lower()

and have therefore arrived at the following (see attached for full files used
for MSVC 7.0)

using NTL::quad_float;
using NTL::to_quad_float;

namespace
{ // anonymous.
        // Pi Exactly representable values, calculated using 300 bit NTL.

        // IEEE float, radix 2, 24 significand digits.
        static const float pi_f_lower = 3.141592502593994140625F;
        static const float pi_f_upper = 3.1415927410125732421875F;
        static const float pi_f_nearest =
3.14159265358979323846264338327950288419716939937510F;

        // IEEE double, radix 2, 53 significand digits.
        static const double pi_d_lower =
3.141592653589793115997963468544185161590576171875;
        static const double pi_d_upper =
3.141592653589793560087173318606801331043243408203125;
        static const double pi_d_nearest =
3.14159265358979323846264338327950288419716939937510;

        // IEEE long double, radix 2, 64 significand digits.
        static const long double pi_l_nearest =
3.141592653589793238462643383279502884197169400753029295841032855793712028004489
974652930461153208029583374L;
        static const long double pi_l_lower =
3.141592653589793238462643383279481227063690961095741346051547380688329091924515
52371494472026824951171875L;
        static const long double pi_l_upper =
3.141592653589793238462643383279530530870267274333579579086877554827683667326709
837652742862701416015625L;

  // Exactly representable in 128 bit SPARC & VAX H double extended format
smallest interval values of pi.
        static const long double pi_ll_lower =
3.141592653589793238462643383279502797479068098137295573004504331874296718662975
536062731407582759857177734375L;
        static const long double pi_ll_nearest =
3.141592653589793238462643383279502884197169400753029295841032855793712028004489
9746529304611532080295833741639955L;
        static const long double pi_ll_upper =
3.141592653589793238462643383279503182665056975584466184200092848859760426283305
179140370455570518970489501953125L;

        // Examples of values for integer, used to show a user specialization.
        // Only useful for US states with brain-dead legislators?
        static const int pi_i_lower = 3;
        static const int pi_i_nearest = 3;
        static const int pi_i_upper = 4;
} // namespace

template <class FPtype, int digits = std::numeric_limits<FPtype>::digits, int
radix = std::numeric_limits<FPtype>::radix >
class pi;
// Default digits and radix are from std::numeric_limits,
// but could be made different for special floating point types
// that don't provide numeric_limits.

// Specializations for builtin floating point types.
// TODO use macro?
template <>
class pi<float>
{
public:
        static const float lower()
        {
                return pi_f_lower;
        }
        static const float upper()
        {
                return pi_f_upper;
        }
        static const float nearest()
        {
                return pi_f_nearest;
        }
}; // template <> class pi<float>

template <>
class pi<double>
{ // Specialization for double.
public:
        static const double lower()
        {
                return pi_d_lower;
        }
        static const double upper()
        {
                return pi_d_upper;
        }
        static const double nearest()
        {
                return pi_d_nearest;
        }
}; // template <> class pi<double>

Usage examples:

        cout << "pi<float>::lower() " << pi<float>::lower() << endl;
        cout << "pi<float>::nearest() " << pi<float>::nearest() << endl;
        cout << "pi<float>::upper() " << pi<float>::upper() << endl;

        // Example of a non-floating point type - not very practical approx to pi!
        cout << nl << "pi<int>::lower() " << pi<int>::lower() << endl;
        cout << "pi<int>::nearest() " << pi<int>::nearest() << endl;
        cout << "pi<int>::upper() " << pi<int>::upper() << endl;

Output example is:

float significant digits = 9
pi<float>::lower() 3.1415925
pi<float>::nearest() 3.14159274
pi<float>::upper() 3.14159274
nearest is upper limit.

I have also specialised for a 'user defined' floating point type
NTL quad_float (aka doubledouble) using 106 significand bits.
This seems to work as a way of providing user extension (probably in a separate
file).

        // Example of a user defined floating point type.
        int quad_float_significand_digits = 106; // 53 + 53
        int quad_float_significant_digits = 2 + quad_float_significand_digits *
30101/100000; // 33
        cout << nl << "quad_float significand digits = " <<
quad_float_significand_digits << endl;
        cout << "quad_float significant digits = " << quad_float_significant_digits <<
endl;
        quad_float::SetOutputPrecision(quad_float_significant_digits); // significant
decimal digits.
        cout << (PrecisionOK() ? "quad_float::SetOutputPrecision OK\n" :
"quad_float::SetOutputPrecision not OK!\n");
        cout.precision(quad_float_significant_digits); // ineffective for quad_float -
use SetOutputPrecision.
        cout << nl << cout.precision() << endl; // 33

        cout << "pi<quad_float>::lower() " << pi<quad_float>::lower() << endl;
        cout << "pi<quad_float>::nearest() " << pi<quad_float>::nearest() << endl;
        cout << "pi<quad_float>::upper() " << pi<quad_float>::upper() << endl;
output is:

quad_float significand digits = 106
quad_float significant digits = 33
quad_float::SetOutputPrecision OK

pi<quad_float>::lower() 3.14159265358979323846264338327948
pi<quad_float>::nearest() 3.14159265358979323846264338327951
pi<quad_float>::upper() 3.14159265358979323846264338327951

Does this look at all promising, if ugly.

Paul

Dr Paul A Bristow, hetp Chromatography
Prizet Farmhouse, Kendal, Cumbria, LA8 8AB UK
+44 1539 561830 Mobile +44 7714 33 02 04
mailto:pbristow_at_[hidden]






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