C++ Boost

Math Constants

Rationale


Introduction
accuracy
Naming convention
Which constants

Introduction

Mathematical constants (like Archimedes' pi) are exceedingly unlikely to change, whereas estimates of physical ‘constants‘ (like Planck's h) are certain to vary. Physical constants usually have a known uncertainty, usually greater than even the accuracy of float representations, whereas mathematical constants can be calculated to an arbitrarily high precision. So it would be confusing to store mathematical and physical constants in the same header file.

Accuracy

A special feature of this collection is that the constants values are a little more accurate than can be represented by current and reasonably foreseeable floating-point hardware. Upper and lower smallest-interval values also provided for some popular floating-point formats: these will be useful when using interval arithmetic, for example to estimate computational uncertainty. Interval limit values are exactly representable to aid portability. Small differences in constants can lead to puzzling differences between computations.  The values given are slightly, but significantly, more accurate than is usually achieved by using any C++ compiler to calculate constants.  The accuracy cannot vary with compiler type and version and so are more portable.
The constants have all been calculated using software working with 400-bit precision equivalent to about 130 decimal digits. (The precision can be chosen and is limited only by compute time). The display precision selected for values of constants (40 decimal digits) exceeds the accuracy of plausibly foreseeable general-purpose floating-point hardware.
The objective is to achieve the full accuracy possible for all real-life computations. This has no extra cost to the user, but reduces irritating, and often confusing and hard-to-trace effects, caused by the intrinsically limited precision of floating-point calculations. At least these show as a spurious least-significant digit; at worst slightly inaccurate constants cause algorithms to fail because internal comparisons just fail.

Naming convention

Discussion about naming convention made very clear that it is not possible to please everyone!  Worse still, there seems to be an irreconcilable conflict between name-first and factor-first conventions when names of upper and lower limits of intervals are required. Allowing aliases has some disadvantages. 

Some urgent desires to use an alternative name can be met using macros to 'rename', or using the C-style macros #define values, for example:

const double My_Very_Own_Name_for_pi  = BOOST_PI;

Naming demands compromises - for this version I have chosen the upper and lower without underscores_ h, for example, oneDivTwoPi.

In general, a C++ Standard Library style is used, favouring longer and easier to read names over ease of typing, and all lower case and underscore _ as separator. Of course, names cannot start with a digit, so words, like two and half, are used instead. C99 names are used where appropriate, but names are not in all capitals as used for constants in many C programs. The rationale is that these names are variable names and not macro or #define names for which ALL CAPITALS are conventionally retained in C++ programs. Some examples, and the rationale for them, should make this clearer than an attempt to write a formal specification.

A major difficulty is the desire to put the name first and follow by type. For example:

pi_div_2  versus  half_pi

And yet there was very strong preference for two_pi rather than pi_twice or pi_times_2.

pi  // Prefer lower case only - use uppercase only for class names.
loge_pi // much clearer than logepi
sqrt_2 // shorter than sqrt_two
log_2 // clearer with separating _ than log2, despite more typing.
but Boost favours clarity over curtness.
// and reserve log2 for log to base 2, log10 for log to base 10.
// sqrt is commonly used and shorter than square_root_2.
cbrt_2 // ugly, but is C99 name.
ten // can’t be 10 so use the word ten instead.
third // shorter than one_div_three.
one_div_sqrt_2 // one_div rather than reciprocal – short but clear.
// _div clearer than _on or _upon or _over.
half_pi // rather than pi_div_2.
pi_sqr // pi_squared is rather long.
two_pow_three_halves // two_pow_three_div_two is ambiguous.
minus_loge_loge_2 // can't start with - so use word.

There are always problems with more complex constants where brackets would be used

two_pow_three_halves // two_pow_three_div_two is ambiguous.

Explicit typed names can only sensibly follow the C99 convention:

pi_f // float
pi_d // double
pi_l // long double
pi_i // integer???
pi // nearest to pi (usually either upper and/or lower interval limit)
pi_l // pi interval lower limit
pi_u // pi interval upper limit

and where both floating-point type AND upper or lower limit are fixed:

pi_f_l // pi float lower limit
pi_l_l // pi long double lower limit
pi_l_u // pi long double upper limit

Which constants?

  1. Basic math constants. The absolute minimum?
  2. More, and some derived math constants, noting that some can be calculated by compilers without loss,  for example * or / factors of 2).
  3. More obscure (but essential for some people) math constants.

