...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
It is, of course, impossible to please everyone with a list like this.
Some of the criteria we have used are:
FPT
one =static_cast<FPT>(42);
).
The constants have all been calculated using high-precision software working with up to 300-bit precision giving about 100 decimal digits. (The precision can be arbitrarily chosen and is limited only by compute time).
The minimum accuracy chosen (100 decimal digits) exceeds the accuracy of reasonably-foreseeable floating-point hardware (256-bit) and should meet most high-precision computations.
long double
epsilon
.
Warning | |
---|---|
We have not yet been able to check that
all constants are accurate at the full
arbitrary precision, at present 100 decimal digits. But certain key values
like |
Code written using math constants is easily portable even when using different floating-point types with differing precision.
It is a mistake to expect that results of computations will be identical, but you can achieve the best accuracy possible for the floating-point type in use.
This has no extra cost to the user, but reduces irritating, and often confusing and very hard-to-trace effects, caused by the intrinsically limited precision of floating-point calculations.
A harmless symptom of this limit is a spurious least-significant digit; at worst, slightly inaccurate constants sometimes cause iterating algorithms to diverge wildly because internal comparisons just fail.
See tutorial above for normal use, but this FAQ explains the internal details used for the constants.
Constants are stored as 100 decimal digit values. However, some compilers do not accept decimal digits strings as long as this. So the constant is split into two parts, with the first containing at least 128-bit long double precision (35 decimal digits), and for consistency should be in scientific format with a signed exponent.
The second part is the value of the constant expressed as a string literal, accurate to at least 100 decimal digits (in practice that means at least 102 digits). Again for consistency use scientific format with a signed exponent.
For types with precision greater than a long double, then if T is constructible
T
is constructible from a
const char*
then it's directly constructed from the
string, otherwise we fall back on lexical_cast to convert to type T
. (Using a string is necessary because
you can't use a numeric constant since even a long
double
might not have enough digits).
So, for example, a constant like pi is internally defined as
BOOST_DEFINE_MATH_CONSTANT(pi, 3.141592653589793238462643383279502884e+00, "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651e+00");
In this case the significand is 109 decimal digits, ensuring 100 decimal digits are exact, and exponent is zero.
See defining new constants to calculate new constants.
A macro definition like this can be pasted into user code where convenient,
or into boost/math/constants.hpp
if
it is to be added to the Boost.Math library.
Apart from the built-in floating-point types float
,
double
, long
double
, there are several arbitrary
precision floating-point classes available, but most are not licensed for
commercial use.
This work is based on an earlier work called e-float: Algorithm 910: A Portable C++ Multiple-Precision System for Special-Function Calculations, in ACM TOMS, {VOL 37, ISSUE 4, (February 2011)} (C) ACM, 2011. http://doi.acm.org/10.1145/1916461.1916469 e_float but is now re-factored and available under the Boost license in the Boost-sandbox at multiprecision where it is being refined and prepared for review.
Big Number which is a reworking of e_float by Christopher Kormanyos to use expression templates for faster execution.
NTL by Victor Shoup has fixed and arbitrary high precision fixed and floating-point types. However none of these are licenced for commercial use.
#include <NTL/quad_float.h> // quad precision 106-bit, about 32 decimal digits. using NTL::to_quad_float; // Less precise than arbitrary precision NTL::RR.
NTL class quad_float
, which
gives a form of quadruple precision, 106-bit significand (but without an
extended exponent range.) With an IEC559/IEEE 754 compatible processor, for
example Intel X86 family, with 64-bit double, and 53-bit significand, using
the significands of two 64-bit doubles,
if std::numeric_limits<double>::digits10
is 16, then we get about twice
the precision, so std::numeric_limits<quad_float>::digits10()
should be 32. (the default std::numeric_limits<RR>::digits10()
should be about 40). (which seems to agree
with experiments). We output constants (including some noisy bits, an approximation
to std::numeric_limits<RR>::max_digits10()
)
by adding 2 extra decimal digits, so using quad_float::SetOutputPrecision(32 +
2);
Apple Mac/Darwin uses a similar doubledouble 106-bit
for its built-in long double
type.
Note | |
---|---|
The precision of all |
Arbitrary precision floating point with NTL class RR, default is 150 bit (about 50 decimal digits) used here with 300 bit to output 100 decimal digits, enough for many practical non-'number-theoretic' C++ applications.
NTL is not licenced for commercial use.
This class is used in Boost.Math and an option when using big_number projects to calculate new math constants.
GMP and MPFR have also been used to compute constants, but are licensed under the Lesser GPL license and are not licensed for commercial use.
A review concluded that the way in which the constants were presented did
not meet many peoples needs. None of the methods proposed met many users'
essential requirement to allow writing simply pi
rather than pi()
.
Many science and engineering equations look difficult to read when because
function call brackets can be confused with the many other brackets often
needed. All the methods then proposed of avoiding the brackets failed to
meet all needs, often on grounds of complexity and lack of applicability
to various realistic scenarios.
So the simple namespace method, proposed on its own, but rejected at the first review, has been added to allow users to have convenient access to float, double and long double values, but combined with template struct and functions to allow simultaneous use with other non-built-in floating-point types.
A function mechanism was provided by in previous versions of Boost.Math.
The new mechanism is to permit partial specialization. See Custom Specializing a constant above. It should also allow use with other packages like ttmath Bignum C++ library.
Not here in this Boost.Math collection, because physical constants:
Some physical constants may be available in Boost.Units.