|
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