I have indicated some rationale for including each one,
drawing on the 'authority' of 3 texts, and Boost discussions:

1 Donald E Knuth, Art of Computer Programming,
2 John Hart, Computer Approximations, and
3 Stephen Moshier, Math Functions, Cephes math function library.
4 Morris, ACM 715 & Brown CDFlib collection of math functions used in statistics.

as a guide to what has been used in typical math work, in particular those constants that would be required for a math function library..

All the builtin sqrt, log, trig and pow functions are especially liable to be inaccurate, (and seriously inaccurate at times) and all lead to run-time code which is extremely unlikely to be optimised. I indicate this by saying, for example, 'avoid log()'.

1 Basic math_constants.hpp
 

name alternative name(s) Use Comments Notes
e       Euler
pi       Archimedes
log_pi pi_log   avoid log()  
log_sqrt_two_pi pi_twice_sqrt_log log( sqrt( two_pi ) ) avoid log() and sqrt  
sqrt_2 two_sqrt   sqrt_2 is shorter and more obvious  
sqrt_3     avoid sqrt  
sqrt_5     avoid psqrt  
sqrt_10     avoid sqrt  
cbrt_2     avoid pow  
cbrt_3 cube_root_3   avoid pow (but follow cbrt C99 naming convention, even if ugly!)  
fourth_root_2     long but not common. avoid pow()  
log_2   loge(2) or ln(2) avoid log()  
log_3   loge(3) avoid log()  
log_4   loge(4) avoid log()  
log_5   loge(5) avoid log()  
log_10   loge(10) avoid log()  
log10_2 two_log10 logbase10 of 2 accuracy  
log10_e e_log10 logbase10 of e accuracy  
log_two_pi        
log_e        
log_pi        
one_div_log_2 reciprocal_log_2   reciprocal is too long?  
one_div_log_10        
one_div_pi     accuracy  
sqrt_pi pi_sqrt  == gamma_half Need an alias system?  
sqrt_1_div_pi   sqrt(1_div_pi) ambigous  
log_sqrt_two_pi        
phi golden_ratio   golden_ratio is too long Phideas
euler gamma   name gamma is likely to be used for other purposes. Euler


2 Additional

Again note that some of these may be calculated accurately by some compilers, but are good for clear programs, and avoid any run-time code for debug and/or less-optimised code.
 

name alternative name(s) Use Comments Notes
pi_div_2 half_pi   Put name pi first.  Convenient even if can be calculated accurately.  
pi_div_4 quarter_pi   Convenient even if can be calculated accurately.  
pi_div_3 third_pi      
pi_div_6 sixth_pi      
pi_div_3_twice two_thirds_pi   two_thirds_pi is MUCH nicer?  
pi_div_3_times_4 four_thirds_pi   four_thirds_pi is mUCH nicer?  
pi_div_4_times_3 three_quarters_pi or three_pi_div_4   Consistency lacks clearness.  
one_div_pi        
pi_squared        
two_pi_squared        
one_div_pi_squared        
sqrt_pi_div_2 sqrt_half_pi      
one_div_sqrt_pi        
sqrt_quarter_pi        
sqrt_two_div_pi        
cbrt_pi        
one_div_cbrt_pi        
sqrt_2_div_2 half_sqrt_2   Convenient even if can be calculated accurately.  
one_div_sqrt_2        
one_div_sqrt_two_pi        
two_pow_two_thirds   2^(2/3)    
log_2_div_2        
e_squared        
one_div_e        
one_div_e_sqr        
two_pow_2_div_3        
log_log_2        
euler        

A handful of real constants:

one  floating point 1. NOT integer 1 useful
two  completeness?
three  completeness?
four  completeness?
ten  completeness?
half  accuracy on any base 10 systems
third  accuracy?
two_thirds  accuracy?
quarter


3 (More) Obscure

cbrt_10
sqrt_5
sqrt_32
sin_0
cos_0
tan_0
sin_1
cos_1
tan_1
sin_half
cos_half
tan_half
log_euler
one_div_euler
one_div_log_euler
gamma_third
gamma_two_thirds
gamma_sixth
gamma_min
gamma_min
e_pow_euler
e_pow_quarter_pi
e_pow_pi
pi_pow_e
zeta_three
exp(-2)
exp(-32)
??? More ???

 


http://www.hetp.u-net.com/public/mathconstants/rational.html, Revised 5 May 2005

© Copyright Paul A Bristow 2002-2005. All Rights Reserved.

Valid HTML 4.01!