diff options
Diffstat (limited to 'src/boost/libs/math/example')
148 files changed, 30408 insertions, 0 deletions
diff --git a/src/boost/libs/math/example/HSO3.hpp b/src/boost/libs/math/example/HSO3.hpp new file mode 100644 index 000000000..4e4ead7ab --- /dev/null +++ b/src/boost/libs/math/example/HSO3.hpp @@ -0,0 +1,509 @@ + +/********************************************************************************************/ +/* */ +/* HSO3.hpp header file */ +/* */ +/* This file is not currently part of the Boost library. It is simply an example of the use */ +/* quaternions can be put to. Hopefully it will be useful too. */ +/* */ +/* This file provides tools to convert between quaternions and R^3 rotation matrices. */ +/* */ +/********************************************************************************************/ + +// (C) Copyright Hubert Holin 2001. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef TEST_HSO3_HPP +#define TEST_HSO3_HPP + +#include <algorithm> + +#if defined(__GNUC__) && (__GNUC__ < 3) +#include <boost/limits.hpp> +#else +#include <limits> +#endif + +#include <stdexcept> +#include <string> + +#include <boost/math/quaternion.hpp> + + +#if defined(__GNUC__) && (__GNUC__ < 3) +// gcc 2.x ignores function scope using declarations, put them here instead: +using namespace ::std; +using namespace ::boost::math; +#endif + +template<typename TYPE_FLOAT> +struct R3_matrix +{ + TYPE_FLOAT a11, a12, a13; + TYPE_FLOAT a21, a22, a23; + TYPE_FLOAT a31, a32, a33; +}; + + +// Note: the input quaternion need not be of norm 1 for the following function + +template<typename TYPE_FLOAT> +R3_matrix<TYPE_FLOAT> quaternion_to_R3_rotation(::boost::math::quaternion<TYPE_FLOAT> const & q) +{ + using ::std::numeric_limits; + + TYPE_FLOAT a = q.R_component_1(); + TYPE_FLOAT b = q.R_component_2(); + TYPE_FLOAT c = q.R_component_3(); + TYPE_FLOAT d = q.R_component_4(); + + TYPE_FLOAT aa = a*a; + TYPE_FLOAT ab = a*b; + TYPE_FLOAT ac = a*c; + TYPE_FLOAT ad = a*d; + TYPE_FLOAT bb = b*b; + TYPE_FLOAT bc = b*c; + TYPE_FLOAT bd = b*d; + TYPE_FLOAT cc = c*c; + TYPE_FLOAT cd = c*d; + TYPE_FLOAT dd = d*d; + + TYPE_FLOAT norme_carre = aa+bb+cc+dd; + + if (norme_carre <= numeric_limits<TYPE_FLOAT>::epsilon()) + { + ::std::string error_reporting("Argument to quaternion_to_R3_rotation is too small!"); + ::std::underflow_error bad_argument(error_reporting); + + throw(bad_argument); + } + + R3_matrix<TYPE_FLOAT> out_matrix; + + out_matrix.a11 = (aa+bb-cc-dd)/norme_carre; + out_matrix.a12 = 2*(-ad+bc)/norme_carre; + out_matrix.a13 = 2*(ac+bd)/norme_carre; + out_matrix.a21 = 2*(ad+bc)/norme_carre; + out_matrix.a22 = (aa-bb+cc-dd)/norme_carre; + out_matrix.a23 = 2*(-ab+cd)/norme_carre; + out_matrix.a31 = 2*(-ac+bd)/norme_carre; + out_matrix.a32 = 2*(ab+cd)/norme_carre; + out_matrix.a33 = (aa-bb-cc+dd)/norme_carre; + + return(out_matrix); +} + + + template<typename TYPE_FLOAT> + void find_invariant_vector( R3_matrix<TYPE_FLOAT> const & rot, + TYPE_FLOAT & x, + TYPE_FLOAT & y, + TYPE_FLOAT & z) + { + using ::std::sqrt; + + using ::std::numeric_limits; + + TYPE_FLOAT b11 = rot.a11 - static_cast<TYPE_FLOAT>(1); + TYPE_FLOAT b12 = rot.a12; + TYPE_FLOAT b13 = rot.a13; + TYPE_FLOAT b21 = rot.a21; + TYPE_FLOAT b22 = rot.a22 - static_cast<TYPE_FLOAT>(1); + TYPE_FLOAT b23 = rot.a23; + TYPE_FLOAT b31 = rot.a31; + TYPE_FLOAT b32 = rot.a32; + TYPE_FLOAT b33 = rot.a33 - static_cast<TYPE_FLOAT>(1); + + TYPE_FLOAT minors[9] = + { + b11*b22-b12*b21, + b11*b23-b13*b21, + b12*b23-b13*b22, + b11*b32-b12*b31, + b11*b33-b13*b31, + b12*b33-b13*b32, + b21*b32-b22*b31, + b21*b33-b23*b31, + b22*b33-b23*b32 + }; + + TYPE_FLOAT * where = ::std::max_element(minors, minors+9); + + TYPE_FLOAT det = *where; + + if (det <= numeric_limits<TYPE_FLOAT>::epsilon()) + { + ::std::string error_reporting("Underflow error in find_invariant_vector!"); + ::std::underflow_error processing_error(error_reporting); + + throw(processing_error); + } + + switch (where-minors) + { + case 0: + + z = static_cast<TYPE_FLOAT>(1); + + x = (-b13*b22+b12*b23)/det; + y = (-b11*b23+b13*b21)/det; + + break; + + case 1: + + y = static_cast<TYPE_FLOAT>(1); + + x = (-b12*b23+b13*b22)/det; + z = (-b11*b22+b12*b21)/det; + + break; + + case 2: + + x = static_cast<TYPE_FLOAT>(1); + + y = (-b11*b23+b13*b21)/det; + z = (-b12*b21+b11*b22)/det; + + break; + + case 3: + + z = static_cast<TYPE_FLOAT>(1); + + x = (-b13*b32+b12*b33)/det; + y = (-b11*b33+b13*b31)/det; + + break; + + case 4: + + y = static_cast<TYPE_FLOAT>(1); + + x = (-b12*b33+b13*b32)/det; + z = (-b11*b32+b12*b31)/det; + + break; + + case 5: + + x = static_cast<TYPE_FLOAT>(1); + + y = (-b11*b33+b13*b31)/det; + z = (-b12*b31+b11*b32)/det; + + break; + + case 6: + + z = static_cast<TYPE_FLOAT>(1); + + x = (-b23*b32+b22*b33)/det; + y = (-b21*b33+b23*b31)/det; + + break; + + case 7: + + y = static_cast<TYPE_FLOAT>(1); + + x = (-b22*b33+b23*b32)/det; + z = (-b21*b32+b22*b31)/det; + + break; + + case 8: + + x = static_cast<TYPE_FLOAT>(1); + + y = (-b21*b33+b23*b31)/det; + z = (-b22*b31+b21*b32)/det; + + break; + + default: + + ::std::string error_reporting("Impossible condition in find_invariant_vector"); + ::std::logic_error processing_error(error_reporting); + + throw(processing_error); + + break; + } + + TYPE_FLOAT vecnorm = sqrt(x*x+y*y+z*z); + + if (vecnorm <= numeric_limits<TYPE_FLOAT>::epsilon()) + { + ::std::string error_reporting("Overflow error in find_invariant_vector!"); + ::std::overflow_error processing_error(error_reporting); + + throw(processing_error); + } + + x /= vecnorm; + y /= vecnorm; + z /= vecnorm; + } + + + template<typename TYPE_FLOAT> + void find_orthogonal_vector( TYPE_FLOAT x, + TYPE_FLOAT y, + TYPE_FLOAT z, + TYPE_FLOAT & u, + TYPE_FLOAT & v, + TYPE_FLOAT & w) + { + using ::std::abs; + using ::std::sqrt; + + using ::std::numeric_limits; + + TYPE_FLOAT vecnormsqr = x*x+y*y+z*z; + + if (vecnormsqr <= numeric_limits<TYPE_FLOAT>::epsilon()) + { + ::std::string error_reporting("Underflow error in find_orthogonal_vector!"); + ::std::underflow_error processing_error(error_reporting); + + throw(processing_error); + } + + TYPE_FLOAT lambda; + + TYPE_FLOAT components[3] = + { + abs(x), + abs(y), + abs(z) + }; + + TYPE_FLOAT * where = ::std::min_element(components, components+3); + + switch (where-components) + { + case 0: + + if (*where <= numeric_limits<TYPE_FLOAT>::epsilon()) + { + v = + w = static_cast<TYPE_FLOAT>(0); + u = static_cast<TYPE_FLOAT>(1); + } + else + { + lambda = -x/vecnormsqr; + + u = static_cast<TYPE_FLOAT>(1) + lambda*x; + v = lambda*y; + w = lambda*z; + } + + break; + + case 1: + + if (*where <= numeric_limits<TYPE_FLOAT>::epsilon()) + { + u = + w = static_cast<TYPE_FLOAT>(0); + v = static_cast<TYPE_FLOAT>(1); + } + else + { + lambda = -y/vecnormsqr; + + u = lambda*x; + v = static_cast<TYPE_FLOAT>(1) + lambda*y; + w = lambda*z; + } + + break; + + case 2: + + if (*where <= numeric_limits<TYPE_FLOAT>::epsilon()) + { + u = + v = static_cast<TYPE_FLOAT>(0); + w = static_cast<TYPE_FLOAT>(1); + } + else + { + lambda = -z/vecnormsqr; + + u = lambda*x; + v = lambda*y; + w = static_cast<TYPE_FLOAT>(1) + lambda*z; + } + + break; + + default: + + ::std::string error_reporting("Impossible condition in find_invariant_vector"); + ::std::logic_error processing_error(error_reporting); + + throw(processing_error); + + break; + } + + TYPE_FLOAT vecnorm = sqrt(u*u+v*v+w*w); + + if (vecnorm <= numeric_limits<TYPE_FLOAT>::epsilon()) + { + ::std::string error_reporting("Underflow error in find_orthogonal_vector!"); + ::std::underflow_error processing_error(error_reporting); + + throw(processing_error); + } + + u /= vecnorm; + v /= vecnorm; + w /= vecnorm; + } + + + // Note: we want [[v, v, w], [r, s, t], [x, y, z]] to be a direct orthogonal basis + // of R^3. It might not be orthonormal, however, and we do not check if the + // two input vectors are colinear or not. + + template<typename TYPE_FLOAT> + void find_vector_for_BOD(TYPE_FLOAT x, + TYPE_FLOAT y, + TYPE_FLOAT z, + TYPE_FLOAT u, + TYPE_FLOAT v, + TYPE_FLOAT w, + TYPE_FLOAT & r, + TYPE_FLOAT & s, + TYPE_FLOAT & t) + { + r = +y*w-z*v; + s = -x*w+z*u; + t = +x*v-y*u; + } + + + +template<typename TYPE_FLOAT> +inline bool is_R3_rotation_matrix(R3_matrix<TYPE_FLOAT> const & mat) +{ + using ::std::abs; + + using ::std::numeric_limits; + + return ( + !( + (abs(mat.a11*mat.a11+mat.a21*mat.a21+mat.a31*mat.a31 - static_cast<TYPE_FLOAT>(1)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + (abs(mat.a11*mat.a12+mat.a21*mat.a22+mat.a31*mat.a32 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + (abs(mat.a11*mat.a13+mat.a21*mat.a23+mat.a31*mat.a33 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + //(abs(mat.a11*mat.a12+mat.a21*mat.a22+mat.a31*mat.a32 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + (abs(mat.a12*mat.a12+mat.a22*mat.a22+mat.a32*mat.a32 - static_cast<TYPE_FLOAT>(1)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + (abs(mat.a12*mat.a13+mat.a22*mat.a23+mat.a32*mat.a33 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + //(abs(mat.a11*mat.a13+mat.a21*mat.a23+mat.a31*mat.a33 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + //(abs(mat.a12*mat.a13+mat.a22*mat.a23+mat.a32*mat.a33 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + (abs(mat.a13*mat.a13+mat.a23*mat.a23+mat.a33*mat.a33 - static_cast<TYPE_FLOAT>(1)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon()) + ) + ); +} + + +template<typename TYPE_FLOAT> +::boost::math::quaternion<TYPE_FLOAT> R3_rotation_to_quaternion( R3_matrix<TYPE_FLOAT> const & rot, + ::boost::math::quaternion<TYPE_FLOAT> const * hint = 0) +{ + using ::boost::math::abs; + + using ::std::abs; + using ::std::sqrt; + + using ::std::numeric_limits; + + if (!is_R3_rotation_matrix(rot)) + { + ::std::string error_reporting("Argument to R3_rotation_to_quaternion is not an R^3 rotation matrix!"); + ::std::range_error bad_argument(error_reporting); + + throw(bad_argument); + } + + ::boost::math::quaternion<TYPE_FLOAT> q; + + if ( + (abs(rot.a11 - static_cast<TYPE_FLOAT>(1)) <= numeric_limits<TYPE_FLOAT>::epsilon())&& + (abs(rot.a22 - static_cast<TYPE_FLOAT>(1)) <= numeric_limits<TYPE_FLOAT>::epsilon())&& + (abs(rot.a33 - static_cast<TYPE_FLOAT>(1)) <= numeric_limits<TYPE_FLOAT>::epsilon()) + ) + { + q = ::boost::math::quaternion<TYPE_FLOAT>(1); + } + else + { + TYPE_FLOAT cos_theta = (rot.a11+rot.a22+rot.a33-static_cast<TYPE_FLOAT>(1))/static_cast<TYPE_FLOAT>(2); + TYPE_FLOAT stuff = (cos_theta+static_cast<TYPE_FLOAT>(1))/static_cast<TYPE_FLOAT>(2); + TYPE_FLOAT cos_theta_sur_2 = sqrt(stuff); + TYPE_FLOAT sin_theta_sur_2 = sqrt(1-stuff); + + TYPE_FLOAT x; + TYPE_FLOAT y; + TYPE_FLOAT z; + + find_invariant_vector(rot, x, y, z); + + TYPE_FLOAT u; + TYPE_FLOAT v; + TYPE_FLOAT w; + + find_orthogonal_vector(x, y, z, u, v, w); + + TYPE_FLOAT r; + TYPE_FLOAT s; + TYPE_FLOAT t; + + find_vector_for_BOD(x, y, z, u, v, w, r, s, t); + + TYPE_FLOAT ru = rot.a11*u+rot.a12*v+rot.a13*w; + TYPE_FLOAT rv = rot.a21*u+rot.a22*v+rot.a23*w; + TYPE_FLOAT rw = rot.a31*u+rot.a32*v+rot.a33*w; + + TYPE_FLOAT angle_sign_determinator = r*ru+s*rv+t*rw; + + if (angle_sign_determinator > +numeric_limits<TYPE_FLOAT>::epsilon()) + { + q = ::boost::math::quaternion<TYPE_FLOAT>(cos_theta_sur_2, +x*sin_theta_sur_2, +y*sin_theta_sur_2, +z*sin_theta_sur_2); + } + else if (angle_sign_determinator < -numeric_limits<TYPE_FLOAT>::epsilon()) + { + q = ::boost::math::quaternion<TYPE_FLOAT>(cos_theta_sur_2, -x*sin_theta_sur_2, -y*sin_theta_sur_2, -z*sin_theta_sur_2); + } + else + { + TYPE_FLOAT desambiguator = u*ru+v*rv+w*rw; + + if (desambiguator >= static_cast<TYPE_FLOAT>(1)) + { + q = ::boost::math::quaternion<TYPE_FLOAT>(0, +x, +y, +z); + } + else + { + q = ::boost::math::quaternion<TYPE_FLOAT>(0, -x, -y, -z); + } + } + } + + if ((hint != 0) && (abs(*hint+q) < abs(*hint-q))) + { + return(-q); + } + + return(q); +} + +#endif /* TEST_HSO3_HPP */ + diff --git a/src/boost/libs/math/example/HSO3SO4.cpp b/src/boost/libs/math/example/HSO3SO4.cpp new file mode 100644 index 000000000..c4462c793 --- /dev/null +++ b/src/boost/libs/math/example/HSO3SO4.cpp @@ -0,0 +1,445 @@ +// test file for HSO3.hpp and HSO4.hpp + +// (C) Copyright Hubert Holin 2001. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#include <iostream> + +#include <boost/math/quaternion.hpp> + +#include "HSO3.hpp" +#include "HSO4.hpp" + + +const int number_of_intervals = 5; + +const float pi = ::std::atan(1.0f)*4; + + + +void test_SO3(); + +void test_SO4(); + + +int main() + +{ + test_SO3(); + + test_SO4(); + + ::std::cout << "That's all folks!" << ::std::endl; +} + + +// +// Test of quaternion and R^3 rotation relationship +// + +void test_SO3_spherical() +{ + ::std::cout << "Testing spherical:" << ::std::endl; + ::std::cout << ::std::endl; + + const float rho = 1.0f; + + float theta; + float phi1; + float phi2; + + for (int idxphi2 = 0; idxphi2 <= number_of_intervals; idxphi2++) + { + phi2 = (-pi/2)+(idxphi2*pi)/number_of_intervals; + + for (int idxphi1 = 0; idxphi1 <= number_of_intervals; idxphi1++) + { + phi1 = (-pi/2)+(idxphi1*pi)/number_of_intervals; + + for (int idxtheta = 0; idxtheta <= number_of_intervals; idxtheta++) + { + theta = -pi+(idxtheta*(2*pi))/number_of_intervals; + + ::std::cout << "theta = " << theta << " ; "; + ::std::cout << "phi1 = " << phi1 << " ; "; + ::std::cout << "phi2 = " << phi2; + ::std::cout << ::std::endl; + + ::boost::math::quaternion<float> q = ::boost::math::spherical(rho, theta, phi1, phi2); + + ::std::cout << "q = " << q << ::std::endl; + + R3_matrix<float> rot = quaternion_to_R3_rotation(q); + + ::std::cout << "rot = "; + ::std::cout << "\t" << rot.a11 << "\t" << rot.a12 << "\t" << rot.a13 << ::std::endl; + ::std::cout << "\t"; + ::std::cout << "\t" << rot.a21 << "\t" << rot.a22 << "\t" << rot.a23 << ::std::endl; + ::std::cout << "\t"; + ::std::cout << "\t" << rot.a31 << "\t" << rot.a32 << "\t" << rot.a33 << ::std::endl; + + ::boost::math::quaternion<float> p = R3_rotation_to_quaternion(rot, &q); + + ::std::cout << "p = " << p << ::std::endl; + + ::std::cout << "round trip discrepancy: " << ::boost::math::abs(q-p) << ::std::endl; + + ::std::cout << ::std::endl; + } + } + } + + ::std::cout << ::std::endl; +} + + +void test_SO3_semipolar() +{ + ::std::cout << "Testing semipolar:" << ::std::endl; + ::std::cout << ::std::endl; + + const float rho = 1.0f; + + float alpha; + float theta1; + float theta2; + + for (int idxalpha = 0; idxalpha <= number_of_intervals; idxalpha++) + { + alpha = (idxalpha*(pi/2))/number_of_intervals; + + for (int idxtheta1 = 0; idxtheta1 <= number_of_intervals; idxtheta1++) + { + theta1 = -pi+(idxtheta1*(2*pi))/number_of_intervals; + + for (int idxtheta2 = 0; idxtheta2 <= number_of_intervals; idxtheta2++) + { + theta2 = -pi+(idxtheta2*(2*pi))/number_of_intervals; + + ::std::cout << "alpha = " << alpha << " ; "; + ::std::cout << "theta1 = " << theta1 << " ; "; + ::std::cout << "theta2 = " << theta2; + ::std::cout << ::std::endl; + + ::boost::math::quaternion<float> q = ::boost::math::semipolar(rho, alpha, theta1, theta2); + + ::std::cout << "q = " << q << ::std::endl; + + R3_matrix<float> rot = quaternion_to_R3_rotation(q); + + ::std::cout << "rot = "; + ::std::cout << "\t" << rot.a11 << "\t" << rot.a12 << "\t" << rot.a13 << ::std::endl; + ::std::cout << "\t"; + ::std::cout << "\t" << rot.a21 << "\t" << rot.a22 << "\t" << rot.a23 << ::std::endl; + ::std::cout << "\t"; + ::std::cout << "\t" << rot.a31 << "\t" << rot.a32 << "\t" << rot.a33 << ::std::endl; + + ::boost::math::quaternion<float> p = R3_rotation_to_quaternion(rot, &q); + + ::std::cout << "p = " << p << ::std::endl; + + ::std::cout << "round trip discrepancy: " << ::boost::math::abs(q-p) << ::std::endl; + + ::std::cout << ::std::endl; + } + } + } + + ::std::cout << ::std::endl; +} + + +void test_SO3_multipolar() +{ + ::std::cout << "Testing multipolar:" << ::std::endl; + ::std::cout << ::std::endl; + + float rho1; + float rho2; + + float theta1; + float theta2; + + for (int idxrho = 0; idxrho <= number_of_intervals; idxrho++) + { + rho1 = (idxrho*1.0f)/number_of_intervals; + rho2 = ::std::sqrt(1.0f-rho1*rho1); + + for (int idxtheta1 = 0; idxtheta1 <= number_of_intervals; idxtheta1++) + { + theta1 = -pi+(idxtheta1*(2*pi))/number_of_intervals; + + for (int idxtheta2 = 0; idxtheta2 <= number_of_intervals; idxtheta2++) + { + theta2 = -pi+(idxtheta2*(2*pi))/number_of_intervals; + + ::std::cout << "rho1 = " << rho1 << " ; "; + ::std::cout << "theta1 = " << theta1 << " ; "; + ::std::cout << "theta2 = " << theta2; + ::std::cout << ::std::endl; + + ::boost::math::quaternion<float> q = ::boost::math::multipolar(rho1, theta1, rho2, theta2); + + ::std::cout << "q = " << q << ::std::endl; + + R3_matrix<float> rot = quaternion_to_R3_rotation(q); + + ::std::cout << "rot = "; + ::std::cout << "\t" << rot.a11 << "\t" << rot.a12 << "\t" << rot.a13 << ::std::endl; + ::std::cout << "\t"; + ::std::cout << "\t" << rot.a21 << "\t" << rot.a22 << "\t" << rot.a23 << ::std::endl; + ::std::cout << "\t"; + ::std::cout << "\t" << rot.a31 << "\t" << rot.a32 << "\t" << rot.a33 << ::std::endl; + + ::boost::math::quaternion<float> p = R3_rotation_to_quaternion(rot, &q); + + ::std::cout << "p = " << p << ::std::endl; + + ::std::cout << "round trip discrepancy: " << ::boost::math::abs(q-p) << ::std::endl; + + ::std::cout << ::std::endl; + } + } + } + + ::std::cout << ::std::endl; +} + + +void test_SO3_cylindrospherical() +{ + ::std::cout << "Testing cylindrospherical:" << ::std::endl; + ::std::cout << ::std::endl; + + float t; + + float radius; + float longitude; + float latitude; + + for (int idxt = 0; idxt <= number_of_intervals; idxt++) + { + t = -1.0f+(idxt*2.0f)/number_of_intervals; + radius = ::std::sqrt(1.0f-t*t); + + for (int idxlatitude = 0; idxlatitude <= number_of_intervals; idxlatitude++) + { + latitude = (-pi/2)+(idxlatitude*pi)/number_of_intervals; + + for (int idxlongitude = 0; idxlongitude <= number_of_intervals; idxlongitude++) + { + longitude = -pi+(idxlongitude*(2*pi))/number_of_intervals; + + ::std::cout << "t = " << t << " ; "; + ::std::cout << "longitude = " << longitude; + ::std::cout << "latitude = " << latitude; + ::std::cout << ::std::endl; + + ::boost::math::quaternion<float> q = ::boost::math::cylindrospherical(t, radius, longitude, latitude); + + ::std::cout << "q = " << q << ::std::endl; + + R3_matrix<float> rot = quaternion_to_R3_rotation(q); + + ::std::cout << "rot = "; + ::std::cout << "\t" << rot.a11 << "\t" << rot.a12 << "\t" << rot.a13 << ::std::endl; + ::std::cout << "\t"; + ::std::cout << "\t" << rot.a21 << "\t" << rot.a22 << "\t" << rot.a23 << ::std::endl; + ::std::cout << "\t"; + ::std::cout << "\t" << rot.a31 << "\t" << rot.a32 << "\t" << rot.a33 << ::std::endl; + + ::boost::math::quaternion<float> p = R3_rotation_to_quaternion(rot, &q); + + ::std::cout << "p = " << p << ::std::endl; + + ::std::cout << "round trip discrepancy: " << ::boost::math::abs(q-p) << ::std::endl; + + ::std::cout << ::std::endl; + } + } + } + + ::std::cout << ::std::endl; +} + + +void test_SO3_cylindrical() +{ + ::std::cout << "Testing cylindrical:" << ::std::endl; + ::std::cout << ::std::endl; + + float r; + float angle; + + float h1; + float h2; + + for (int idxh2 = 0; idxh2 <= number_of_intervals; idxh2++) + { + h2 = -1.0f+(idxh2*2.0f)/number_of_intervals; + + for (int idxh1 = 0; idxh1 <= number_of_intervals; idxh1++) + { + h1 = ::std::sqrt(1.0f-h2*h2)*(-1.0f+(idxh2*2.0f)/number_of_intervals); + r = ::std::sqrt(1.0f-h1*h1-h2*h2); + + for (int idxangle = 0; idxangle <= number_of_intervals; idxangle++) + { + angle = -pi+(idxangle*(2*pi))/number_of_intervals; + + ::std::cout << "angle = " << angle << " ; "; + ::std::cout << "h1 = " << h1; + ::std::cout << "h2 = " << h2; + ::std::cout << ::std::endl; + + ::boost::math::quaternion<float> q = ::boost::math::cylindrical(r, angle, h1, h2); + + ::std::cout << "q = " << q << ::std::endl; + + R3_matrix<float> rot = quaternion_to_R3_rotation(q); + + ::std::cout << "rot = "; + ::std::cout << "\t" << rot.a11 << "\t" << rot.a12 << "\t" << rot.a13 << ::std::endl; + ::std::cout << "\t"; + ::std::cout << "\t" << rot.a21 << "\t" << rot.a22 << "\t" << rot.a23 << ::std::endl; + ::std::cout << "\t"; + ::std::cout << "\t" << rot.a31 << "\t" << rot.a32 << "\t" << rot.a33 << ::std::endl; + + ::boost::math::quaternion<float> p = R3_rotation_to_quaternion(rot, &q); + + ::std::cout << "p = " << p << ::std::endl; + + ::std::cout << "round trip discrepancy: " << ::boost::math::abs(q-p) << ::std::endl; + + ::std::cout << ::std::endl; + } + } + } + + ::std::cout << ::std::endl; +} + + +void test_SO3() +{ + ::std::cout << "Testing SO3:" << ::std::endl; + ::std::cout << ::std::endl; + + test_SO3_spherical(); + + test_SO3_semipolar(); + + test_SO3_multipolar(); + + test_SO3_cylindrospherical(); + + test_SO3_cylindrical(); +} + + +// +// Test of quaternion and R^4 rotation relationship +// + +void test_SO4_spherical() +{ + ::std::cout << "Testing spherical:" << ::std::endl; + ::std::cout << ::std::endl; + + const float rho1 = 1.0f; + const float rho2 = 1.0f; + + float theta1; + float phi11; + float phi21; + + float theta2; + float phi12; + float phi22; + + for (int idxphi21 = 0; idxphi21 <= number_of_intervals; idxphi21++) + { + phi21 = (-pi/2)+(idxphi21*pi)/number_of_intervals; + + for (int idxphi22 = 0; idxphi22 <= number_of_intervals; idxphi22++) + { + phi22 = (-pi/2)+(idxphi22*pi)/number_of_intervals; + + for (int idxphi11 = 0; idxphi11 <= number_of_intervals; idxphi11++) + { + phi11 = (-pi/2)+(idxphi11*pi)/number_of_intervals; + + for (int idxphi12 = 0; idxphi12 <= number_of_intervals; idxphi12++) + { + phi12 = (-pi/2)+(idxphi12*pi)/number_of_intervals; + + for (int idxtheta1 = 0; idxtheta1 <= number_of_intervals; idxtheta1++) + { + theta1 = -pi+(idxtheta1*(2*pi))/number_of_intervals; + + for (int idxtheta2 = 0; idxtheta2 <= number_of_intervals; idxtheta2++) + { + theta2 = -pi+(idxtheta2*(2*pi))/number_of_intervals; + + ::std::cout << "theta1 = " << theta1 << " ; "; + ::std::cout << "phi11 = " << phi11 << " ; "; + ::std::cout << "phi21 = " << phi21; + ::std::cout << "theta2 = " << theta2 << " ; "; + ::std::cout << "phi12 = " << phi12 << " ; "; + ::std::cout << "phi22 = " << phi22; + ::std::cout << ::std::endl; + + ::boost::math::quaternion<float> p1 = ::boost::math::spherical(rho1, theta1, phi11, phi21); + + ::std::cout << "p1 = " << p1 << ::std::endl; + + ::boost::math::quaternion<float> q1 = ::boost::math::spherical(rho2, theta2, phi12, phi22); + + ::std::cout << "q1 = " << q1 << ::std::endl; + + ::std::pair< ::boost::math::quaternion<float> , ::boost::math::quaternion<float> > pq1 = + ::std::make_pair(p1,q1); + + R4_matrix<float> rot = quaternions_to_R4_rotation(pq1); + + ::std::cout << "rot = "; + ::std::cout << "\t" << rot.a11 << "\t" << rot.a12 << "\t" << rot.a13 << "\t" << rot.a14 << ::std::endl; + ::std::cout << "\t"; + ::std::cout << "\t" << rot.a21 << "\t" << rot.a22 << "\t" << rot.a23 << "\t" << rot.a24 << ::std::endl; + ::std::cout << "\t"; + ::std::cout << "\t" << rot.a31 << "\t" << rot.a32 << "\t" << rot.a33 << "\t" << rot.a34 << ::std::endl; + ::std::cout << "\t"; + ::std::cout << "\t" << rot.a41 << "\t" << rot.a42 << "\t" << rot.a43 << "\t" << rot.a44 << ::std::endl; + + ::std::pair< ::boost::math::quaternion<float> , ::boost::math::quaternion<float> > pq2 = + R4_rotation_to_quaternions(rot, &pq1); + + ::std::cout << "p1 = " << pq2.first << ::std::endl; + ::std::cout << "p2 = " << pq2.second << ::std::endl; + + ::std::cout << "round trip discrepancy: " << ::std::sqrt(::boost::math::norm(pq1.first-pq2.first)+::boost::math::norm(pq1.second-pq2.second)) << ::std::endl; + + ::std::cout << ::std::endl; + } + } + } + } + } + } + + ::std::cout << ::std::endl; +} + + +void test_SO4() +{ + ::std::cout << "Testing SO4:" << ::std::endl; + ::std::cout << ::std::endl; + + test_SO4_spherical(); +} + + diff --git a/src/boost/libs/math/example/HSO4.hpp b/src/boost/libs/math/example/HSO4.hpp new file mode 100644 index 000000000..e7171b815 --- /dev/null +++ b/src/boost/libs/math/example/HSO4.hpp @@ -0,0 +1,183 @@ + +/********************************************************************************************/ +/* */ +/* HSO4.hpp header file */ +/* */ +/* This file is not currently part of the Boost library. It is simply an example of the use */ +/* quaternions can be put to. Hopefully it will be useful too. */ +/* */ +/* This file provides tools to convert between quaternions and R^4 rotation matrices. */ +/* */ +/********************************************************************************************/ + +// (C) Copyright Hubert Holin 2001. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef TEST_HSO4_HPP +#define TEST_HSO4_HPP + +#include <utility> + +#include "HSO3.hpp" + + +template<typename TYPE_FLOAT> +struct R4_matrix +{ + TYPE_FLOAT a11, a12, a13, a14; + TYPE_FLOAT a21, a22, a23, a24; + TYPE_FLOAT a31, a32, a33, a34; + TYPE_FLOAT a41, a42, a43, a44; +}; + + +// Note: the input quaternions need not be of norm 1 for the following function + +template<typename TYPE_FLOAT> +R4_matrix<TYPE_FLOAT> quaternions_to_R4_rotation(::std::pair< ::boost::math::quaternion<TYPE_FLOAT> , ::boost::math::quaternion<TYPE_FLOAT> > const & pq) +{ + using ::std::numeric_limits; + + TYPE_FLOAT a0 = pq.first.R_component_1(); + TYPE_FLOAT b0 = pq.first.R_component_2(); + TYPE_FLOAT c0 = pq.first.R_component_3(); + TYPE_FLOAT d0 = pq.first.R_component_4(); + + TYPE_FLOAT norme_carre0 = a0*a0+b0*b0+c0*c0+d0*d0; + + if (norme_carre0 <= numeric_limits<TYPE_FLOAT>::epsilon()) + { + ::std::string error_reporting("Argument to quaternions_to_R4_rotation is too small!"); + ::std::underflow_error bad_argument(error_reporting); + + throw(bad_argument); + } + + TYPE_FLOAT a1 = pq.second.R_component_1(); + TYPE_FLOAT b1 = pq.second.R_component_2(); + TYPE_FLOAT c1 = pq.second.R_component_3(); + TYPE_FLOAT d1 = pq.second.R_component_4(); + + TYPE_FLOAT norme_carre1 = a1*a1+b1*b1+c1*c1+d1*d1; + + if (norme_carre1 <= numeric_limits<TYPE_FLOAT>::epsilon()) + { + ::std::string error_reporting("Argument to quaternions_to_R4_rotation is too small!"); + ::std::underflow_error bad_argument(error_reporting); + + throw(bad_argument); + } + + TYPE_FLOAT prod_norm = norme_carre0*norme_carre1; + + TYPE_FLOAT a0a1 = a0*a1; + TYPE_FLOAT a0b1 = a0*b1; + TYPE_FLOAT a0c1 = a0*c1; + TYPE_FLOAT a0d1 = a0*d1; + TYPE_FLOAT b0a1 = b0*a1; + TYPE_FLOAT b0b1 = b0*b1; + TYPE_FLOAT b0c1 = b0*c1; + TYPE_FLOAT b0d1 = b0*d1; + TYPE_FLOAT c0a1 = c0*a1; + TYPE_FLOAT c0b1 = c0*b1; + TYPE_FLOAT c0c1 = c0*c1; + TYPE_FLOAT c0d1 = c0*d1; + TYPE_FLOAT d0a1 = d0*a1; + TYPE_FLOAT d0b1 = d0*b1; + TYPE_FLOAT d0c1 = d0*c1; + TYPE_FLOAT d0d1 = d0*d1; + + R4_matrix<TYPE_FLOAT> out_matrix; + + out_matrix.a11 = (+a0a1+b0b1+c0c1+d0d1)/prod_norm; + out_matrix.a12 = (+a0b1-b0a1-c0d1+d0c1)/prod_norm; + out_matrix.a13 = (+a0c1+b0d1-c0a1-d0b1)/prod_norm; + out_matrix.a14 = (+a0d1-b0c1+c0b1-d0a1)/prod_norm; + out_matrix.a21 = (-a0b1+b0a1-c0d1+d0c1)/prod_norm; + out_matrix.a22 = (+a0a1+b0b1-c0c1-d0d1)/prod_norm; + out_matrix.a23 = (-a0d1+b0c1+c0b1-d0a1)/prod_norm; + out_matrix.a24 = (+a0c1+b0d1+c0a1+d0b1)/prod_norm; + out_matrix.a31 = (-a0c1+b0d1+c0a1-d0b1)/prod_norm; + out_matrix.a32 = (+a0d1+b0c1+c0b1+d0a1)/prod_norm; + out_matrix.a33 = (+a0a1-b0b1+c0c1-d0d1)/prod_norm; + out_matrix.a34 = (-a0b1-b0a1+c0d1+d0c1)/prod_norm; + out_matrix.a41 = (-a0d1-b0c1+c0b1+d0a1)/prod_norm; + out_matrix.a42 = (-a0c1+b0d1-c0a1+d0b1)/prod_norm; + out_matrix.a43 = (+a0b1+b0a1+c0d1+d0c1)/prod_norm; + out_matrix.a44 = (+a0a1-b0b1-c0c1+d0d1)/prod_norm; + + return(out_matrix); +} + + +template<typename TYPE_FLOAT> +inline bool is_R4_rotation_matrix(R4_matrix<TYPE_FLOAT> const & mat) +{ + using ::std::abs; + + using ::std::numeric_limits; + + return ( + !( + (abs(mat.a11*mat.a11+mat.a21*mat.a21+mat.a31*mat.a31+mat.a41*mat.a41 - static_cast<TYPE_FLOAT>(1)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + (abs(mat.a11*mat.a12+mat.a21*mat.a22+mat.a31*mat.a32+mat.a41*mat.a42 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + (abs(mat.a11*mat.a13+mat.a21*mat.a23+mat.a31*mat.a33+mat.a41*mat.a43 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + (abs(mat.a11*mat.a14+mat.a21*mat.a24+mat.a31*mat.a34+mat.a41*mat.a44 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + //(abs(mat.a11*mat.a12+mat.a21*mat.a22+mat.a31*mat.a32+mat.a41*mat.a42 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + (abs(mat.a12*mat.a12+mat.a22*mat.a22+mat.a32*mat.a32+mat.a42*mat.a42 - static_cast<TYPE_FLOAT>(1)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + (abs(mat.a12*mat.a13+mat.a22*mat.a23+mat.a32*mat.a33+mat.a42*mat.a43 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + (abs(mat.a12*mat.a14+mat.a22*mat.a24+mat.a32*mat.a34+mat.a42*mat.a44 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + //(abs(mat.a11*mat.a13+mat.a21*mat.a23+mat.a31*mat.a33+mat.a41*mat.a43 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + //(abs(mat.a12*mat.a13+mat.a22*mat.a23+mat.a32*mat.a33+mat.a42*mat.a43 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + (abs(mat.a13*mat.a13+mat.a23*mat.a23+mat.a33*mat.a33+mat.a43*mat.a43 - static_cast<TYPE_FLOAT>(1)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + (abs(mat.a13*mat.a14+mat.a23*mat.a24+mat.a33*mat.a34+mat.a43*mat.a44 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + //(abs(mat.a11*mat.a14+mat.a21*mat.a24+mat.a31*mat.a34+mat.a41*mat.a44 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + //(abs(mat.a12*mat.a14+mat.a22*mat.a24+mat.a32*mat.a34+mat.a42*mat.a44 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + //(abs(mat.a13*mat.a14+mat.a23*mat.a24+mat.a33*mat.a34+mat.a43*mat.a44 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())|| + (abs(mat.a14*mat.a14+mat.a24*mat.a24+mat.a34*mat.a34+mat.a44*mat.a44 - static_cast<TYPE_FLOAT>(1)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon()) + ) + ); +} + + +template<typename TYPE_FLOAT> +::std::pair< ::boost::math::quaternion<TYPE_FLOAT> , ::boost::math::quaternion<TYPE_FLOAT> > R4_rotation_to_quaternions( R4_matrix<TYPE_FLOAT> const & rot, + ::std::pair< ::boost::math::quaternion<TYPE_FLOAT> , ::boost::math::quaternion<TYPE_FLOAT> > const * hint = 0) +{ + if (!is_R4_rotation_matrix(rot)) + { + ::std::string error_reporting("Argument to R4_rotation_to_quaternions is not an R^4 rotation matrix!"); + ::std::range_error bad_argument(error_reporting); + + throw(bad_argument); + } + + R3_matrix<TYPE_FLOAT> mat; + + mat.a11 = -rot.a31*rot.a42+rot.a32*rot.a41+rot.a22*rot.a11-rot.a21*rot.a12; + mat.a12 = -rot.a31*rot.a43+rot.a33*rot.a41+rot.a23*rot.a11-rot.a21*rot.a13; + mat.a13 = -rot.a31*rot.a44+rot.a34*rot.a41+rot.a24*rot.a11-rot.a21*rot.a14; + mat.a21 = -rot.a31*rot.a12-rot.a22*rot.a41+rot.a32*rot.a11+rot.a21*rot.a42; + mat.a22 = -rot.a31*rot.a13-rot.a23*rot.a41+rot.a33*rot.a11+rot.a21*rot.a43; + mat.a23 = -rot.a31*rot.a14-rot.a24*rot.a41+rot.a34*rot.a11+rot.a21*rot.a44; + mat.a31 = +rot.a31*rot.a22-rot.a12*rot.a41+rot.a42*rot.a11-rot.a21*rot.a32; + mat.a32 = +rot.a31*rot.a23-rot.a13*rot.a41+rot.a43*rot.a11-rot.a21*rot.a33; + mat.a33 = +rot.a31*rot.a24-rot.a14*rot.a41+rot.a44*rot.a11-rot.a21*rot.a34; + + ::boost::math::quaternion<TYPE_FLOAT> q = R3_rotation_to_quaternion(mat); + + ::boost::math::quaternion<TYPE_FLOAT> p = + ::boost::math::quaternion<TYPE_FLOAT>(rot.a11,rot.a12,rot.a13,rot.a14)*q; + + if ((hint != 0) && (abs(hint->second+q) < abs(hint->second-q))) + { + return(::std::make_pair(-p,-q)); + } + + return(::std::make_pair(p,q)); +} + +#endif /* TEST_HSO4_HPP */ + diff --git a/src/boost/libs/math/example/Jamfile.v2 b/src/boost/libs/math/example/Jamfile.v2 new file mode 100644 index 000000000..fd40f3982 --- /dev/null +++ b/src/boost/libs/math/example/Jamfile.v2 @@ -0,0 +1,159 @@ +# \libs\math\example\jamfile.v2 +# Runs statistics and floating-point examples. +# Copyright 2007 John Maddock +# Copyright Paul A. Bristow 2007, 2010, 2011. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +# bring in the rules for testing +import testing ; +import ../../config/checks/config : requires ; + +project + : requirements + <toolset>gcc:<cxxflags>-Wno-missing-braces + <toolset>darwin:<cxxflags>-Wno-missing-braces + <toolset>acc:<cxxflags>+W2068,2461,2236,4070 + <toolset>intel:<cxxflags>-Qwd264,239 + <toolset>msvc:<warnings>all + <toolset>msvc:<asynch-exceptions>on + <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE + <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE + <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS + <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS + <toolset>msvc:<cxxflags>/wd4996 + <toolset>msvc:<cxxflags>/wd4512 + <toolset>msvc:<cxxflags>/wd4610 + <toolset>msvc:<cxxflags>/wd4510 + <toolset>msvc:<cxxflags>/wd4127 + <toolset>msvc:<cxxflags>/wd4701 + <toolset>msvc:<cxxflags>/wd4127 + <toolset>msvc:<cxxflags>/wd4305 + <toolset>msvc:<cxxflags>/wd4459 + <toolset>msvc:<cxxflags>/wd4456 # declaration of hides previous local declaration. + #-<toolset>msvc:<cxxflags>/Za # nonfinite Serialization examples fail link if disable MS extensions, + # because serialization library is built with MS extensions enabled (default). + <toolset>clang:<cxxflags>-Wno-unknown-pragmas + <toolset>clang:<cxxflags>-Wno-language-extension-token + + <include>../../.. + <include>../include_private + <exception-handling>off:<source>../test//no_eh + ; + +test-suite examples : + [ run bessel_zeros_example_1.cpp : : : <exception-handling>off:<build>no ] + [ run bessel_zeros_interator_example.cpp : : : <exception-handling>off:<build>no ] + [ run neumann_zeros_example_1.cpp : : : <exception-handling>off:<build>no ] + + [ run test_cpp_float_close_fraction.cpp ../../test/build//boost_unit_test_framework/<link>static : : : <exception-handling>off:<build>no ] + [ run binomial_coinflip_example.cpp : : : <exception-handling>off:<build>no ] + [ run binomial_confidence_limits.cpp ] + [ run binomial_example_nag.cpp ] + [ run binomial_quiz_example.cpp : : : <exception-handling>off:<build>no ] + [ run binomial_sample_sizes.cpp ] + [ run brent_minimise_example.cpp : : : [ requires cxx11_hdr_tuple ] ] + + [ run c_error_policy_example.cpp ] + [ run chi_square_std_dev_test.cpp : : : <exception-handling>off:<build>no ] + [ run distribution_construction.cpp : : : <exception-handling>off:<build>no ] + [ run error_handling_example.cpp : : : <exception-handling>off:<build>no ] + [ run error_policies_example.cpp ] + [ run error_policy_example.cpp : : : <exception-handling>off:<build>no ] + [ run f_test.cpp ] + # [ run fft_sines_table.cpp : : : [ requires cxx11_numeric_limits ] ] + # No need to re-run this routinely as it only creates a table of sines for a documentation example. + + [ run find_location_example.cpp : : : <exception-handling>off:<build>no ] + [ run find_mean_and_sd_normal.cpp : : : <exception-handling>off:<build>no ] + [ run find_root_example.cpp : : : <exception-handling>off:<build>no ] + [ run find_scale_example.cpp : : : <exception-handling>off:<build>no ] + [ run geometric_examples.cpp : : : <exception-handling>off:<build>no ] + [ run hyperexponential_snips.cpp ] + [ run hyperexponential_more_snips.cpp ] + [ run inverse_chi_squared_example.cpp ] + [ run legendre_stieltjes_example.cpp : : : [ requires cxx11_auto_declarations cxx11_defaulted_functions cxx11_lambdas ] ] + #[ # run inverse_chi_squared_find_df_example.cpp ] + #[ run lambert_w_basic_example.cpp ] + [ run lambert_w_basic_example.cpp : : : [ requires cxx11_numeric_limits ] ] + [ run lambert_w_simple_examples.cpp : : : [ requires cxx11_numeric_limits ] ] + [ run lambert_w_precision_example.cpp : : : [ check-target-builds ../config//has_float128 "GCC libquadmath and __float128 support" : <linkflags>-lquadmath ] [ requires cxx11_numeric_limits cxx11_explicit_conversion_operators ] ] + + [ run inverse_gamma_example.cpp ] + [ run inverse_gamma_distribution_example.cpp : : : <exception-handling>off:<build>no ] + [ run laplace_example.cpp : : : <exception-handling>off:<build>no ] + [ run nc_chi_sq_example.cpp ] + [ run neg_binom_confidence_limits.cpp ] + [ run neg_binomial_sample_sizes.cpp ] + [ run negative_binomial_example1.cpp : : : <exception-handling>off:<build>no ] + [ run negative_binomial_example2.cpp ] + + [ run nonfinite_num_facet.cpp ] + [ run nonfinite_facet_simple.cpp ] + [ run nonfinite_num_facet_serialization.cpp ../../serialization/build//boost_serialization : : : <exception-handling>off:<build>no <toolset>gcc-mingw:<link>static ] + #[ # run lexical_cast_native.cpp ] # Expected to fail on some (but not all) platforms. + [ run lexical_cast_nonfinite_facets.cpp ] + [ run nonfinite_loopback_ok.cpp ] + [ run nonfinite_serialization_archives.cpp ../../serialization/build//boost_serialization : : : <exception-handling>off:<build>no <toolset>gcc-mingw:<link>static ] + [ run nonfinite_facet_sstream.cpp ] + + [ run constants_eg1.cpp ] + + [ run normal_misc_examples.cpp : : : <exception-handling>off:<build>no ] + [ run owens_t_example.cpp ] + [ run policy_eg_1.cpp ] + [ run policy_eg_10.cpp : : : <target-os>vxworks:<build>no ] # VxWorks' complex.h has conflicting declaration of real + [ run policy_eg_2.cpp ] + [ run policy_eg_3.cpp ] + [ run policy_eg_4.cpp ] + [ run policy_eg_5.cpp ] + [ run policy_eg_6.cpp ] + [ run policy_eg_7.cpp ] + [ run policy_eg_8.cpp ] + [ run policy_eg_9.cpp ] + [ run policy_ref_snip1.cpp : : : <exception-handling>off:<build>no ] + [ run policy_ref_snip10.cpp ] + [ run policy_ref_snip11.cpp ] + [ run policy_ref_snip12.cpp ] + [ run policy_ref_snip13.cpp : : : <exception-handling>off:<build>no ] # Fails clang-win - thrown exception from no Cauchy mean. + [ run policy_ref_snip2.cpp ] + [ run policy_ref_snip3.cpp : : : <exception-handling>off:<build>no ] + [ run policy_ref_snip4.cpp ] + [ run policy_ref_snip5.cpp : : : <target-os>vxworks:<build>no ] + [ run policy_ref_snip6.cpp ] + [ run policy_ref_snip7.cpp ] + [ run policy_ref_snip8.cpp ] + [ run policy_ref_snip9.cpp ] + [ run skew_normal_example.cpp ] + [ run students_t_example1.cpp ] + [ run students_t_example2.cpp ] + [ run students_t_example3.cpp ] + [ run students_t_single_sample.cpp ] + [ run students_t_two_samples.cpp ] + [ run HSO3SO4.cpp ] + [ run series.cpp ] + [ run continued_fractions.cpp ] + + [ run barycentric_interpolation_example.cpp : : : [ requires cxx11_smart_ptr cxx11_function_template_default_args cxx11_unified_initialization_syntax cxx11_defaulted_functions cxx11_allocator cxx11_auto_declarations cxx11_lambdas ] ] + [ run barycentric_interpolation_example_2.cpp : : : [ requires cxx11_smart_ptr cxx11_function_template_default_args cxx11_unified_initialization_syntax cxx11_defaulted_functions cxx11_allocator cxx11_auto_declarations cxx11_lambdas ] ] + [ run cardinal_cubic_b_spline_example.cpp : : : [ requires cxx11_smart_ptr cxx11_hdr_random cxx11_defaulted_functions ] ] + [ compile naive_monte_carlo_example.cpp : [ requires cxx11_auto_declarations cxx11_lambdas cxx11_unified_initialization_syntax cxx11_hdr_thread cxx11_hdr_atomic cxx11_decltype cxx11_hdr_future cxx11_hdr_chrono cxx11_hdr_random cxx11_allocator ] ] # requires user input, can't run it, take a long time too! + [ run catmull_rom_example.cpp : : : [ requires cxx17_if_constexpr cxx11_auto_declarations cxx17_std_apply ] ] # Actually the C++17 features used is std::size, not if constexpr; looks like there isn't yet a test for it. + [ run autodiff_black_scholes_brief.cpp : : : [ requires cxx11_inline_namespaces ] ] + [ run autodiff_black_scholes.cpp : : : [ requires cxx11_inline_namespaces ] ] + [ run autodiff_fourth_power.cpp : : : [ requires cxx11_inline_namespaces ] ] + [ run autodiff_mixed_partials.cpp : : : [ requires cxx11_inline_namespaces ] ] + [ run autodiff_multiprecision.cpp : : : [ requires cxx11_inline_namespaces ] ] + [ run ooura_fourier_integrals_example.cpp : : : [ requires cxx11_hdr_mutex cxx11_lambdas cxx11_inline_namespaces cxx11_auto_declarations ] ] + [ run ooura_fourier_integrals_cosine_example.cpp : : : [ requires cxx11_hdr_mutex cxx11_inline_namespaces cxx11_auto_declarations cxx17_std_apply ] ] + [ run ooura_fourier_integrals_multiprecision_example.cpp : : : [ check-target-builds ../config//has_float128 "GCC libquadmath and __float128 support" : <linkflags>-lquadmath ] [ requires cxx11_hdr_mutex cxx11_inline_namespaces cxx11_auto_declarations cxx17_std_apply ] ] + +; + +run root_elliptic_finding.cpp /boost/timer : : : release <link>static [ requires cxx11_unified_initialization_syntax cxx11_defaulted_functions ] <target-os>freebsd:<linkflags>"-lrt" <target-os>linux:<linkflags>"-lrt -lpthread" ; +run root_finding_algorithms.cpp /boost/timer : : : release <link>static [ requires cxx11_hdr_tuple cxx11_unified_initialization_syntax ] <target-os>freebsd:<linkflags>"-lrt" <target-os>linux:<linkflags>"-lrt -lpthread" ; +run root_n_finding_algorithms.cpp /boost/timer : : : release <link>static [ requires cxx11_unified_initialization_syntax cxx11_defaulted_functions ] <target-os>freebsd:<linkflags>"-lrt" <target-os>linux:<linkflags>"-lrt -lpthread" ; + +explicit root_elliptic_finding ; +explicit root_finding_algorithms ; +explicit root_n_finding_algorithms ; diff --git a/src/boost/libs/math/example/airy_zeros_example.cpp b/src/boost/libs/math/example/airy_zeros_example.cpp new file mode 100644 index 000000000..3ab2c77d5 --- /dev/null +++ b/src/boost/libs/math/example/airy_zeros_example.cpp @@ -0,0 +1,165 @@ + +// Copyright Christopher Kormanyos 2013. +// Copyright Paul A. Bristow 2013. +// Copyright John Maddock 2013. + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http://www.boost.org/LICENSE_1_0.txt). + +#ifdef _MSC_VER +# pragma warning (disable : 4512) // assignment operator could not be generated. +# pragma warning (disable : 4996) // assignment operator could not be generated. +#endif + +#include <iostream> +#include <limits> +#include <vector> +#include <algorithm> +#include <iomanip> +#include <iterator> + +// Weisstein, Eric W. "Bessel Function Zeros." From MathWorld--A Wolfram Web Resource. +// http://mathworld.wolfram.com/BesselFunctionZeros.html +// Test values can be calculated using [@wolframalpha.com WolframAplha] +// See also http://dlmf.nist.gov/10.21 + +//[airy_zeros_example_1 + +/*`This example demonstrates calculating zeros of the Airy functions. +It also shows how Boost.Math and Boost.Multiprecision can be combined to provide +a many decimal digit precision. For 50 decimal digit precision we need to include +*/ + + #include <boost/multiprecision/cpp_dec_float.hpp> + +/*`and a `typedef` for `float_type` may be convenient +(allowing a quick switch to re-compute at built-in `double` or other precision) +*/ + typedef boost::multiprecision::cpp_dec_float_50 float_type; + +//`To use the functions for finding zeros of the functions we need + + #include <boost/math/special_functions/airy.hpp> + +/*`This example shows obtaining both a single zero of the Airy functions, +and then placing multiple zeros into a container like `std::vector` by providing an iterator. +The signature of the single-value Airy Ai function is: + + template <class T> + T airy_ai_zero(unsigned m); // 1-based index of the zero. + +The signature of multiple zeros Airy Ai function is: + + template <class T, class OutputIterator> + OutputIterator airy_ai_zero( + unsigned start_index, // 1-based index of the zero. + unsigned number_of_zeros, // How many zeros to generate. + OutputIterator out_it); // Destination for zeros. + +There are also versions which allows control of the __policy_section for error handling and precision. + + template <class T, class OutputIterator, class Policy> + OutputIterator airy_ai_zero( + unsigned start_index, // 1-based index of the zero. + unsigned number_of_zeros, // How many zeros to generate. + OutputIterator out_it, // Destination for zeros. + const Policy& pol); // Policy to use. +*/ +//] [/airy_zeros_example_1] + +int main() +{ + try + { +//[airy_zeros_example_2 + +/*`[tip It is always wise to place code using Boost.Math inside `try'n'catch` blocks; +this will ensure that helpful error messages are shown when exceptional conditions arise.] + +First, evaluate a single Airy zero. + +The precision is controlled by the template parameter `T`, +so this example has `double` precision, at least 15 but up to 17 decimal digits +(for the common 64-bit double). +*/ + double aiz1 = boost::math::airy_ai_zero<double>(1); + std::cout << "boost::math::airy_ai_zero<double>(1) = " << aiz1 << std::endl; + double aiz2 = boost::math::airy_ai_zero<double>(2); + std::cout << "boost::math::airy_ai_zero<double>(2) = " << aiz2 << std::endl; + double biz3 = boost::math::airy_bi_zero<double>(3); + std::cout << "boost::math::airy_bi_zero<double>(3) = " << biz3 << std::endl; + +/*`Other versions of `airy_ai_zero` and `airy_bi_zero` +allow calculation of multiple zeros with one call, +placing the results in a container, often `std::vector`. +For example, generate and display the first five `double` roots +[@http://mathworld.wolfram.com/AiryFunctionZeros.html Wolfram Airy Functions Zeros]. +*/ + unsigned int n_roots = 5U; + std::vector<double> roots; + boost::math::airy_ai_zero<double>(1U, n_roots, std::back_inserter(roots)); + std::cout << "airy_ai_zeros:" << std::endl; + std::copy(roots.begin(), + roots.end(), + std::ostream_iterator<double>(std::cout, "\n")); + +/*`The first few real roots of Ai(x) are approximately -2.33811, -4.08795, -5.52056, -6.7867144, -7.94413, -9.02265 ... + +Or we can use Boost.Multiprecision to generate 50 decimal digit roots. + +We set the precision of the output stream, and show trailing zeros to display a fixed 50 decimal digits. +*/ + std::cout.precision(std::numeric_limits<float_type>::digits10); // float_type has 50 decimal digits. + std::cout << std::showpoint << std::endl; // Show trailing zeros too. + + unsigned int m = 1U; + float_type r = boost::math::airy_ai_zero<float_type>(1U); // 1st root. + std::cout << "boost::math::airy_bi_zero<float_type>(" << m << ") = " << r << std::endl; + m = 2; + r = boost::math::airy_ai_zero<float_type>(2U); // 2nd root. + std::cout << "boost::math::airy_bi_zero<float_type>(" << m << ") = " << r << std::endl; + m = 7U; + r = boost::math::airy_bi_zero<float_type>(7U); // 7th root. + std::cout << "boost::math::airy_bi_zero<float_type>(" << m << ") = " << r << std::endl; + + std::vector<float_type> zeros; + boost::math::airy_ai_zero<float_type>(1U, 3, std::back_inserter(zeros)); + std::cout << "airy_ai_zeros:" << std::endl; + // Print the roots to the output stream. + std::copy(zeros.begin(), zeros.end(), + std::ostream_iterator<float_type>(std::cout, "\n")); +//] [/airy_zeros_example_2] + } + catch (std::exception ex) + { + std::cout << "Thrown exception " << ex.what() << std::endl; + } + + } // int main() + +/* + + Output: + + Description: Autorun "J:\Cpp\big_number\Debug\airy_zeros_example.exe" + boost::math::airy_ai_zero<double>(1) = -2.33811 + boost::math::airy_ai_zero<double>(2) = -4.08795 + boost::math::airy_bi_zero<double>(3) = -4.83074 + airy_ai_zeros: + -2.33811 + -4.08795 + -5.52056 + -6.78671 + -7.94413 + + boost::math::airy_bi_zero<float_type>(1) = -2.3381074104597670384891972524467354406385401456711 + boost::math::airy_bi_zero<float_type>(2) = -4.0879494441309706166369887014573910602247646991085 + boost::math::airy_bi_zero<float_type>(7) = -9.5381943793462388866329885451560196208390720763825 + airy_ai_zeros: + -2.3381074104597670384891972524467354406385401456711 + -4.0879494441309706166369887014573910602247646991085 + -5.5205598280955510591298555129312935737972142806175 + +*/ + diff --git a/src/boost/libs/math/example/arcsine_example.cpp b/src/boost/libs/math/example/arcsine_example.cpp new file mode 100644 index 000000000..aa757f3ea --- /dev/null +++ b/src/boost/libs/math/example/arcsine_example.cpp @@ -0,0 +1,89 @@ +// arcsine_example.cpp + +// Copyright John Maddock 2014. +// Copyright Paul A. Bristow 2014. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Example for the arcsine Distribution. + +// Note: Contains Quickbook snippets in comments. + +//[arcsine_snip_1 +#include <boost/math/distributions/arcsine.hpp> // For arcsine_distribution. +//] [/arcsine_snip_1] + +#include <iostream> +#include <exception> +#include <boost/assert.hpp> + +int main() +{ + std::cout << "Examples of Arcsine distribution." << std::endl; + std::cout.precision(3); // Avoid uninformative decimal digits. + + using boost::math::arcsine; + + arcsine as; // Construct a default `double` standard [0, 1] arcsine distribution. + +//[arcsine_snip_2 + std::cout << pdf(as, 1. / 2) << std::endl; // 0.637 + // pdf has a minimum at x = 0.5 +//] [/arcsine_snip_2] + +//[arcsine_snip_3 + std::cout << pdf(as, 1. / 4) << std::endl; // 0.735 +//] [/arcsine_snip_3] + + +//[arcsine_snip_4 + std::cout << cdf(as, 0.05) << std::endl; // 0.144 +//] [/arcsine_snip_4] + +//[arcsine_snip_5 + std::cout << 2 * cdf(as, 1 - 0.975) << std::endl; // 0.202 +//] [/arcsine_snip_5] + + +//[arcsine_snip_6 + std::cout << 2 * cdf(complement(as, 0.975)) << std::endl; // 0.202 +//] [/arcsine_snip_6] + +//[arcsine_snip_7 + std::cout << quantile(as, 1 - 0.2 / 2) << std::endl; // 0.976 + + std::cout << quantile(complement(as, 0.2 / 2)) << std::endl; // 0.976 +//] [/arcsine_snip_7] + +{ +//[arcsine_snip_8 + using boost::math::arcsine_distribution; + + arcsine_distribution<> as(2, 5); // Constructs a double arcsine distribution. + BOOST_ASSERT(as.x_min() == 2.); // as.x_min() returns 2. + BOOST_ASSERT(as.x_max() == 5.); // as.x_max() returns 5. +//] [/arcsine_snip_8] +} + return 0; + +} // int main() + +/* +[arcsine_output + +Example of Arcsine distribution +0.637 +0.735 +0.144 +0.202 +0.202 +0.976 +0.976 + +] [/arcsine_output] +*/ + + diff --git a/src/boost/libs/math/example/autodiff_black_scholes.cpp b/src/boost/libs/math/example/autodiff_black_scholes.cpp new file mode 100644 index 000000000..b7fcd9c0a --- /dev/null +++ b/src/boost/libs/math/example/autodiff_black_scholes.cpp @@ -0,0 +1,195 @@ +// Copyright Matthew Pulver 2018 - 2019. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +#include <boost/math/differentiation/autodiff.hpp> +#include <iostream> +#include <stdexcept> + +using namespace boost::math::constants; +using namespace boost::math::differentiation; + +// Equations and function/variable names are from +// https://en.wikipedia.org/wiki/Greeks_(finance)#Formulas_for_European_option_Greeks + +// Standard normal probability density function +template <typename X> +X phi(X const& x) { + return one_div_root_two_pi<X>() * exp(-0.5 * x * x); +} + +// Standard normal cumulative distribution function +template <typename X> +X Phi(X const& x) { + return 0.5 * erfc(-one_div_root_two<X>() * x); +} + +enum class CP { call, put }; + +// Assume zero annual dividend yield (q=0). +template <typename Price, typename Sigma, typename Tau, typename Rate> +promote<Price, Sigma, Tau, Rate> black_scholes_option_price(CP cp, + double K, + Price const& S, + Sigma const& sigma, + Tau const& tau, + Rate const& r) { + using namespace std; + auto const d1 = (log(S / K) + (r + sigma * sigma / 2) * tau) / (sigma * sqrt(tau)); + auto const d2 = (log(S / K) + (r - sigma * sigma / 2) * tau) / (sigma * sqrt(tau)); + switch (cp) { + case CP::call: + return S * Phi(d1) - exp(-r * tau) * K * Phi(d2); + case CP::put: + return exp(-r * tau) * K * Phi(-d2) - S * Phi(-d1); + default: + throw std::runtime_error("Invalid CP value."); + } +} + +int main() { + double const K = 100.0; // Strike price. + auto const variables = make_ftuple<double, 3, 3, 1, 1>(105, 5, 30.0 / 365, 1.25 / 100); + auto const& S = std::get<0>(variables); // Stock price. + auto const& sigma = std::get<1>(variables); // Volatility. + auto const& tau = std::get<2>(variables); // Time to expiration in years. (30 days). + auto const& r = std::get<3>(variables); // Interest rate. + auto const call_price = black_scholes_option_price(CP::call, K, S, sigma, tau, r); + auto const put_price = black_scholes_option_price(CP::put, K, S, sigma, tau, r); + + double const d1 = static_cast<double>((log(S / K) + (r + sigma * sigma / 2) * tau) / (sigma * sqrt(tau))); + double const d2 = static_cast<double>((log(S / K) + (r - sigma * sigma / 2) * tau) / (sigma * sqrt(tau))); + double const formula_call_delta = +Phi(+d1); + double const formula_put_delta = -Phi(-d1); + double const formula_vega = static_cast<double>(S * phi(d1) * sqrt(tau)); + double const formula_call_theta = + static_cast<double>(-S * phi(d1) * sigma / (2 * sqrt(tau)) - r * K * exp(-r * tau) * Phi(+d2)); + double const formula_put_theta = + static_cast<double>(-S * phi(d1) * sigma / (2 * sqrt(tau)) + r * K * exp(-r * tau) * Phi(-d2)); + double const formula_call_rho = static_cast<double>(+K * tau * exp(-r * tau) * Phi(+d2)); + double const formula_put_rho = static_cast<double>(-K * tau * exp(-r * tau) * Phi(-d2)); + double const formula_gamma = static_cast<double>(phi(d1) / (S * sigma * sqrt(tau))); + double const formula_vanna = static_cast<double>(-phi(d1) * d2 / sigma); + double const formula_charm = + static_cast<double>(phi(d1) * (d2 * sigma * sqrt(tau) - 2 * r * tau) / (2 * tau * sigma * sqrt(tau))); + double const formula_vomma = static_cast<double>(S * phi(d1) * sqrt(tau) * d1 * d2 / sigma); + double const formula_veta = static_cast<double>(-S * phi(d1) * sqrt(tau) * + (r * d1 / (sigma * sqrt(tau)) - (1 + d1 * d2) / (2 * tau))); + double const formula_speed = + static_cast<double>(-phi(d1) * (d1 / (sigma * sqrt(tau)) + 1) / (S * S * sigma * sqrt(tau))); + double const formula_zomma = static_cast<double>(phi(d1) * (d1 * d2 - 1) / (S * sigma * sigma * sqrt(tau))); + double const formula_color = + static_cast<double>(-phi(d1) / (2 * S * tau * sigma * sqrt(tau)) * + (1 + (2 * r * tau - d2 * sigma * sqrt(tau)) * d1 / (sigma * sqrt(tau)))); + double const formula_ultima = + -formula_vega * static_cast<double>((d1 * d2 * (1 - d1 * d2) + d1 * d1 + d2 * d2) / (sigma * sigma)); + + std::cout << std::setprecision(std::numeric_limits<double>::digits10) + << "autodiff black-scholes call price = " << call_price.derivative(0, 0, 0, 0) << '\n' + << "autodiff black-scholes put price = " << put_price.derivative(0, 0, 0, 0) << '\n' + << "\n## First-order Greeks\n" + << "autodiff call delta = " << call_price.derivative(1, 0, 0, 0) << '\n' + << " formula call delta = " << formula_call_delta << '\n' + << "autodiff call vega = " << call_price.derivative(0, 1, 0, 0) << '\n' + << " formula call vega = " << formula_vega << '\n' + << "autodiff call theta = " << -call_price.derivative(0, 0, 1, 0) + << '\n' // minus sign due to tau = T-time + << " formula call theta = " << formula_call_theta << '\n' + << "autodiff call rho = " << call_price.derivative(0, 0, 0, 1) << '\n' + << " formula call rho = " << formula_call_rho << '\n' + << '\n' + << "autodiff put delta = " << put_price.derivative(1, 0, 0, 0) << '\n' + << " formula put delta = " << formula_put_delta << '\n' + << "autodiff put vega = " << put_price.derivative(0, 1, 0, 0) << '\n' + << " formula put vega = " << formula_vega << '\n' + << "autodiff put theta = " << -put_price.derivative(0, 0, 1, 0) << '\n' + << " formula put theta = " << formula_put_theta << '\n' + << "autodiff put rho = " << put_price.derivative(0, 0, 0, 1) << '\n' + << " formula put rho = " << formula_put_rho << '\n' + << "\n## Second-order Greeks\n" + << "autodiff call gamma = " << call_price.derivative(2, 0, 0, 0) << '\n' + << "autodiff put gamma = " << put_price.derivative(2, 0, 0, 0) << '\n' + << " formula gamma = " << formula_gamma << '\n' + << "autodiff call vanna = " << call_price.derivative(1, 1, 0, 0) << '\n' + << "autodiff put vanna = " << put_price.derivative(1, 1, 0, 0) << '\n' + << " formula vanna = " << formula_vanna << '\n' + << "autodiff call charm = " << -call_price.derivative(1, 0, 1, 0) << '\n' + << "autodiff put charm = " << -put_price.derivative(1, 0, 1, 0) << '\n' + << " formula charm = " << formula_charm << '\n' + << "autodiff call vomma = " << call_price.derivative(0, 2, 0, 0) << '\n' + << "autodiff put vomma = " << put_price.derivative(0, 2, 0, 0) << '\n' + << " formula vomma = " << formula_vomma << '\n' + << "autodiff call veta = " << call_price.derivative(0, 1, 1, 0) << '\n' + << "autodiff put veta = " << put_price.derivative(0, 1, 1, 0) << '\n' + << " formula veta = " << formula_veta << '\n' + << "\n## Third-order Greeks\n" + << "autodiff call speed = " << call_price.derivative(3, 0, 0, 0) << '\n' + << "autodiff put speed = " << put_price.derivative(3, 0, 0, 0) << '\n' + << " formula speed = " << formula_speed << '\n' + << "autodiff call zomma = " << call_price.derivative(2, 1, 0, 0) << '\n' + << "autodiff put zomma = " << put_price.derivative(2, 1, 0, 0) << '\n' + << " formula zomma = " << formula_zomma << '\n' + << "autodiff call color = " << call_price.derivative(2, 0, 1, 0) << '\n' + << "autodiff put color = " << put_price.derivative(2, 0, 1, 0) << '\n' + << " formula color = " << formula_color << '\n' + << "autodiff call ultima = " << call_price.derivative(0, 3, 0, 0) << '\n' + << "autodiff put ultima = " << put_price.derivative(0, 3, 0, 0) << '\n' + << " formula ultima = " << formula_ultima << '\n'; + return 0; +} +/* +Output: +autodiff black-scholes call price = 56.5136030677739 +autodiff black-scholes put price = 51.4109161009333 + +## First-order Greeks +autodiff call delta = 0.773818444921273 + formula call delta = 0.773818444921274 +autodiff call vega = 9.05493427705736 + formula call vega = 9.05493427705736 +autodiff call theta = -275.73013426444 + formula call theta = -275.73013426444 +autodiff call rho = 2.03320550539396 + formula call rho = 2.03320550539396 + +autodiff put delta = -0.226181555078726 + formula put delta = -0.226181555078726 +autodiff put vega = 9.05493427705736 + formula put vega = 9.05493427705736 +autodiff put theta = -274.481417851526 + formula put theta = -274.481417851526 +autodiff put rho = -6.17753255212599 + formula put rho = -6.17753255212599 + +## Second-order Greeks +autodiff call gamma = 0.00199851912993254 +autodiff put gamma = 0.00199851912993254 + formula gamma = 0.00199851912993254 +autodiff call vanna = 0.0410279463126531 +autodiff put vanna = 0.0410279463126531 + formula vanna = 0.0410279463126531 +autodiff call charm = -1.2505564233679 +autodiff put charm = -1.2505564233679 + formula charm = -1.2505564233679 +autodiff call vomma = -0.928114149313108 +autodiff put vomma = -0.928114149313108 + formula vomma = -0.928114149313107 +autodiff call veta = 26.7947073115641 +autodiff put veta = 26.7947073115641 + formula veta = 26.7947073115641 + +## Third-order Greeks +autodiff call speed = -2.90117322380992e-05 +autodiff put speed = -2.90117322380992e-05 + formula speed = -2.90117322380992e-05 +autodiff call zomma = -0.000604548369901419 +autodiff put zomma = -0.000604548369901419 + formula zomma = -0.000604548369901419 +autodiff call color = -0.0184014426606065 +autodiff put color = -0.0184014426606065 + formula color = -0.0184014426606065 +autodiff call ultima = -0.0922426864775683 +autodiff put ultima = -0.0922426864775683 + formula ultima = -0.0922426864775685 +**/ diff --git a/src/boost/libs/math/example/autodiff_black_scholes_brief.cpp b/src/boost/libs/math/example/autodiff_black_scholes_brief.cpp new file mode 100644 index 000000000..7078217b6 --- /dev/null +++ b/src/boost/libs/math/example/autodiff_black_scholes_brief.cpp @@ -0,0 +1,70 @@ +// Copyright Matthew Pulver 2018 - 2019. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +#include <boost/math/differentiation/autodiff.hpp> +#include <iostream> +#include <stdexcept> + +using namespace boost::math::constants; +using namespace boost::math::differentiation; + +// Equations and function/variable names are from +// https://en.wikipedia.org/wiki/Greeks_(finance)#Formulas_for_European_option_Greeks + +// Standard normal cumulative distribution function +template <typename X> +X Phi(X const& x) { + return 0.5 * erfc(-one_div_root_two<X>() * x); +} + +enum class CP { call, put }; + +// Assume zero annual dividend yield (q=0). +template <typename Price, typename Sigma, typename Tau, typename Rate> +promote<Price, Sigma, Tau, Rate> black_scholes_option_price(CP cp, + double K, + Price const& S, + Sigma const& sigma, + Tau const& tau, + Rate const& r) { + using namespace std; + auto const d1 = (log(S / K) + (r + sigma * sigma / 2) * tau) / (sigma * sqrt(tau)); + auto const d2 = (log(S / K) + (r - sigma * sigma / 2) * tau) / (sigma * sqrt(tau)); + switch (cp) { + case CP::call: + return S * Phi(d1) - exp(-r * tau) * K * Phi(d2); + case CP::put: + return exp(-r * tau) * K * Phi(-d2) - S * Phi(-d1); + default: + throw std::runtime_error("Invalid CP value."); + } +} + +int main() { + double const K = 100.0; // Strike price. + auto const S = make_fvar<double, 2>(105); // Stock price. + double const sigma = 5; // Volatility. + double const tau = 30.0 / 365; // Time to expiration in years. (30 days). + double const r = 1.25 / 100; // Interest rate. + auto const call_price = black_scholes_option_price(CP::call, K, S, sigma, tau, r); + auto const put_price = black_scholes_option_price(CP::put, K, S, sigma, tau, r); + + std::cout << "black-scholes call price = " << call_price.derivative(0) << '\n' + << "black-scholes put price = " << put_price.derivative(0) << '\n' + << "call delta = " << call_price.derivative(1) << '\n' + << "put delta = " << put_price.derivative(1) << '\n' + << "call gamma = " << call_price.derivative(2) << '\n' + << "put gamma = " << put_price.derivative(2) << '\n'; + return 0; +} +/* +Output: +black-scholes call price = 56.5136 +black-scholes put price = 51.4109 +call delta = 0.773818 +put delta = -0.226182 +call gamma = 0.00199852 +put gamma = 0.00199852 +**/ diff --git a/src/boost/libs/math/example/autodiff_fourth_power.cpp b/src/boost/libs/math/example/autodiff_fourth_power.cpp new file mode 100644 index 000000000..50f280b6b --- /dev/null +++ b/src/boost/libs/math/example/autodiff_fourth_power.cpp @@ -0,0 +1,34 @@ +// Copyright Matthew Pulver 2018 - 2019. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +#include <boost/math/differentiation/autodiff.hpp> +#include <iostream> + +template <typename T> +T fourth_power(T const& x) { + T x4 = x * x; // retval in operator*() uses x4's memory via NRVO. + x4 *= x4; // No copies of x4 are made within operator*=() even when squaring. + return x4; // x4 uses y's memory in main() via NRVO. +} + +int main() { + using namespace boost::math::differentiation; + + constexpr unsigned Order = 5; // Highest order derivative to be calculated. + auto const x = make_fvar<double, Order>(2.0); // Find derivatives at x=2. + auto const y = fourth_power(x); + for (unsigned i = 0; i <= Order; ++i) + std::cout << "y.derivative(" << i << ") = " << y.derivative(i) << std::endl; + return 0; +} +/* +Output: +y.derivative(0) = 16 +y.derivative(1) = 32 +y.derivative(2) = 48 +y.derivative(3) = 48 +y.derivative(4) = 24 +y.derivative(5) = 0 +**/ diff --git a/src/boost/libs/math/example/autodiff_mixed_partials.cpp b/src/boost/libs/math/example/autodiff_mixed_partials.cpp new file mode 100644 index 000000000..551429e01 --- /dev/null +++ b/src/boost/libs/math/example/autodiff_mixed_partials.cpp @@ -0,0 +1,293 @@ +// Copyright Matthew Pulver 2018 - 2019. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +#include <boost/lexical_cast.hpp> +#include <boost/math/differentiation/autodiff.hpp> +#include <boost/mp11/tuple.hpp> +#include <boost/mp11/utility.hpp> +#include <boost/multiprecision/cpp_bin_float.hpp> +#include <iostream> + +using namespace boost::math::differentiation; + +struct f { + template <typename W, typename X, typename Y, typename Z> + promote<W, X, Y, Z> operator()(W const& w, X const& x, Y const& y, Z const& z) const { + return exp(w * sin(x * log(y) / z) + sqrt(w * z / (x * y))) + w * w / tan(z); + } +}; + +// Derivatives calculated from symbolic differentiation by Mathematica for comparison. Script: +// mixed_partials.nb +static constexpr std::array<char const*, 240> answers{ + {"19878.40628980434922342465374997798674242532797789489", + "20731.74838274939517275508122761443159515217855975002", + "14667.60767623939014840117674691707821648144188283774", + "1840.559936449813118734351750381849294157477519107602", + "-9219.318005237072129605008516120710807803827373819700", + "-7272.300634012811783845589472196110804386170683300081", + "-2135.296370062283924160196772166043360841114107521292", + "3095.081027251846799545897828297310835169325417217168", + "4249.026762908615627428402369471953790564918480025345", + "2063.989061062734416582172072883742097425754355167541", + "-885.5284114876496084068555333811894392182458751895290", + "-1962.133420441743158021558423645064067562765178375508", + "-1846.899830787084518564013512948598850243350915531775", + "-160.9590127603295755195950112199107484483554942817846", + "1091.039412341633994110997652976585409621806446647794", + "452.4395574345229946707651998323417632800605985181691", + "666.4013922727704990031159406121675703174518834914461", + "-415.6464114333629107803309520898363153301435468382605", + "-625.1464179039986361267627631122900331946746137220517", + "369.9491669772617110087494756677334192842413470837587", + "-24330.89613849389343130420303653062335840497802221681", + "-18810.41605175626752065686192937776868736029049989926", + "-4890.406122702359099863022925593448420259414896197252", + "8833.005054768976417065486877649473665597894570245307", + "8484.350739681613747819854384228795938450532463850094", + "3097.204151240398893507362023543393154680147349049848", + "-3255.045136783440612110181337652522080890693968833148", + "-4342.778553332193097878812792875447018366988006584840", + "-2407.987237906523486012534085031032446996713414362131", + "861.1173916470300084261504495377425043024739914571554", + "2436.743725763308619092960749816106318692933687303014", + "-19.24649610733827783846392798978023489104363382129689", + "187.7855148870511714395275130898958731897480766620821", + "-1259.466063335212195169531010871023748854744563232277", + "-709.6860523972158261343923419671629587637051060458295", + "1423.000558608604536932163648918899935569543711292466", + "484.9208133389233959103861107714757012185008046446372", + "763.9746885074453180462508029718247316712990115789154", + "-327.4162918228055568224139277603073169658358026440432", + "-1122.337707248494521123614369562896901904418640152220", + "23973.06007192346989337502250398494874845408708506720", + "8840.543151778796869949670401421984604862699128880003", + "-9082.571033221549378277312292526023838132689941236879", + "-12270.27378289258717737657881957466807305650429436397", + "-4320.434071420599854743576892819691675331049612545664", + "3281.351967707280898543984556670710235259118405463698", + "5880.336263083418767219493592767818708317492833223933", + "-1288.482785219706549809211085113790275109642879331959", + "-803.9713537626580526627976840414468844364935388365037", + "-2986.387245331698390346145949708414455858834967096376", + "-586.7316859822658306283656047992829723003491823675739", + "3929.073189280739356198769778905960586080418779863615", + "1453.728280983826630077825553258703050898056317382483", + "1037.878071685953829685046234106860743366780050925514", + "-1482.745805277401336553926171580259185140208053329753", + "-1877.134792933828810602377451370316364621357891989679", + "-931.7138710369298207131581126980851620513905805624544", + "254.6565590420322632851077818917210811815919344882311", + "1391.248064745611663849820246430123214796614030838600", + "-431.4820563154137955051720207563800896297257103310465", + "16975.34005365179555009050533000516107937041784876054", + "19662.60356303341709846238790020024593550984564081068", + "15765.85130704020004301064240357947656083104783442825", + "3972.155036195937013764185795634749937308876197976202", + "-8681.748539789720512499473840242996096730194203989543", + "-7703.183042460387656743498394861780784700076575106134", + "-3049.708696569518774040135942468704911634779352213044", + "2971.469685992270876159892302788930292108129670398058", + "4370.196499857550025657084783894747734031876677385611", + "2524.632473357435670756946837415389227139966527203701", + "-656.6080000236679071742450437463693211275208125750923", + "-2423.452917325258132591368397957959217829861665178601", + "-2074.987664204263204162199830716851483704870169031179", + "-381.2253794988132984501358802316138392247470857452486", + "1219.507245791997351017860252538035146744682380716428", + "805.3802239840836877339667281819652171888443003165988", + "838.4004190058912380470543219448821914235443115661655", + "-390.6125197108983831575656956558201636111305409512701", + "-828.2085489298235758253219930356006757081473789845849", + "293.8999854454994790079171865082094494146506490533363", + "-22965.85985843951977785883587223006628792405076928067", + "-20026.69101529929621743747554537576887048069629325374", + "-7316.092745063355996548975300169565482331369744607021", + "8632.466133972614659252310985982644793465043032940318", + "8987.046882870452266200748127338744248816756004290490", + "4199.925399536137541108783465785304128965582292174062", + "-2958.429850896062893179851696175634522187021390095560", + "-5665.563891218624062243686482808197054863235184904433", + "-2945.404552250341615883104643651287431663294281737652", + "555.6566272478262524735403145861484390537770707372992", + "2936.796403550079139218970638242013974322758744804216", + "651.5191650747110008135060635556227666232180743487328", + "444.7629427486155148584918602702161457622049333694568", + "-1390.989671799095801316658971275073184600067187023729", + "-1142.861468946763860859271224968631944511098747155437", + "1541.978723117340843491920690654997335632919116206279", + "455.7146063293814470171599782651235242129856311098151", + "998.7943503940357037260061331795191352937661538946216", + "-204.8485581981121295383497187536442450324011940647949", + "-1560.354115460478786113711476250386112014306509906244", + "25278.29450605247223516529112562423587288781657290275", + "11873.22337179046469888005044109378787446671408425048", + "-8242.187303368878103323785658604027555126374435611949", + "-15939.98056417465751946455567789306872745912255628512", + "-5648.833539698031486810309720694416837861242341227280", + "2751.513926122717118525029734574022921057261239749143", + "7349.432002479077129245930487320138527887196396579062", + "194.9972545980371127390142753318206783334452047502143", + "-402.8156857682688265622049800462325595907987257153782", + "-3518.871908683063371167722463713374376552181380727802", + "-1494.304793474682619087166400375396721307777439607909", + "4640.927509426080087451995953783429589632369803588940", + "1585.757705203227141964561144798400703219894640413562", + "1565.169992404407137888592924342582799362959736185298", + "-1513.259809733540018859089666188672238777297615451800", + "-2974.437872674680092826212901753475972242208819679978", + "-1203.236292653823441598437153564865951527142648802876", + "72.52425949879153384040698301599842998884036742649047", + "1871.625274253419949517250818647194858608124560073483", + "-2.489984337379681666361341362948045621969765070197429", + "14462.74423518633102580192225823524237502860825596609", + "18367.74740916432711689913219912502810575714860430297", + "16565.76324499673961400925630526921000337443450249297", + "6054.315252651102952034254100792777051580892954459740", + "-8084.981271982030146065497115893934803061545998433631", + "-7988.314359128201297240919364015959817416101519999194", + "-3989.319346941492698525859335371231602272119870228687", + "2616.721186534649016680934493970036169897788778926434", + "4420.859270970486562095630193355634655337290952862363", + "2973.033519764547909146474824627687039969488363657908", + "-324.1453016982713707989332262410969595194473127209825", + "-2843.242039958969221918101261762794653424879358390111", + "-2281.461806143289517702658392470195144560150025832652", + "-642.9353229582055924928927665183236308235598082837497", + "1299.287274176955358490409470855361289523321919337117", + "1238.597083372069762230817383681570828675426312803376", + "1021.334042770848165110529668635291528449691525937968", + "-329.0529345069271079573348500899329811170455711610811", + "-1046.254301544052075124857362060924818517694048905299", + "134.7343039554480655186788228552325941588620079791654", + "-21431.41643507661192392650726158493697457993678274754", + "-20856.88281479015784660571401663659059349708627445067", + "-9829.261970591930907585958999196966814861251125275804", + "7806.858647077811827981774785577363365546600234846335", + "9319.700085649568180114405924685286453652118439999060", + "5319.898768025758256383579171601100187435481641933401", + "-2387.954826466841736373447020403170264502066930376059", + "-6958.298525165359760665355886221309296550746152109847", + "-3468.539106391972560670887295398968213297736424267559", + "130.4167253342709401698825285623058661085645012029873", + "3371.139930235175987370940343096776588915600470241960", + "1569.232678004908105313880673484968847566948896728142", + "750.0912101179065245750415609380442359608197763310413", + "-1462.257209626597452197736652121394535208578921869658", + "-1661.577809630240615684355192771059515041884351493459", + "1509.628528603869133250456671040505284128185908768108", + "383.8950902580816259502239917715884779698864996879279", + "1248.051096343638013308778159911906703363730187986273", + "17.18569564265260274901760034571610990094333217519021", + "-2038.024598002604853054532645991188063394308018947374", + "26118.98132017823514803387529120810044029492871875474", + "14943.61943482227903328457116850255971625430735856355", + "-6650.686262276131072415580833374348889422387492668440", + "-19519.81529547404067945704333355155941895199228108631", + "-6983.190236500848647457042860591724089812405118922223", + "1899.297502873688983038424995203515277346497811783168", + "8715.003652642963488202943622358986745434720576722170", + "2368.150690681864301926962120618658083737878227231428", + "136.8920793093482831910443246272238406481527839521448", + "-3954.732706163417141961077488373290331419627965482785", + "-2673.556440231186786375595871506657802723673830409989", + "5078.483935249043594670125721926702845818403229980691", + "1643.459143721204817182772630730123271413273760820347", + "2182.216979506380293664703833586468523416961563720645", + "-1345.838830963620501537777318021157952722412472356094", + "-4309.285350629108413525304135326225818270616857298235", + "-1488.050869922417817689426519211523527088509094291312", + "-228.0584943070343720919835603886532454450555855354340", + "2373.398940425709177876367020236623713151456855728138", + "773.8481328103928058186643458500631723389600248582833", + "12294.40387737855548614823173849184004455244840062464", + "16977.34966571858301862913845572077593071467784570724", + "17057.17475622503175013658695220988017704387344177727", + "8121.189758511830935868344768490586007624092305459885", + "-7458.443541406284389918808653948439156033975014107187", + "-8134.131160882738058651976911725365291142418949378248", + "-4912.881158613784419581465435995807691111897279859302", + "2030.653136098933717888434825960516061206391833398177", + "4407.490527709412730881592594976776779312299897714205", + "3392.434568825892752350943548729559313328141534290860", + "104.0372355841506198680609232049783930050635078746762", + "-3180.817620484463214391157460812371170723810181051096", + "-2460.523987075069437321629265332968914260047631079537", + "-938.2209314069133432825590545267820890922150850657831", + "1315.246905571876456706320919211807375254975062430487", + "1735.862392405992188189147617586418269768276241147998", + "1209.759657223166954850207025399731503326968841680649", + "-227.3320054566642297128407910803774238020746116287390", + "-1266.126209991929259396966729664100401813091860201682", + "-123.0794572338149156803989321165094334755661021559442", + "-19806.90794333834685506732819834090525250045748665845", + "-21314.81635440575229337844631555492486744407550254908", + "-12317.58384430130805020250005527399703840208659666608", + "6349.418659888281474363154227419204673663621492760982", + "9489.819687696527735093973063679592839666155440941289", + "6409.538948456309994399374417972222747225748405617373", + "-1550.281799013125267606263057621300789555474258987989", + "-8109.711199785217512061886243157800006692908759687186", + "-3957.840330296874877742767473517819198882831790006004", + "-404.0796555836667858753163727999380679499192203780272", + "3693.614351301181980145006883746936633676934626580499", + "2716.146658322790064799415509615557123789406209068981", + "1094.591086641398900496318896947912437274250932576747", + "-1456.269645549946420883827817869876763706452982413420", + "-2244.380608735636962338392373719455877272151458411079", + "1268.593891556261871090883000459505759446497182073132", + "265.2206730327749346649809229271069944357537135668622", + "1496.091578778639488439197917198148587432113387871024", + "354.6137351047722781932932090799444060236757625488818", + "-2508.477110048684129181005769771219369377836598443263", + "26517.86140875157324686379805134248778305979287686214", + "17922.98387741915144079932445041215068937644694653527", + "-4328.259142127668040873054918170572859673703425721293", + "-22704.70245940080949074466622805971940616027152354999", + "-8268.613747173738971390434576274225941735552759965376", + "740.4056074392611464740778308961471299437619012164253", + "9848.900182836035080973766381422758538530595451048714", + "5213.598341476210337710365441072904970861063876340963", + "801.2462923723508233330997243930793458484750729415321", + "-4241.870133920767845856621968904769727964770527614244", + "-4092.241355868550570635569815488217469506874233892269", + "5074.435909206083943809967780457349942315503368249477", + "1607.765329254820915989772546102530187884674235100928", + "2861.155651116567526208762405651011317435252198548496", + "-918.9310546317296090214320737728927500362088478158839", + "-5803.211323646092019259074499814222806376618363553826", + "-1767.541897994477314401145980308432268207111761980100", + "-663.0646207520075726320417301262932382663072876188661", + "2837.903194613938414496183429129769829434890424213252", + "1976.319600747797717779881875290418720908121189218755"}}; + +int main() { + using float50 = boost::multiprecision::cpp_bin_float_50; + constexpr std::size_t Nw = 3; // Max order of derivative to calculate for w + constexpr std::size_t Nx = 2; // Max order of derivative to calculate for x + constexpr std::size_t Ny = 4; // Max order of derivative to calculate for y + constexpr std::size_t Nz = 3; // Max order of derivative to calculate for z + auto const variables = make_ftuple<float50, Nw, Nx, Ny, Nz>(11, 12, 13, 14); + auto const v = boost::mp11::tuple_apply(f{}, variables); + std::size_t ia = 0; + double max_relative_error = 0; + for (std::size_t iw = 0; iw <= Nw; ++iw) + for (std::size_t ix = 0; ix <= Nx; ++ix) + for (std::size_t iy = 0; iy <= Ny; ++iy) + for (std::size_t iz = 0; iz <= Nz; ++iz) { + float50 const value = v.derivative(iw, ix, iy, iz); + float50 const answer = boost::lexical_cast<float50>(answers[ia++]); + double const error = static_cast<double>(fabs(value / answer - 1)); + max_relative_error = (std::max)(error, max_relative_error); + } + std::cout << "max_relative_error = " << std::setprecision(3) << max_relative_error << " out of " << ia + << " calculated values." << std::endl; + return 0; +} +/* +Output: +max_relative_error = 6.82e-13 out of 240 calculated values. (for double) +max_relative_error = 3.36e-47 out of 240 calculated values. (for cpp_bin_float_50) +**/ diff --git a/src/boost/libs/math/example/autodiff_multiprecision.cpp b/src/boost/libs/math/example/autodiff_multiprecision.cpp new file mode 100644 index 000000000..81c7c27c5 --- /dev/null +++ b/src/boost/libs/math/example/autodiff_multiprecision.cpp @@ -0,0 +1,46 @@ +// Copyright Matthew Pulver 2018 - 2019. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +#include <boost/math/differentiation/autodiff.hpp> +#include <boost/multiprecision/cpp_bin_float.hpp> +#include <iostream> + +using namespace boost::math::differentiation; + +template <typename W, typename X, typename Y, typename Z> +promote<W, X, Y, Z> f(const W& w, const X& x, const Y& y, const Z& z) { + using namespace std; + return exp(w * sin(x * log(y) / z) + sqrt(w * z / (x * y))) + w * w / tan(z); +} + +int main() { + using float50 = boost::multiprecision::cpp_bin_float_50; + + constexpr unsigned Nw = 3; // Max order of derivative to calculate for w + constexpr unsigned Nx = 2; // Max order of derivative to calculate for x + constexpr unsigned Ny = 4; // Max order of derivative to calculate for y + constexpr unsigned Nz = 3; // Max order of derivative to calculate for z + // Declare 4 independent variables together into a std::tuple. + auto const variables = make_ftuple<float50, Nw, Nx, Ny, Nz>(11, 12, 13, 14); + auto const& w = std::get<0>(variables); // Up to Nw derivatives at w=11 + auto const& x = std::get<1>(variables); // Up to Nx derivatives at x=12 + auto const& y = std::get<2>(variables); // Up to Ny derivatives at y=13 + auto const& z = std::get<3>(variables); // Up to Nz derivatives at z=14 + auto const v = f(w, x, y, z); + // Calculated from Mathematica symbolic differentiation. + float50 const answer("1976.319600747797717779881875290418720908121189218755"); + std::cout << std::setprecision(std::numeric_limits<float50>::digits10) + << "mathematica : " << answer << '\n' + << "autodiff : " << v.derivative(Nw, Nx, Ny, Nz) << '\n' + << std::setprecision(3) + << "relative error: " << (v.derivative(Nw, Nx, Ny, Nz) / answer - 1) << '\n'; + return 0; +} +/* +Output: +mathematica : 1976.3196007477977177798818752904187209081211892188 +autodiff : 1976.3196007477977177798818752904187209081211892188 +relative error: 2.67e-50 +**/ diff --git a/src/boost/libs/math/example/barycentric_interpolation_example.cpp b/src/boost/libs/math/example/barycentric_interpolation_example.cpp new file mode 100644 index 000000000..263e20f19 --- /dev/null +++ b/src/boost/libs/math/example/barycentric_interpolation_example.cpp @@ -0,0 +1,92 @@ + +// Copyright Nick Thompson, 2017 + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http://www.boost.org/LICENSE_1_0.txt). + +#include <iostream> +#include <limits> +#include <vector> + +//[barycentric_rational_example + +/*` +This example shows how to use barycentric rational interpolation, using Walter Kohn's classic paper +"Solution of the Schrodinger Equation in Periodic Lattices with an Application to Metallic Lithium" +In this paper, Kohn needs to repeatedly solve an ODE (the radial Schrodinger equation) given a potential +which is only known at non-equally samples data. + +If he'd only had the barycentric rational interpolant of Boost.Math! + +References: Kohn, W., and N. Rostoker. "Solution of the Schrodinger equation in periodic lattices with an application to metallic lithium." Physical Review 94.5 (1954): 1111. +*/ + +#include <boost/math/interpolators/barycentric_rational.hpp> + +int main() +{ + // The lithium potential is given in Kohn's paper, Table I: + std::vector<double> r(45); + std::vector<double> mrV(45); + + // We'll skip the code for filling the above vectors with data for now... + //<- + + r[0] = 0.02; mrV[0] = 5.727; + r[1] = 0.04, mrV[1] = 5.544; + r[2] = 0.06, mrV[2] = 5.450; + r[3] = 0.08, mrV[3] = 5.351; + r[4] = 0.10, mrV[4] = 5.253; + r[5] = 0.12, mrV[5] = 5.157; + r[6] = 0.14, mrV[6] = 5.058; + r[7] = 0.16, mrV[7] = 4.960; + r[8] = 0.18, mrV[8] = 4.862; + r[9] = 0.20, mrV[9] = 4.762; + r[10] = 0.24, mrV[10] = 4.563; + r[11] = 0.28, mrV[11] = 4.360; + r[12] = 0.32, mrV[12] = 4.1584; + r[13] = 0.36, mrV[13] = 3.9463; + r[14] = 0.40, mrV[14] = 3.7360; + r[15] = 0.44, mrV[15] = 3.5429; + r[16] = 0.48, mrV[16] = 3.3797; + r[17] = 0.52, mrV[17] = 3.2417; + r[18] = 0.56, mrV[18] = 3.1209; + r[19] = 0.60, mrV[19] = 3.0138; + r[20] = 0.68, mrV[20] = 2.8342; + r[21] = 0.76, mrV[21] = 2.6881; + r[22] = 0.84, mrV[22] = 2.5662; + r[23] = 0.92, mrV[23] = 2.4242; + r[24] = 1.00, mrV[24] = 2.3766; + r[25] = 1.08, mrV[25] = 2.3058; + r[26] = 1.16, mrV[26] = 2.2458; + r[27] = 1.24, mrV[27] = 2.2035; + r[28] = 1.32, mrV[28] = 2.1661; + r[29] = 1.40, mrV[29] = 2.1350; + r[30] = 1.48, mrV[30] = 2.1090; + r[31] = 1.64, mrV[31] = 2.0697; + r[32] = 1.80, mrV[32] = 2.0466; + r[33] = 1.96, mrV[33] = 2.0325; + r[34] = 2.12, mrV[34] = 2.0288; + r[35] = 2.28, mrV[35] = 2.0292; + r[36] = 2.44, mrV[36] = 2.0228; + r[37] = 2.60, mrV[37] = 2.0124; + r[38] = 2.76, mrV[38] = 2.0065; + r[39] = 2.92, mrV[39] = 2.0031; + r[40] = 3.08, mrV[40] = 2.0015; + r[41] = 3.24, mrV[41] = 2.0008; + r[42] = 3.40, mrV[42] = 2.0004; + r[43] = 3.56, mrV[43] = 2.0002; + r[44] = 3.72, mrV[44] = 2.0001; + //-> + + // Now we want to interpolate this potential at any r: + boost::math::barycentric_rational<double> b(r.data(), mrV.data(), r.size()); + + for (size_t i = 1; i < 8; ++i) + { + double r = i*0.5; + std::cout << "(r, V) = (" << r << ", " << -b(r)/r << ")\n"; + } +} +//] [/barycentric_rational_example] diff --git a/src/boost/libs/math/example/barycentric_interpolation_example_2.cpp b/src/boost/libs/math/example/barycentric_interpolation_example_2.cpp new file mode 100644 index 000000000..4128f95ba --- /dev/null +++ b/src/boost/libs/math/example/barycentric_interpolation_example_2.cpp @@ -0,0 +1,108 @@ + +// Copyright Nick Thompson, 2017 + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http://www.boost.org/LICENSE_1_0.txt). + +#include <iostream> +#include <limits> +#include <map> + +//[barycentric_rational_example2 + +/*`This further example shows how to use the iterator based constructor, and then uses the +function object in our root finding algorithms to locate the points where the potential +achieves a specific value. +*/ + +#include <boost/math/interpolators/barycentric_rational.hpp> +#include <boost/range/adaptors.hpp> +#include <boost/math/tools/roots.hpp> + +int main() +{ + // The lithium potential is given in Kohn's paper, Table I. + // (We could equally easily use an unordered_map, a list of tuples or pairs, or a 2-dimensional array). + std::map<double, double> r; + + r[0.02] = 5.727; + r[0.04] = 5.544; + r[0.06] = 5.450; + r[0.08] = 5.351; + r[0.10] = 5.253; + r[0.12] = 5.157; + r[0.14] = 5.058; + r[0.16] = 4.960; + r[0.18] = 4.862; + r[0.20] = 4.762; + r[0.24] = 4.563; + r[0.28] = 4.360; + r[0.32] = 4.1584; + r[0.36] = 3.9463; + r[0.40] = 3.7360; + r[0.44] = 3.5429; + r[0.48] = 3.3797; + r[0.52] = 3.2417; + r[0.56] = 3.1209; + r[0.60] = 3.0138; + r[0.68] = 2.8342; + r[0.76] = 2.6881; + r[0.84] = 2.5662; + r[0.92] = 2.4242; + r[1.00] = 2.3766; + r[1.08] = 2.3058; + r[1.16] = 2.2458; + r[1.24] = 2.2035; + r[1.32] = 2.1661; + r[1.40] = 2.1350; + r[1.48] = 2.1090; + r[1.64] = 2.0697; + r[1.80] = 2.0466; + r[1.96] = 2.0325; + r[2.12] = 2.0288; + r[2.28] = 2.0292; + r[2.44] = 2.0228; + r[2.60] = 2.0124; + r[2.76] = 2.0065; + r[2.92] = 2.0031; + r[3.08] = 2.0015; + r[3.24] = 2.0008; + r[3.40] = 2.0004; + r[3.56] = 2.0002; + r[3.72] = 2.0001; + + // Let's discover the absissa that will generate a potential of exactly 3.0, + // start by creating 2 ranges for the x and y values: + auto x_range = boost::adaptors::keys(r); + auto y_range = boost::adaptors::values(r); + boost::math::barycentric_rational<double> b(x_range.begin(), x_range.end(), y_range.begin()); + // + // We'll use a lambda expression to provide the functor to our root finder, since we want + // the abscissa value that yields 3, not zero. We pass the functor b by value to the + // lambda expression since barycentric_rational is trivial to copy. + // Here we're using simple bisection to find the root: + boost::uintmax_t iterations = (std::numeric_limits<boost::uintmax_t>::max)(); + double abscissa_3 = boost::math::tools::bisect([=](double x) { return b(x) - 3; }, 0.44, 1.24, boost::math::tools::eps_tolerance<double>(), iterations).first; + std::cout << "Abscissa value that yields a potential of 3 = " << abscissa_3 << std::endl; + std::cout << "Root was found in " << iterations << " iterations." << std::endl; + // + // However, we have a more efficient root finding algorithm than simple bisection: + iterations = (std::numeric_limits<boost::uintmax_t>::max)(); + abscissa_3 = boost::math::tools::bracket_and_solve_root([=](double x) { return b(x) - 3; }, 0.6, 1.2, false, boost::math::tools::eps_tolerance<double>(), iterations).first; + std::cout << "Abscissa value that yields a potential of 3 = " << abscissa_3 << std::endl; + std::cout << "Root was found in " << iterations << " iterations." << std::endl; +} +//] [/barycentric_rational_example2] + + +//[barycentric_rational_example2_out +/*` Program output is: +[pre +Abscissa value that yields a potential of 3 = 0.604728 +Root was found in 54 iterations. +Abscissa value that yields a potential of 3 = 0.604728 +Root was found in 10 iterations. +] +*/ +//] diff --git a/src/boost/libs/math/example/bernoulli_example.cpp b/src/boost/libs/math/example/bernoulli_example.cpp new file mode 100644 index 000000000..5a2c58969 --- /dev/null +++ b/src/boost/libs/math/example/bernoulli_example.cpp @@ -0,0 +1,207 @@ +// Copyright Paul A. Bristow 2013. +// Copyright Nakhar Agrawal 2013. +// Copyright John Maddock 2013. +// Copyright Christopher Kormanyos 2013. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#pragma warning (disable : 4100) // unreferenced formal parameter. +#pragma warning (disable : 4127) // conditional expression is constant. + +//#define BOOST_MATH_OVERFLOW_ERROR_POLICY ignore_error + +#include <boost/multiprecision/cpp_dec_float.hpp> +#include <boost/math/special_functions/bernoulli.hpp> + +#include <iostream> + +/* First 50 from 2 to 100 inclusive: */ +/* TABLE[N[BernoulliB[n], 200], {n,2,100,2}] */ + +//SC_(0.1666666666666666666666666666666666666666), +//SC_(-0.0333333333333333333333333333333333333333), +//SC_(0.0238095238095238095238095238095238095238), +//SC_(-0.0333333333333333333333333333333333333333), +//SC_(0.0757575757575757575757575757575757575757), +//SC_(-0.2531135531135531135531135531135531135531), +//SC_(1.1666666666666666666666666666666666666666), +//SC_(-7.0921568627450980392156862745098039215686), +//SC_(54.9711779448621553884711779448621553884711), + +int main() +{ + //[bernoulli_example_1 + +/*`A simple example computes the value of B[sub 4] where the return type is `double`, +note that the argument to bernoulli_b2n is ['2] not ['4] since it computes B[sub 2N]. + + +*/ + try + { // It is always wise to use try'n'catch blocks around Boost.Math functions + // so that any informative error messages can be displayed in the catch block. + std::cout + << std::setprecision(std::numeric_limits<double>::digits10) + << boost::math::bernoulli_b2n<double>(2) << std::endl; + +/*`So B[sub 4] == -1/30 == -0.0333333333333333 + +If we use Boost.Multiprecision and its 50 decimal digit floating-point type `cpp_dec_float_50`, +we can calculate the value of much larger numbers like B[sub 200] +and also obtain much higher precision. +*/ + + std::cout + << std::setprecision(std::numeric_limits<boost::multiprecision::cpp_dec_float_50>::digits10) + << boost::math::bernoulli_b2n<boost::multiprecision::cpp_dec_float_50>(100) << std::endl; + +//] //[/bernoulli_example_1] + +//[bernoulli_example_2 +/*`We can compute and save all the float-precision Bernoulli numbers from one call. +*/ + std::vector<float> bn; // Space for 32-bit `float` precision Bernoulli numbers. + + // Start with Bernoulli number 0. + boost::math::bernoulli_b2n<float>(0, 32, std::back_inserter(bn)); // Fill vector with even Bernoulli numbers. + + for(size_t i = 0; i < bn.size(); i++) + { // Show vector of even Bernoulli numbers, showing all significant decimal digits. + std::cout << std::setprecision(std::numeric_limits<float>::digits10) + << i*2 << ' ' + << bn[i] + << std::endl; + } +//] //[/bernoulli_example_2] + + } + catch(const std::exception& ex) + { + std::cout << "Thrown Exception caught: " << ex.what() << std::endl; + } + + +//[bernoulli_example_3 +/*`Of course, for any floating-point type, there is a maximum Bernoulli number that can be computed + before it overflows the exponent. + By default policy, if we try to compute too high a Bernoulli number, an exception will be thrown. +*/ + try + { + std::cout + << std::setprecision(std::numeric_limits<float>::digits10) + << "Bernoulli number " << 33 * 2 <<std::endl; + + std::cout << boost::math::bernoulli_b2n<float>(33) << std::endl; + } + catch (std::exception ex) + { + std::cout << "Thrown Exception caught: " << ex.what() << std::endl; + } + +/*` +and we will get a helpful error message (provided try'n'catch blocks are used). +*/ + +//] //[/bernoulli_example_3] + +//[bernoulli_example_4 +/*For example: +*/ + std::cout << "boost::math::max_bernoulli_b2n<float>::value = " << boost::math::max_bernoulli_b2n<float>::value << std::endl; + std::cout << "Maximum Bernoulli number using float is " << boost::math::bernoulli_b2n<float>( boost::math::max_bernoulli_b2n<float>::value) << std::endl; + std::cout << "boost::math::max_bernoulli_b2n<double>::value = " << boost::math::max_bernoulli_b2n<double>::value << std::endl; + std::cout << "Maximum Bernoulli number using double is " << boost::math::bernoulli_b2n<double>( boost::math::max_bernoulli_b2n<double>::value) << std::endl; + //] //[/bernoulli_example_4] + +//[tangent_example_1 + +/*`We can compute and save a few Tangent numbers. +*/ + std::vector<float> tn; // Space for some `float` precision Tangent numbers. + + // Start with Bernoulli number 0. + boost::math::tangent_t2n<float>(1, 6, std::back_inserter(tn)); // Fill vector with even Tangent numbers. + + for(size_t i = 0; i < tn.size(); i++) + { // Show vector of even Tangent numbers, showing all significant decimal digits. + std::cout << std::setprecision(std::numeric_limits<float>::digits10) + << " " + << tn[i]; + } + std::cout << std::endl; + +//] [/tangent_example_1] + +// 1, 2, 16, 272, 7936, 353792, 22368256, 1903757312 + + + +} // int main() + +/* + +//[bernoulli_output_1 + -3.6470772645191354362138308865549944904868234686191e+215 +//] //[/bernoulli_output_1] + +//[bernoulli_output_2 + + 0 1 + 2 0.166667 + 4 -0.0333333 + 6 0.0238095 + 8 -0.0333333 + 10 0.0757576 + 12 -0.253114 + 14 1.16667 + 16 -7.09216 + 18 54.9712 + 20 -529.124 + 22 6192.12 + 24 -86580.3 + 26 1.42552e+006 + 28 -2.72982e+007 + 30 6.01581e+008 + 32 -1.51163e+010 + 34 4.29615e+011 + 36 -1.37117e+013 + 38 4.88332e+014 + 40 -1.92966e+016 + 42 8.41693e+017 + 44 -4.03381e+019 + 46 2.11507e+021 + 48 -1.20866e+023 + 50 7.50087e+024 + 52 -5.03878e+026 + 54 3.65288e+028 + 56 -2.84988e+030 + 58 2.38654e+032 + 60 -2.14e+034 + 62 2.0501e+036 +//] //[/bernoulli_output_2] + +//[bernoulli_output_3 + Bernoulli number 66 + Thrown Exception caught: Error in function boost::math::bernoulli_b2n<float>(n): + Overflow evaluating function at 33 +//] //[/bernoulli_output_3] +//[bernoulli_output_4 + boost::math::max_bernoulli_b2n<float>::value = 32 + Maximum Bernoulli number using float is -2.0938e+038 + boost::math::max_bernoulli_b2n<double>::value = 129 + Maximum Bernoulli number using double is 1.33528e+306 +//] //[/bernoulli_output_4] + + +//[tangent_output_1 + 1 2 16 272 7936 353792 +//] [/tangent_output_1] + + + +*/ + + diff --git a/src/boost/libs/math/example/bessel_errors_example.cpp b/src/boost/libs/math/example/bessel_errors_example.cpp new file mode 100644 index 000000000..1b7729269 --- /dev/null +++ b/src/boost/libs/math/example/bessel_errors_example.cpp @@ -0,0 +1,171 @@ +// Copyright Christopher Kormanyos 2013. +// Copyright Paul A. Bristow 2013. +// Copyright John Maddock 2013. + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http://www.boost.org/LICENSE_1_0.txt). + +#ifdef _MSC_VER +# pragma warning (disable : 4512) // assignment operator could not be generated. +# pragma warning (disable : 4996) // assignment operator could not be generated. +#endif + +#include <iostream> +#include <limits> +#include <vector> +#include <algorithm> +#include <iomanip> +#include <exception> + +// Weisstein, Eric W. "Bessel Function Zeros." From MathWorld--A Wolfram Web Resource. +// http://mathworld.wolfram.com/BesselFunctionZeros.html +// Test values can be calculated using [@wolframalpha.com WolframAplha] +// See also http://dlmf.nist.gov/10.21 + +//[bessel_errors_example_1 + +/*`[h5 Error messages from 'bad' input] + +Another example demonstrates calculating zeros of the Bessel functions +showing the error messages from 'bad' input is handled by throwing exceptions. + +To use the functions for finding zeros of the functions we need: +*/ + #include <boost/math/special_functions/bessel.hpp> + #include <boost/math/special_functions/airy.hpp> + +//] [/bessel_errors_example_1] + +int main() +{ +//[bessel_errors_example_2 + +/*`[tip It is always wise to place all code using Boost.Math inside try'n'catch blocks; +this will ensure that helpful error messages can be shown when exceptional conditions arise.] + +Examples below show messages from several 'bad' arguments that throw a `domain_error` exception. +*/ + try + { // Try a zero order v. + float dodgy_root = boost::math::cyl_bessel_j_zero(0.F, 0); + std::cout << "boost::math::cyl_bessel_j_zero(0.F, 0) " << dodgy_root << std::endl; + // Thrown exception Error in function boost::math::cyl_bessel_j_zero<double>(double, int): + // Requested the 0'th zero of J0, but the rank must be > 0 ! + } + catch (std::exception& ex) + { + std::cout << "Thrown exception " << ex.what() << std::endl; + } + +/*`[note The type shown in the error message is the type [*after promotion], +using __precision_policy and __promotion_policy, from `float` to `double` in this case.] + +In this example the promotion goes: + +# Arguments are `float` and `int`. +# Treat `int` "as if" it were a `double`, so arguments are `float` and `double`. +# Common type is `double` - so that's the precision we want (and the type that will be returned). +# Evaluate internally as `double` for full `float` precision. + +See full code for other examples that promote from `double` to `long double`. + +Other examples of 'bad' inputs like infinity and NaN are below. +Some compiler warnings indicate that 'bad' values are detected at compile time. +*/ + + try + { // order v = inf + std::cout << "boost::math::cyl_bessel_j_zero(inf, 1) " << std::endl; + double inf = std::numeric_limits<double>::infinity(); + double inf_root = boost::math::cyl_bessel_j_zero(inf, 1); + std::cout << "boost::math::cyl_bessel_j_zero(inf, 1) " << inf_root << std::endl; + // Throw exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, unsigned): + // Order argument is 1.#INF, but must be finite >= 0 ! + } + catch (std::exception& ex) + { + std::cout << "Thrown exception " << ex.what() << std::endl; + } + + try + { // order v = NaN, rank m = 1 + std::cout << "boost::math::cyl_bessel_j_zero(nan, 1) " << std::endl; + double nan = std::numeric_limits<double>::quiet_NaN(); + double nan_root = boost::math::cyl_bessel_j_zero(nan, 1); + std::cout << "boost::math::cyl_bessel_j_zero(nan, 1) " << nan_root << std::endl; + // Throw exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, unsigned): + // Order argument is 1.#QNAN, but must be finite >= 0 ! + } + catch (std::exception& ex) + { + std::cout << "Thrown exception " << ex.what() << std::endl; + } + +/*`The output from other examples are shown appended to the full code listing. +*/ +//] [/bessel_errors_example_2] + try + { // Try a zero rank m. + std::cout << "boost::math::cyl_neumann_zero(0.0, 0) " << std::endl; + double dodgy_root = boost::math::cyl_bessel_j_zero(0.0, 0); + // warning C4146: unary minus operator applied to unsigned type, result still unsigned. + std::cout << "boost::math::cyl_neumann_zero(0.0, -1) " << dodgy_root << std::endl; + // boost::math::cyl_neumann_zero(0.0, -1) 6.74652e+009 + // This *should* fail because m is unreasonably large. + + } + catch (std::exception& ex) + { + std::cout << "Thrown exception " << ex.what() << std::endl; + } + + try + { // m = inf + std::cout << "boost::math::cyl_bessel_j_zero(0.0, inf) " << std::endl; + double inf = std::numeric_limits<double>::infinity(); + double inf_root = boost::math::cyl_bessel_j_zero(0.0, inf); + // warning C4244: 'argument' : conversion from 'double' to 'int', possible loss of data. + std::cout << "boost::math::cyl_bessel_j_zero(0.0, inf) " << inf_root << std::endl; + // Throw exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, int): + // Requested the 0'th zero, but must be > 0 ! + + } + catch (std::exception& ex) + { + std::cout << "Thrown exception " << ex.what() << std::endl; + } + + try + { // m = NaN + double nan = std::numeric_limits<double>::quiet_NaN(); + double nan_root = boost::math::airy_ai_zero<double>(nan); + // warning C4244: 'argument' : conversion from 'double' to 'int', possible loss of data. + std::cout << "boost::math::airy_ai_zero<double>(nan) " << nan_root << std::endl; + // Thrown exception Error in function boost::math::airy_ai_zero<double>(double,double): + // The requested rank of the zero is 0, but must be 1 or more ! + } + catch (std::exception& ex) + { + std::cout << "Thrown exception " << ex.what() << std::endl; + } + } // int main() + +/* +Output: + + Description: Autorun "J:\Cpp\big_number\Debug\bessel_errors_example.exe" + Thrown exception Error in function boost::math::cyl_bessel_j_zero<double>(double, int): Requested the 0'th zero of J0, but the rank must be > 0 ! + boost::math::cyl_bessel_j_zero(inf, 1) + Thrown exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, int): Order argument is 1.#INF, but must be finite >= 0 ! + boost::math::cyl_bessel_j_zero(nan, 1) + Thrown exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, int): Order argument is 1.#QNAN, but must be finite >= 0 ! + boost::math::cyl_neumann_zero(0.0, 0) + Thrown exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, int): Requested the 0'th zero of J0, but the rank must be > 0 ! + boost::math::cyl_bessel_j_zero(0.0, inf) + Thrown exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, int): Requested the -2147483648'th zero, but the rank must be positive ! + Thrown exception Error in function boost::math::airy_ai_zero<double>(double,double): The requested rank of the zero is 0, but must be 1 or more ! + + +*/ + diff --git a/src/boost/libs/math/example/bessel_zeros_example.cpp b/src/boost/libs/math/example/bessel_zeros_example.cpp new file mode 100644 index 000000000..0d3ec3ccc --- /dev/null +++ b/src/boost/libs/math/example/bessel_zeros_example.cpp @@ -0,0 +1,447 @@ +// Copyright Christopher Kormanyos 2013. +// Copyright Paul A. Bristow 2013. +// Copyright John Maddock 2013. + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http://www.boost.org/LICENSE_1_0.txt). + +#ifdef _MSC_VER +# pragma warning (disable : 4512) // assignment operator could not be generated. +# pragma warning (disable : 4996) // assignment operator could not be generated. +#endif + +#include <iostream> +#include <limits> +#include <vector> +#include <algorithm> +#include <iomanip> +#include <iterator> + +// Weisstein, Eric W. "Bessel Function Zeros." From MathWorld--A Wolfram Web Resource. +// http://mathworld.wolfram.com/BesselFunctionZeros.html +// Test values can be calculated using [@wolframalpha.com WolframAplha] +// See also http://dlmf.nist.gov/10.21 + +//[bessel_zero_example_1 + +/*`This example demonstrates calculating zeros of the Bessel, Neumann and Airy functions. +It also shows how Boost.Math and Boost.Multiprecision can be combined to provide +a many decimal digit precision. For 50 decimal digit precision we need to include +*/ + + #include <boost/multiprecision/cpp_dec_float.hpp> + +/*`and a `typedef` for `float_type` may be convenient +(allowing a quick switch to re-compute at built-in `double` or other precision) +*/ + typedef boost::multiprecision::cpp_dec_float_50 float_type; + +//`To use the functions for finding zeros of the functions we need + + #include <boost/math/special_functions/bessel.hpp> + +//`This file includes the forward declaration signatures for the zero-finding functions: + +// #include <boost/math/special_functions/math_fwd.hpp> + +/*`but more details are in the full documentation, for example at +[@http://www.boost.org/doc/libs/1_53_0/libs/math/doc/sf_and_dist/html/math_toolkit/special/bessel/bessel_over.html Boost.Math Bessel functions] +*/ + +/*`This example shows obtaining both a single zero of the Bessel function, +and then placing multiple zeros into a container like `std::vector` by providing an iterator. +The signature of the single value function is: + + template <class T> + inline typename detail::bessel_traits<T, T, policies::policy<> >::result_type + cyl_bessel_j_zero(T v, // Floating-point value for Jv. + int m); // start index. + +The result type is controlled by the floating-point type of parameter `v` +(but subject to the usual __precision_policy and __promotion_policy). + +The signature of multiple zeros function is: + + template <class T, class OutputIterator> + inline OutputIterator cyl_bessel_j_zero(T v, // Floating-point value for Jv. + int start_index, // 1-based start index. + unsigned number_of_zeros, + OutputIterator out_it); // iterator into container for zeros. + +There is also a version which allows control of the __policy_section for error handling and precision. + + template <class T, class OutputIterator, class Policy> + inline OutputIterator cyl_bessel_j_zero(T v, // Floating-point value for Jv. + int start_index, // 1-based start index. + unsigned number_of_zeros, + OutputIterator out_it, + const Policy& pol); // iterator into container for zeros. + +*/ +//] [/bessel_zero_example_1] + +//[bessel_zero_example_iterator_1] +/*`We use the `cyl_bessel_j_zero` output iterator parameter `out_it` +to create a sum of 1/zeros[super 2] by defining a custom output iterator: +*/ + +template <class T> +struct output_summation_iterator +{ + output_summation_iterator(T* p) : p_sum(p) + {} + output_summation_iterator& operator*() + { return *this; } + output_summation_iterator& operator++() + { return *this; } + output_summation_iterator& operator++(int) + { return *this; } + output_summation_iterator& operator = (T const& val) + { + *p_sum += 1./ (val * val); // Summing 1/zero^2. + return *this; + } +private: + T* p_sum; +}; + + +//] [/bessel_zero_example_iterator_1] + +int main() +{ + try + { +//[bessel_zero_example_2] + +/*`[tip It is always wise to place code using Boost.Math inside try'n'catch blocks; +this will ensure that helpful error messages can be shown when exceptional conditions arise.] + +First, evaluate a single Bessel zero. + +The precision is controlled by the float-point type of template parameter `T` of `v` +so this example has `double` precision, at least 15 but up to 17 decimal digits (for the common 64-bit double). +*/ + double root = boost::math::cyl_bessel_j_zero(0.0, 1); + // Displaying with default precision of 6 decimal digits: + std::cout << "boost::math::cyl_bessel_j_zero(0.0, 1) " << root << std::endl; // 2.40483 + // And with all the guaranteed (15) digits: + std::cout.precision(std::numeric_limits<double>::digits10); + std::cout << "boost::math::cyl_bessel_j_zero(0.0, 1) " << root << std::endl; // 2.40482555769577 +/*`But note that because the parameter `v` controls the precision of the result, +`v` [*must be a floating-point type]. +So if you provide an integer type, say 0, rather than 0.0, then it will fail to compile thus: +`` + root = boost::math::cyl_bessel_j_zero(0, 1); +`` +with this error message +`` + error C2338: Order must be a floating-point type. +`` + +Optionally, we can use a policy to ignore errors, C-style, returning some value +perhaps infinity or NaN, or the best that can be done. (See __user_error_handling). + +To create a (possibly unwise!) policy that ignores all errors: +*/ + + typedef boost::math::policies::policy + < + boost::math::policies::domain_error<boost::math::policies::ignore_error>, + boost::math::policies::overflow_error<boost::math::policies::ignore_error>, + boost::math::policies::underflow_error<boost::math::policies::ignore_error>, + boost::math::policies::denorm_error<boost::math::policies::ignore_error>, + boost::math::policies::pole_error<boost::math::policies::ignore_error>, + boost::math::policies::evaluation_error<boost::math::policies::ignore_error> + > ignore_all_policy; + + double inf = std::numeric_limits<double>::infinity(); + double nan = std::numeric_limits<double>::quiet_NaN(); + + std::cout << "boost::math::cyl_bessel_j_zero(-1.0, 0) " << std::endl; + double dodgy_root = boost::math::cyl_bessel_j_zero(-1.0, 0, ignore_all_policy()); + std::cout << "boost::math::cyl_bessel_j_zero(-1.0, 1) " << dodgy_root << std::endl; // 1.#QNAN + double inf_root = boost::math::cyl_bessel_j_zero(inf, 1, ignore_all_policy()); + std::cout << "boost::math::cyl_bessel_j_zero(inf, 1) " << inf_root << std::endl; // 1.#QNAN + double nan_root = boost::math::cyl_bessel_j_zero(nan, 1, ignore_all_policy()); + std::cout << "boost::math::cyl_bessel_j_zero(nan, 1) " << nan_root << std::endl; // 1.#QNAN + +/*`Another version of `cyl_bessel_j_zero` allows calculation of multiple zeros with one call, +placing the results in a container, often `std::vector`. +For example, generate five `double` roots of J[sub v] for integral order 2. + +showing the same results as column J[sub 2](x) in table 1 of +[@ http://mathworld.wolfram.com/BesselFunctionZeros.html Wolfram Bessel Function Zeros]. + +*/ + unsigned int n_roots = 5U; + std::vector<double> roots; + boost::math::cyl_bessel_j_zero(2.0, 1, n_roots, std::back_inserter(roots)); + std::copy(roots.begin(), + roots.end(), + std::ostream_iterator<double>(std::cout, "\n")); + +/*`Or generate 50 decimal digit roots of J[sub v] for non-integral order `v = 71/19`. + +We set the precision of the output stream and show trailing zeros to display a fixed 50 decimal digits. +*/ + std::cout.precision(std::numeric_limits<float_type>::digits10); // 50 decimal digits. + std::cout << std::showpoint << std::endl; // Show trailing zeros. + + float_type x = float_type(71) / 19; + float_type r = boost::math::cyl_bessel_j_zero(x, 1); // 1st root. + std::cout << "x = " << x << ", r = " << r << std::endl; + + r = boost::math::cyl_bessel_j_zero(x, 20U); // 20th root. + std::cout << "x = " << x << ", r = " << r << std::endl; + + std::vector<float_type> zeros; + boost::math::cyl_bessel_j_zero(x, 1, 3, std::back_inserter(zeros)); + + std::cout << "cyl_bessel_j_zeros" << std::endl; + // Print the roots to the output stream. + std::copy(zeros.begin(), zeros.end(), + std::ostream_iterator<float_type>(std::cout, "\n")); + +/*`The Neumann function zeros are evaluated very similarly: +*/ + using boost::math::cyl_neumann_zero; + + double zn = cyl_neumann_zero(2., 1); + + std::cout << "cyl_neumann_zero(2., 1) = " << std::endl; + //double zn0 = zn; + // std::cout << "zn0 = " << std::endl; + // std::cout << zn0 << std::endl; + // + std::cout << zn << std::endl; + // std::cout << cyl_neumann_zero(2., 1) << std::endl; + + std::vector<float> nzeros(3); // Space for 3 zeros. + cyl_neumann_zero<float>(2.F, 1, nzeros.size(), nzeros.begin()); + + std::cout << "cyl_neumann_zero<float>(2.F, 1, " << std::endl; + // Print the zeros to the output stream. + std::copy(nzeros.begin(), nzeros.end(), + std::ostream_iterator<float>(std::cout, "\n")); + + std::cout << cyl_neumann_zero(static_cast<float_type>(220)/100, 1) << std::endl; + // 3.6154383428745996706772556069431792744372398748422 + +/*`Finally we show how the output iterator can be used to compute a sum of zeros. + +(See [@https://doi.org/10.1017/S2040618500034067 Ian N. Sneddon, Infinite Sums of Bessel Zeros], +page 150 equation 40). +*/ +//] [/bessel_zero_example_2] + + { +//[bessel_zero_example_iterator_2] +/*`The sum is calculated for many values, converging on the analytical exact value of `1/8`. +*/ + using boost::math::cyl_bessel_j_zero; + double nu = 1.; + double sum = 0; + output_summation_iterator<double> it(&sum); // sum of 1/zeros^2 + cyl_bessel_j_zero(nu, 1, 10000, it); + + double s = 1/(4 * (nu + 1)); // 0.125 = 1/8 is exact analytical solution. + std::cout << std::setprecision(6) << "nu = " << nu << ", sum = " << sum + << ", exact = " << s << std::endl; + // nu = 1.00000, sum = 0.124990, exact = 0.125000 +//] [/bessel_zero_example_iterator_2] + } + } + catch (std::exception& ex) + { + std::cout << "Thrown exception " << ex.what() << std::endl; + } + +//[bessel_zero_example_iterator_3] + +/*`Examples below show effect of 'bad' arguments that throw a `domain_error` exception. +*/ + try + { // Try a negative rank m. + std::cout << "boost::math::cyl_bessel_j_zero(-1.F, -1) " << std::endl; + float dodgy_root = boost::math::cyl_bessel_j_zero(-1.F, -1); + std::cout << "boost::math::cyl_bessel_j_zero(-1.F, -1) " << dodgy_root << std::endl; + // Throw exception Error in function boost::math::cyl_bessel_j_zero<double>(double, int): + // Order argument is -1, but must be >= 0 ! + } + catch (std::exception& ex) + { + std::cout << "Throw exception " << ex.what() << std::endl; + } + +/*`[note The type shown is the type [*after promotion], +using __precision_policy and __promotion_policy, from `float` to `double` in this case.] + +In this example the promotion goes: + +# Arguments are `float` and `int`. +# Treat `int` "as if" it were a `double`, so arguments are `float` and `double`. +# Common type is `double` - so that's the precision we want (and the type that will be returned). +# Evaluate internally as `long double` for full `double` precision. + +See full code for other examples that promote from `double` to `long double`. + +*/ + +//] [/bessel_zero_example_iterator_3] + try + { // order v = inf + std::cout << "boost::math::cyl_bessel_j_zero(infF, 1) " << std::endl; + float infF = std::numeric_limits<float>::infinity(); + float inf_root = boost::math::cyl_bessel_j_zero(infF, 1); + std::cout << "boost::math::cyl_bessel_j_zero(infF, 1) " << inf_root << std::endl; + // boost::math::cyl_bessel_j_zero(-1.F, -1) + //Thrown exception Error in function boost::math::cyl_bessel_j_zero<double>(double, int): + // Requested the -1'th zero, but the rank must be positive ! + } + catch (std::exception& ex) + { + std::cout << "Thrown exception " << ex.what() << std::endl; + } + try + { // order v = inf + double inf = std::numeric_limits<double>::infinity(); + double inf_root = boost::math::cyl_bessel_j_zero(inf, 1); + std::cout << "boost::math::cyl_bessel_j_zero(inf, 1) " << inf_root << std::endl; + // Throw exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, unsigned): + // Order argument is 1.#INF, but must be finite >= 0 ! + } + catch (std::exception& ex) + { + std::cout << "Thrown exception " << ex.what() << std::endl; + } + + try + { // order v = NaN + double nan = std::numeric_limits<double>::quiet_NaN(); + double nan_root = boost::math::cyl_bessel_j_zero(nan, 1); + std::cout << "boost::math::cyl_bessel_j_zero(nan, 1) " << nan_root << std::endl; + // Throw exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, unsigned): + // Order argument is 1.#QNAN, but must be finite >= 0 ! + } + catch (std::exception& ex) + { + std::cout << "Thrown exception " << ex.what() << std::endl; + } + + try + { // Try a negative m. + double dodgy_root = boost::math::cyl_bessel_j_zero(0.0, -1); + // warning C4146: unary minus operator applied to unsigned type, result still unsigned. + std::cout << "boost::math::cyl_bessel_j_zero(0.0, -1) " << dodgy_root << std::endl; + // boost::math::cyl_bessel_j_zero(0.0, -1) 6.74652e+009 + // This *should* fail because m is unreasonably large. + + } + catch (std::exception& ex) + { + std::cout << "Thrown exception " << ex.what() << std::endl; + } + + try + { // m = inf + double inf = std::numeric_limits<double>::infinity(); + double inf_root = boost::math::cyl_bessel_j_zero(0.0, inf); + // warning C4244: 'argument' : conversion from 'double' to 'int', possible loss of data. + std::cout << "boost::math::cyl_bessel_j_zero(0.0, inf) " << inf_root << std::endl; + // Throw exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, int): + // Requested the 0'th zero, but must be > 0 ! + + } + catch (std::exception& ex) + { + std::cout << "Thrown exception " << ex.what() << std::endl; + } + + try + { // m = NaN + std::cout << "boost::math::cyl_bessel_j_zero(0.0, nan) " << std::endl ; + double nan = std::numeric_limits<double>::quiet_NaN(); + double nan_root = boost::math::cyl_bessel_j_zero(0.0, nan); + // warning C4244: 'argument' : conversion from 'double' to 'int', possible loss of data. + std::cout << nan_root << std::endl; + // Throw exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, int): + // Requested the 0'th zero, but must be > 0 ! + } + catch (std::exception& ex) + { + std::cout << "Thrown exception " << ex.what() << std::endl; + } + + } // int main() + +/* +Mathematica: Table[N[BesselJZero[71/19, n], 50], {n, 1, 20, 1}] + +7.2731751938316489503185694262290765588963196701623 +10.724858308883141732536172745851416647110749599085 +14.018504599452388106120459558042660282427471931581 +17.25249845917041718216248716654977734919590383861 +20.456678874044517595180234083894285885460502077814 +23.64363089714234522494551422714731959985405172504 +26.819671140255087745421311470965019261522390519297 +29.988343117423674742679141796661432043878868194142 +33.151796897690520871250862469973445265444791966114 +36.3114160002162074157243540350393860813165201842 +39.468132467505236587945197808083337887765967032029 +42.622597801391236474855034831297954018844433480227 +45.775281464536847753390206207806726581495950012439 +48.926530489173566198367766817478553992471739894799 +52.076607045343002794279746041878924876873478063472 +55.225712944912571393594224327817265689059002890192 +58.374006101538886436775188150439025201735151418932 +61.521611873000965273726742659353136266390944103571 +64.66863105379093036834648221487366079456596628716 +67.815145619696290925556791375555951165111460585458 + +Mathematica: Table[N[BesselKZero[2, n], 50], {n, 1, 5, 1}] +n | +1 | 3.3842417671495934727014260185379031127323883259329 +2 | 6.7938075132682675382911671098369487124493222183854 +3 | 10.023477979360037978505391792081418280789658279097 + + +*/ + + /* +[bessel_zero_output] + + boost::math::cyl_bessel_j_zero(0.0, 1) 2.40483 + boost::math::cyl_bessel_j_zero(0.0, 1) 2.40482555769577 + boost::math::cyl_bessel_j_zero(-1.0, 1) 1.#QNAN + boost::math::cyl_bessel_j_zero(inf, 1) 1.#QNAN + boost::math::cyl_bessel_j_zero(nan, 1) 1.#QNAN + 5.13562230184068 + 8.41724414039986 + 11.6198411721491 + 14.7959517823513 + 17.9598194949878 + + x = 3.7368421052631578947368421052631578947368421052632, r = 7.2731751938316489503185694262290765588963196701623 + x = 3.7368421052631578947368421052631578947368421052632, r = 67.815145619696290925556791375555951165111460585458 + 7.2731751938316489503185694262290765588963196701623 + 10.724858308883141732536172745851416647110749599085 + 14.018504599452388106120459558042660282427471931581 + cyl_neumann_zero(2., 1) = 3.3842417671495935000000000000000000000000000000000 + 3.3842418193817139000000000000000000000000000000000 + 6.7938075065612793000000000000000000000000000000000 + 10.023477554321289000000000000000000000000000000000 + 3.6154383428745996706772556069431792744372398748422 + nu = 1.00000, sum = 0.124990, exact = 0.125000 + Throw exception Error in function boost::math::cyl_bessel_j_zero<double>(double, int): Order argument is -1, but must be >= 0 ! + Throw exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, int): Order argument is 1.#INF, but must be finite >= 0 ! + Throw exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, int): Order argument is 1.#QNAN, but must be finite >= 0 ! + Throw exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, int): Requested the -1'th zero, but must be > 0 ! + Throw exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, int): Requested the -2147483648'th zero, but must be > 0 ! + Throw exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, int): Requested the -2147483648'th zero, but must be > 0 ! + + +] [/bessel_zero_output] +*/ + diff --git a/src/boost/libs/math/example/bessel_zeros_example_1.cpp b/src/boost/libs/math/example/bessel_zeros_example_1.cpp new file mode 100644 index 000000000..59172cd02 --- /dev/null +++ b/src/boost/libs/math/example/bessel_zeros_example_1.cpp @@ -0,0 +1,213 @@ + +// Copyright Christopher Kormanyos 2013. +// Copyright Paul A. Bristow 2013. +// Copyright John Maddock 2013. + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http://www.boost.org/LICENSE_1_0.txt). + +#ifdef _MSC_VER +# pragma warning (disable : 4512) // assignment operator could not be generated. +# pragma warning (disable : 4996) // assignment operator could not be generated. +#endif + +#include <iostream> +#include <limits> +#include <vector> +#include <algorithm> +#include <iomanip> +#include <iterator> + +// Weisstein, Eric W. "Bessel Function Zeros." From MathWorld--A Wolfram Web Resource. +// http://mathworld.wolfram.com/BesselFunctionZeros.html +// Test values can be calculated using [@wolframalpha.com WolframAplha] +// See also http://dlmf.nist.gov/10.21 + +//[bessel_zeros_example_1 + +/*`This example demonstrates calculating zeros of the Bessel and Neumann functions. +It also shows how Boost.Math and Boost.Multiprecision can be combined to provide +a many decimal digit precision. For 50 decimal digit precision we need to include +*/ + + #include <boost/multiprecision/cpp_dec_float.hpp> + +/*`and a `typedef` for `float_type` may be convenient +(allowing a quick switch to re-compute at built-in `double` or other precision) +*/ + typedef boost::multiprecision::cpp_dec_float_50 float_type; + +//`To use the functions for finding zeros of the functions we need + + #include <boost/math/special_functions/bessel.hpp> + +//`This file includes the forward declaration signatures for the zero-finding functions: + +// #include <boost/math/special_functions/math_fwd.hpp> + +/*`but more details are in the full documentation, for example at +[@http://www.boost.org/doc/libs/1_53_0/libs/math/doc/sf_and_dist/html/math_toolkit/special/bessel/bessel_over.html Boost.Math Bessel functions]. +*/ + +/*`This example shows obtaining both a single zero of the Bessel function, +and then placing multiple zeros into a container like `std::vector` by providing an iterator. +*/ +//] [/bessel_zeros_example_1] + +/*The signature of the single value function is: + + template <class T> + inline typename detail::bessel_traits<T, T, policies::policy<> >::result_type + cyl_bessel_j_zero( + T v, // Floating-point value for Jv. + int m); // start index. + +The result type is controlled by the floating-point type of parameter `v` +(but subject to the usual __precision_policy and __promotion_policy). + +The signature of multiple zeros function is: + + template <class T, class OutputIterator> + inline OutputIterator cyl_bessel_j_zero( + T v, // Floating-point value for Jv. + int start_index, // 1-based start index. + unsigned number_of_zeros, // How many zeros to generate + OutputIterator out_it); // Destination for zeros. + +There is also a version which allows control of the __policy_section for error handling and precision. + + template <class T, class OutputIterator, class Policy> + inline OutputIterator cyl_bessel_j_zero( + T v, // Floating-point value for Jv. + int start_index, // 1-based start index. + unsigned number_of_zeros, // How many zeros to generate + OutputIterator out_it, // Destination for zeros. + const Policy& pol); // Policy to use. +*/ + +int main() +{ + try + { +//[bessel_zeros_example_2 + +/*`[tip It is always wise to place code using Boost.Math inside try'n'catch blocks; +this will ensure that helpful error messages are shown when exceptional conditions arise.] + +First, evaluate a single Bessel zero. + +The precision is controlled by the float-point type of template parameter `T` of `v` +so this example has `double` precision, at least 15 but up to 17 decimal digits (for the common 64-bit double). +*/ +// double root = boost::math::cyl_bessel_j_zero(0.0, 1); +// // Displaying with default precision of 6 decimal digits: +// std::cout << "boost::math::cyl_bessel_j_zero(0.0, 1) " << root << std::endl; // 2.40483 +// // And with all the guaranteed (15) digits: +// std::cout.precision(std::numeric_limits<double>::digits10); +// std::cout << "boost::math::cyl_bessel_j_zero(0.0, 1) " << root << std::endl; // 2.40482555769577 +/*`But note that because the parameter `v` controls the precision of the result, +`v` [*must be a floating-point type]. +So if you provide an integer type, say 0, rather than 0.0, then it will fail to compile thus: +`` + root = boost::math::cyl_bessel_j_zero(0, 1); +`` +with this error message +`` + error C2338: Order must be a floating-point type. +`` + +Optionally, we can use a policy to ignore errors, C-style, returning some value, +perhaps infinity or NaN, or the best that can be done. (See __user_error_handling). + +To create a (possibly unwise!) policy `ignore_all_policy` that ignores all errors: +*/ + + typedef boost::math::policies::policy< + boost::math::policies::domain_error<boost::math::policies::ignore_error>, + boost::math::policies::overflow_error<boost::math::policies::ignore_error>, + boost::math::policies::underflow_error<boost::math::policies::ignore_error>, + boost::math::policies::denorm_error<boost::math::policies::ignore_error>, + boost::math::policies::pole_error<boost::math::policies::ignore_error>, + boost::math::policies::evaluation_error<boost::math::policies::ignore_error> + > ignore_all_policy; + //`Examples of use of this `ignore_all_policy` are + + double inf = std::numeric_limits<double>::infinity(); + double nan = std::numeric_limits<double>::quiet_NaN(); + + double dodgy_root = boost::math::cyl_bessel_j_zero(-1.0, 1, ignore_all_policy()); + std::cout << "boost::math::cyl_bessel_j_zero(-1.0, 1) " << dodgy_root << std::endl; // 1.#QNAN + double inf_root = boost::math::cyl_bessel_j_zero(inf, 1, ignore_all_policy()); + std::cout << "boost::math::cyl_bessel_j_zero(inf, 1) " << inf_root << std::endl; // 1.#QNAN + double nan_root = boost::math::cyl_bessel_j_zero(nan, 1, ignore_all_policy()); + std::cout << "boost::math::cyl_bessel_j_zero(nan, 1) " << nan_root << std::endl; // 1.#QNAN + +/*`Another version of `cyl_bessel_j_zero` allows calculation of multiple zeros with one call, +placing the results in a container, often `std::vector`. +For example, generate and display the first five `double` roots of J[sub v] for integral order 2, +as column ['J[sub 2](x)] in table 1 of +[@ http://mathworld.wolfram.com/BesselFunctionZeros.html Wolfram Bessel Function Zeros]. +*/ + unsigned int n_roots = 5U; + std::vector<double> roots; + boost::math::cyl_bessel_j_zero(2.0, 1, n_roots, std::back_inserter(roots)); + std::copy(roots.begin(), + roots.end(), + std::ostream_iterator<double>(std::cout, "\n")); + +/*`Or we can use Boost.Multiprecision to generate 50 decimal digit roots of ['J[sub v]] +for non-integral order `v= 71/19 == 3.736842`, expressed as an exact-integer fraction +to generate the most accurate value possible for all floating-point types. + +We set the precision of the output stream, and show trailing zeros to display a fixed 50 decimal digits. +*/ + std::cout.precision(std::numeric_limits<float_type>::digits10); // 50 decimal digits. + std::cout << std::showpoint << std::endl; // Show trailing zeros. + + float_type x = float_type(71) / 19; + float_type r = boost::math::cyl_bessel_j_zero(x, 1); // 1st root. + std::cout << "x = " << x << ", r = " << r << std::endl; + + r = boost::math::cyl_bessel_j_zero(x, 20U); // 20th root. + std::cout << "x = " << x << ", r = " << r << std::endl; + + std::vector<float_type> zeros; + boost::math::cyl_bessel_j_zero(x, 1, 3, std::back_inserter(zeros)); + + std::cout << "cyl_bessel_j_zeros" << std::endl; + // Print the roots to the output stream. + std::copy(zeros.begin(), zeros.end(), + std::ostream_iterator<float_type>(std::cout, "\n")); +//] [/bessel_zeros_example_2] + } + catch (std::exception const& ex) + { + std::cout << "Thrown exception " << ex.what() << std::endl; + } + + } // int main() + + /* + + Output: + + Description: Autorun "J:\Cpp\big_number\Debug\bessel_zeros_example_1.exe" + boost::math::cyl_bessel_j_zero(-1.0, 1) 3.83171 + boost::math::cyl_bessel_j_zero(inf, 1) 1.#QNAN + boost::math::cyl_bessel_j_zero(nan, 1) 1.#QNAN + 5.13562 + 8.41724 + 11.6198 + 14.796 + 17.9598 + + x = 3.7368421052631578947368421052631578947368421052632, r = 7.2731751938316489503185694262290765588963196701623 + x = 3.7368421052631578947368421052631578947368421052632, r = 67.815145619696290925556791375555951165111460585458 + cyl_bessel_j_zeros + 7.2731751938316489503185694262290765588963196701623 + 10.724858308883141732536172745851416647110749599085 + 14.018504599452388106120459558042660282427471931581 + +*/ + diff --git a/src/boost/libs/math/example/bessel_zeros_interator_example.cpp b/src/boost/libs/math/example/bessel_zeros_interator_example.cpp new file mode 100644 index 000000000..a92a2704a --- /dev/null +++ b/src/boost/libs/math/example/bessel_zeros_interator_example.cpp @@ -0,0 +1,88 @@ +// Copyright Christopher Kormanyos 2013. +// Copyright Paul A. Bristow 2013. +// Copyright John Maddock 2013. + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http://www.boost.org/LICENSE_1_0.txt). + +#ifdef _MSC_VER +# pragma warning (disable : 4512) // assignment operator could not be generated. +# pragma warning (disable : 4996) // assignment operator could not be generated. +#endif + +#include <iostream> +#include <limits> +#include <vector> +#include <algorithm> +#include <iomanip> +#include <iterator> + +//[bessel_zeros_iterator_example_1 + +/*`[h5 Using Output Iterator to sum zeros of Bessel Functions] + +This example demonstrates summing zeros of the Bessel functions. +To use the functions for finding zeros of the functions we need + */ + +#include <boost/math/special_functions/bessel.hpp> + +/*`We use the `cyl_bessel_j_zero` output iterator parameter `out_it` +to create a sum of ['1/zeros[super 2]] by defining a custom output iterator: +*/ + +template <class T> +struct output_summation_iterator +{ + output_summation_iterator(T* p) : p_sum(p) + {} + output_summation_iterator& operator*() + { return *this; } + output_summation_iterator& operator++() + { return *this; } + output_summation_iterator& operator++(int) + { return *this; } + output_summation_iterator& operator = (T const& val) + { + *p_sum += 1./ (val * val); // Summing 1/zero^2. + return *this; + } +private: + T* p_sum; +}; + +//] [/bessel_zeros_iterator_example_1] + +int main() +{ + try + { +//[bessel_zeros_iterator_example_2 + +/*`The sum is calculated for many values, converging on the analytical exact value of `1/8`. +*/ + using boost::math::cyl_bessel_j_zero; + double nu = 1.; + double sum = 0; + output_summation_iterator<double> it(&sum); // sum of 1/zeros^2 + cyl_bessel_j_zero(nu, 1, 10000, it); + + double s = 1/(4 * (nu + 1)); // 0.125 = 1/8 is exact analytical solution. + std::cout << std::setprecision(6) << "nu = " << nu << ", sum = " << sum + << ", exact = " << s << std::endl; + // nu = 1.00000, sum = 0.124990, exact = 0.125000 +//] [/bessel_zeros_iterator_example_2] + } + catch (std::exception const& ex) + { + std::cout << "Thrown exception " << ex.what() << std::endl; + } + return 0; + } // int_main() + +/* + Output: + + nu = 1, sum = 0.12499, exact = 0.125 +*/ diff --git a/src/boost/libs/math/example/big_seventh.cpp b/src/boost/libs/math/example/big_seventh.cpp new file mode 100644 index 000000000..7f3a3b0d9 --- /dev/null +++ b/src/boost/libs/math/example/big_seventh.cpp @@ -0,0 +1,204 @@ +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Copyright Paul A. Bristow 2019. +// Copyright Christopher Kormanyos 2012. +// Copyright John Maddock 2012. + +// This file is written to be included from a Quickbook .qbk document. +// It can be compiled by the C++ compiler, and run. Any output can +// also be added here as comment or included or pasted in elsewhere. +// Caution: this file contains Quickbook markup as well as code +// and comments: don't change any of the special comment markups! + +#ifdef _MSC_VER +#pragma warning(disable : 4512) // assignment operator could not be generated. +#pragma warning(disable : 4996) +#endif + +//[big_seventh_example_1 + +/*`[h5 Using Boost.Multiprecision `cpp_float` types for numerical calculations with higher precision than built-in `long double`.] + +The Boost.Multiprecision library can be used for computations requiring precision +exceeding that of standard built-in types such as `float`, `double` +and `long double`. For extended-precision calculations, Boost.Multiprecision +supplies several template data types called `cpp_bin_float_`. + +The number of decimal digits of precision is fixed at compile-time via template parameter. + +To use these floating-point types and +[@https://www.boost.org/doc/libs/release/libs/math/doc/html/constants.html Boost.Math collection of high-precision constants], +we need some includes: +*/ + +#include <boost/math/constants/constants.hpp> + +#include <boost/multiprecision/cpp_bin_float.hpp> +// that includes some predefined typedefs that can be used thus: +// using boost::multiprecision::cpp_bin_float_quad; +// using boost::multiprecision::cpp_bin_float_50; +// using boost::multiprecision::cpp_bin_float_100; + +#include <iostream> +#include <limits> +#include <type_traits> + +/*` So now we can demonstrate with some trivial calculations: +*/ + +//] //[big_seventh_example_1] + +void no_et() +{ + using namespace boost::multiprecision; + + std::cout.setf(std::ios_base::boolalpha); + + typedef number<backends::cpp_bin_float<113, backends::digit_base_2, void, boost::int16_t, -16382, 16383>, et_on> cpp_bin_float_quad_et_on; + typedef number<backends::cpp_bin_float<113, backends::digit_base_2, void, boost::int16_t, -16382, 16383>, et_off> cpp_bin_float_quad_et_off; + + typedef number<backends::cpp_bin_float<113, backends::digit_base_2, void, boost::int16_t, -16382, 16383>, et_off> cpp_bin_float_oct; + + + cpp_bin_float_quad x("42."); + std::cout << "cpp_bin_float_quad x = " << x << std::endl; + + cpp_bin_float_quad_et_on q("42."); + + std::cout << "std::is_same<cpp_bin_float_quad, cpp_bin_float_quad_et_off>::value is " << std::is_same<cpp_bin_float_quad, cpp_bin_float_quad_et_off>::value << std::endl; + std::cout << "std::is_same<cpp_bin_float_quad, cpp_bin_float_quad_et_on>::value is " << std::is_same<cpp_bin_float_quad, cpp_bin_float_quad_et_on>::value << std::endl; + + std::cout << "cpp_bin_float_quad_et_on q = " << q << std::endl; + cpp_bin_float_50 y("42."); // typedef number<backends::cpp_bin_float<50> > cpp_bin_float_50; + + std::cout << "cpp_bin_float_50 y = " << y << std::endl; + + typedef number<backends::cpp_bin_float<50>, et_off > cpp_bin_float_50_no_et; + typedef number<backends::cpp_bin_float<50>, et_on > cpp_bin_float_50_et; + + cpp_bin_float_50_no_et z("42."); // typedef number<backends::cpp_bin_float<50> > cpp_bin_float_50; + + std::cout << "cpp_bin_float_50_no_et z = " << z << std::endl; + + std::cout << " std::is_same<cpp_bin_float_50, cpp_bin_float_50_no_et>::value is " << std::is_same<cpp_bin_float_50, cpp_bin_float_50_no_et>::value << std::endl; + std::cout << " std::is_same<cpp_bin_float_50_et, cpp_bin_float_50_no_et>::value is " << std::is_same<cpp_bin_float_50_et, cpp_bin_float_50_no_et>::value << std::endl; + +} // void no_et() + +int main() +{ + + no_et(); + + return 0; + + + //[big_seventh_example_2 + /*`Using `typedef cpp_bin_float_50` hides the complexity of multiprecision, +allows us to define variables with 50 decimal digit precision just like built-in `double`. +*/ + using boost::multiprecision::cpp_bin_float_50; + + cpp_bin_float_50 seventh = cpp_bin_float_50(1) / 7; // 1 / 7 + + /*`By default, output would only show the standard 6 decimal digits, + so set precision to show all 50 significant digits, including any trailing zeros. +*/ + std::cout.precision(std::numeric_limits<cpp_bin_float_50>::digits10); + std::cout << std::showpoint << std::endl; // Append any trailing zeros. + std::cout << seventh << std::endl; + /*`which outputs: + + 0.14285714285714285714285714285714285714285714285714 + +We can also use __math_constants like [pi], +guaranteed to be initialized with the very last bit of precision (__ULP) for the floating-point type. +*/ + std::cout << "pi = " << boost::math::constants::pi<cpp_bin_float_50>() << std::endl; + cpp_bin_float_50 circumference = boost::math::constants::pi<cpp_bin_float_50>() * 2 * seventh; + std::cout << "c = " << circumference << std::endl; + + /*`which outputs + + pi = 3.1415926535897932384626433832795028841971693993751 + + c = 0.89759790102565521098932668093700082405633411410717 +*/ + //] [/big_seventh_example_2] + + //[big_seventh_example_3 + /*`So using `cpp_bin_float_50` looks like a simple 'drop-in' for the __fundamental_type like 'double', +but beware of loss of precision from construction or conversion from `double` or other lower precision types. +This is a mistake that is very easy to make, +and very difficult to detect because the loss of precision is only visible after the 17th decimal digit. + +We can show this by constructing from `double`, (avoiding the schoolboy-error `double d7 = 1 / 7;` giving zero!) +*/ + + double d7 = 1. / 7; // + std::cout << "d7 = " << d7 << std::endl; + + cpp_bin_float_50 seventh_0 = cpp_bin_float_50(1 / 7); // Avoid the schoolboy-error 1 / 7 == 0!) + std::cout << "seventh_0 = " << seventh_0 << std::endl; + // seventh_double0 = 0.0000000000000000000000000000000000000000000000000 + + cpp_bin_float_50 seventh_double = cpp_bin_float_50(1. / 7); // Construct from double! + std::cout << "seventh_double = " << seventh_double << std::endl; // Boost.Multiprecision post-school error! + // seventh_double = 0.14285714285714284921269268124888185411691665649414 + + /*`Did you spot the mistake? After the 17th decimal digit, result is random! + +14285714285714 should be recurring. +*/ + + cpp_bin_float_50 seventh_big(1); // 1 + seventh_big /= 7; + std::cout << "seventh_big = " << seventh_big << std::endl; // + // seventh_big = 0.14285714285714285714285714285714285714285714285714 + /*`Note the recurring 14285714285714 pattern as expected. + +As one would expect, the variable can be `const` (but sadly [*not yet `constexpr`]). +*/ + + const cpp_bin_float_50 seventh_const(cpp_bin_float_50(1) / 7); + std::cout << "seventh_const = " << seventh_const << std::endl; + // seventh_const = 0.14285714285714285714285714285714285714285714285714 + +/*`The full output is: +*/ + +//] [/big_seventh_example_3 + +//[big_seventh_example_constexpr + +// Sadly we cannot (yet) write: +// constexpr cpp_bin_float_50 any_constexpr(0); + +// constexpr cpp_bin_float_50 seventh_constexpr (cpp_bin_float_50(1) / 7); +// std::cout << "seventh_constexpr = " << seventh_constexpr << std::endl; // +// nor use the macro BOOST_CONSTEXPR_OR_CONST unless it returns `const` +// BOOST_CONSTEXPR_OR_CONST cpp_bin_float_50 seventh_constexpr(seventh_const); + +//] [/big_seventh_example_constexpr + + return 0; +} // int main() + +/* +//[big_seventh_example_output + +0.14285714285714285714285714285714285714285714285714 +pi = 3.1415926535897932384626433832795028841971693993751 +c = 0.89759790102565521098932668093700082405633411410717 +d7 = 0.14285714285714284921269268124888185411691665649414 +seventh_0 = 0.0000000000000000000000000000000000000000000000000 +seventh_double = 0.14285714285714284921269268124888185411691665649414 +seventh_big = 0.14285714285714285714285714285714285714285714285714 +seventh_const = 0.14285714285714285714285714285714285714285714285714 + +//] //[big_seventh_example_output] + +*/ diff --git a/src/boost/libs/math/example/binomial_coinflip_example.cpp b/src/boost/libs/math/example/binomial_coinflip_example.cpp new file mode 100644 index 000000000..5f1826b94 --- /dev/null +++ b/src/boost/libs/math/example/binomial_coinflip_example.cpp @@ -0,0 +1,243 @@ +// Copyright Paul A. 2007, 2010 +// Copyright John Maddock 2006 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Simple example of computing probabilities and quantiles for +// a Bernoulli random variable representing the flipping of a coin. + +// http://mathworld.wolfram.com/CoinTossing.html +// http://en.wikipedia.org/wiki/Bernoulli_trial +// Weisstein, Eric W. "Dice." From MathWorld--A Wolfram Web Resource. +// http://mathworld.wolfram.com/Dice.html +// http://en.wikipedia.org/wiki/Bernoulli_distribution +// http://mathworld.wolfram.com/BernoulliDistribution.html +// +// An idealized coin consists of a circular disk of zero thickness which, +// when thrown in the air and allowed to fall, will rest with either side face up +// ("heads" H or "tails" T) with equal probability. A coin is therefore a two-sided die. +// Despite slight differences between the sides and nonzero thickness of actual coins, +// the distribution of their tosses makes a good approximation to a p==1/2 Bernoulli distribution. + +//[binomial_coinflip_example1 + +/*`An example of a [@http://en.wikipedia.org/wiki/Bernoulli_process Bernoulli process] +is coin flipping. +A variable in such a sequence may be called a Bernoulli variable. + +This example shows using the Binomial distribution to predict the probability +of heads and tails when throwing a coin. + +The number of correct answers (say heads), +X, is distributed as a binomial random variable +with binomial distribution parameters number of trials (flips) n = 10 and probability (success_fraction) of getting a head p = 0.5 (a 'fair' coin). + +(Our coin is assumed fair, but we could easily change the success_fraction parameter p +from 0.5 to some other value to simulate an unfair coin, +say 0.6 for one with chewing gum on the tail, +so it is more likely to fall tails down and heads up). + +First we need some includes and using statements to be able to use the binomial distribution, some std input and output, and get started: +*/ + +#include <boost/math/distributions/binomial.hpp> + using boost::math::binomial; + +#include <iostream> + using std::cout; using std::endl; using std::left; +#include <iomanip> + using std::setw; + +int main() +{ + cout << "Using Binomial distribution to predict how many heads and tails." << endl; + try + { +/*` +See note [link coinflip_eg_catch with the catch block] +about why a try and catch block is always a good idea. + +First, construct a binomial distribution with parameters success_fraction +1/2, and how many flips. +*/ + const double success_fraction = 0.5; // = 50% = 1/2 for a 'fair' coin. + int flips = 10; + binomial flip(flips, success_fraction); + + cout.precision(4); +/*` + Then some examples of using Binomial moments (and echoing the parameters). +*/ + cout << "From " << flips << " one can expect to get on average " + << mean(flip) << " heads (or tails)." << endl; + cout << "Mode is " << mode(flip) << endl; + cout << "Standard deviation is " << standard_deviation(flip) << endl; + cout << "So about 2/3 will lie within 1 standard deviation and get between " + << ceil(mean(flip) - standard_deviation(flip)) << " and " + << floor(mean(flip) + standard_deviation(flip)) << " correct." << endl; + cout << "Skewness is " << skewness(flip) << endl; + // Skewness of binomial distributions is only zero (symmetrical) + // if success_fraction is exactly one half, + // for example, when flipping 'fair' coins. + cout << "Skewness if success_fraction is " << flip.success_fraction() + << " is " << skewness(flip) << endl << endl; // Expect zero for a 'fair' coin. +/*` +Now we show a variety of predictions on the probability of heads: +*/ + cout << "For " << flip.trials() << " coin flips: " << endl; + cout << "Probability of getting no heads is " << pdf(flip, 0) << endl; + cout << "Probability of getting at least one head is " << 1. - pdf(flip, 0) << endl; +/*` +When we want to calculate the probability for a range or values we can sum the PDF's: +*/ + cout << "Probability of getting 0 or 1 heads is " + << pdf(flip, 0) + pdf(flip, 1) << endl; // sum of exactly == probabilities +/*` +Or we can use the cdf. +*/ + cout << "Probability of getting 0 or 1 (<= 1) heads is " << cdf(flip, 1) << endl; + cout << "Probability of getting 9 or 10 heads is " << pdf(flip, 9) + pdf(flip, 10) << endl; +/*` +Note that using +*/ + cout << "Probability of getting 9 or 10 heads is " << 1. - cdf(flip, 8) << endl; +/*` +is less accurate than using the complement +*/ + cout << "Probability of getting 9 or 10 heads is " << cdf(complement(flip, 8)) << endl; +/*` +Since the subtraction may involve +[@http://docs.sun.com/source/806-3568/ncg_goldberg.html cancellation error], +where as `cdf(complement(flip, 8))` +does not use such a subtraction internally, and so does not exhibit the problem. + +To get the probability for a range of heads, we can either add the pdfs for each number of heads +*/ + cout << "Probability of between 4 and 6 heads (4 or 5 or 6) is " + // P(X == 4) + P(X == 5) + P(X == 6) + << pdf(flip, 4) + pdf(flip, 5) + pdf(flip, 6) << endl; +/*` +But this is probably less efficient than using the cdf +*/ + cout << "Probability of between 4 and 6 heads (4 or 5 or 6) is " + // P(X <= 6) - P(X <= 3) == P(X < 4) + << cdf(flip, 6) - cdf(flip, 3) << endl; +/*` +Certainly for a bigger range like, 3 to 7 +*/ + cout << "Probability of between 3 and 7 heads (3, 4, 5, 6 or 7) is " + // P(X <= 7) - P(X <= 2) == P(X < 3) + << cdf(flip, 7) - cdf(flip, 2) << endl; + cout << endl; + +/*` +Finally, print two tables of probability for the /exactly/ and /at least/ a number of heads. +*/ + // Print a table of probability for the exactly a number of heads. + cout << "Probability of getting exactly (==) heads" << endl; + for (int successes = 0; successes <= flips; successes++) + { // Say success means getting a head (or equally success means getting a tail). + double probability = pdf(flip, successes); + cout << left << setw(2) << successes << " " << setw(10) + << probability << " or 1 in " << 1. / probability + << ", or " << probability * 100. << "%" << endl; + } // for i + cout << endl; + + // Tabulate the probability of getting between zero heads and 0 up to 10 heads. + cout << "Probability of getting up to (<=) heads" << endl; + for (int successes = 0; successes <= flips; successes++) + { // Say success means getting a head + // (equally success could mean getting a tail). + double probability = cdf(flip, successes); // P(X <= heads) + cout << setw(2) << successes << " " << setw(10) << left + << probability << " or 1 in " << 1. / probability << ", or " + << probability * 100. << "%"<< endl; + } // for i +/*` +The last (0 to 10 heads) must, of course, be 100% probability. +*/ + double probability = 0.3; + double q = quantile(flip, probability); + std::cout << "Quantile (flip, " << probability << ") = " << q << std::endl; // Quantile (flip, 0.3) = 3 + probability = 0.6; + q = quantile(flip, probability); + std::cout << "Quantile (flip, " << probability << ") = " << q << std::endl; // Quantile (flip, 0.6) = 5 + } + catch(const std::exception& e) + { + // + /*` + [#coinflip_eg_catch] + It is always essential to include try & catch blocks because + default policies are to throw exceptions on arguments that + are out of domain or cause errors like numeric-overflow. + + Lacking try & catch blocks, the program will abort, whereas the + message below from the thrown exception will give some helpful + clues as to the cause of the problem. + */ + std::cout << + "\n""Message from thrown exception was:\n " << e.what() << std::endl; + } +//] [binomial_coinflip_example1] + return 0; +} // int main() + +// Output: + +//[binomial_coinflip_example_output +/*` + +[pre +Using Binomial distribution to predict how many heads and tails. +From 10 one can expect to get on average 5 heads (or tails). +Mode is 5 +Standard deviation is 1.581 +So about 2/3 will lie within 1 standard deviation and get between 4 and 6 correct. +Skewness is 0 +Skewness if success_fraction is 0.5 is 0 + +For 10 coin flips: +Probability of getting no heads is 0.0009766 +Probability of getting at least one head is 0.999 +Probability of getting 0 or 1 heads is 0.01074 +Probability of getting 0 or 1 (<= 1) heads is 0.01074 +Probability of getting 9 or 10 heads is 0.01074 +Probability of getting 9 or 10 heads is 0.01074 +Probability of getting 9 or 10 heads is 0.01074 +Probability of between 4 and 6 heads (4 or 5 or 6) is 0.6562 +Probability of between 4 and 6 heads (4 or 5 or 6) is 0.6563 +Probability of between 3 and 7 heads (3, 4, 5, 6 or 7) is 0.8906 + +Probability of getting exactly (==) heads +0 0.0009766 or 1 in 1024, or 0.09766% +1 0.009766 or 1 in 102.4, or 0.9766% +2 0.04395 or 1 in 22.76, or 4.395% +3 0.1172 or 1 in 8.533, or 11.72% +4 0.2051 or 1 in 4.876, or 20.51% +5 0.2461 or 1 in 4.063, or 24.61% +6 0.2051 or 1 in 4.876, or 20.51% +7 0.1172 or 1 in 8.533, or 11.72% +8 0.04395 or 1 in 22.76, or 4.395% +9 0.009766 or 1 in 102.4, or 0.9766% +10 0.0009766 or 1 in 1024, or 0.09766% + +Probability of getting up to (<=) heads +0 0.0009766 or 1 in 1024, or 0.09766% +1 0.01074 or 1 in 93.09, or 1.074% +2 0.05469 or 1 in 18.29, or 5.469% +3 0.1719 or 1 in 5.818, or 17.19% +4 0.377 or 1 in 2.653, or 37.7% +5 0.623 or 1 in 1.605, or 62.3% +6 0.8281 or 1 in 1.208, or 82.81% +7 0.9453 or 1 in 1.058, or 94.53% +8 0.9893 or 1 in 1.011, or 98.93% +9 0.999 or 1 in 1.001, or 99.9% +10 1 or 1 in 1, or 100% +] +*/ +//][/binomial_coinflip_example_output] diff --git a/src/boost/libs/math/example/binomial_confidence_limits.cpp b/src/boost/libs/math/example/binomial_confidence_limits.cpp new file mode 100644 index 000000000..56ab48c36 --- /dev/null +++ b/src/boost/libs/math/example/binomial_confidence_limits.cpp @@ -0,0 +1,165 @@ +// Copyright John Maddock 2006 +// Copyright Paul A. Bristow 2010 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifdef _MSC_VER +# pragma warning(disable: 4512) // assignment operator could not be generated. +# pragma warning(disable: 4510) // default constructor could not be generated. +# pragma warning(disable: 4610) // can never be instantiated - user defined constructor required. +#endif + +#include <iostream> +using std::cout; using std::endl; +#include <iomanip> +using std::fixed; using std::left; using std::right; using std::right; using std::setw; +using std::setprecision; + +#include <boost/math/distributions/binomial.hpp> + +void confidence_limits_on_frequency(unsigned trials, unsigned successes) +{ + // + // trials = Total number of trials. + // successes = Total number of observed successes. + // + // Calculate confidence limits for an observed + // frequency of occurrence that follows a binomial distribution. + // + //using namespace std; // Avoid + // using namespace boost::math; // potential name ambiguity with std <random> + using boost::math::binomial_distribution; + + // Print out general info: + cout << + "___________________________________________\n" + "2-Sided Confidence Limits For Success Ratio\n" + "___________________________________________\n\n"; + cout << setprecision(7); + cout << setw(40) << left << "Number of Observations" << "= " << trials << "\n"; + cout << setw(40) << left << "Number of successes" << "= " << successes << "\n"; + cout << setw(40) << left << "Sample frequency of occurrence" << "= " << double(successes) / trials << "\n"; + // + // Define a table of significance levels: + // + double alpha[] = { 0.5, 0.25, 0.1, 0.05, 0.01, 0.001, 0.0001, 0.00001 }; + // + // Print table header: + // + cout << "\n\n" + "_______________________________________________________________________\n" + "Confidence Lower CP Upper CP Lower JP Upper JP\n" + " Value (%) Limit Limit Limit Limit\n" + "_______________________________________________________________________\n"; + // + // Now print out the data for the table rows. + // + for(unsigned i = 0; i < sizeof(alpha)/sizeof(alpha[0]); ++i) + { + // Confidence value: + cout << fixed << setprecision(3) << setw(10) << right << 100 * (1-alpha[i]); + // Calculate Clopper Pearson bounds: + double l = binomial_distribution<>::find_lower_bound_on_p(trials, successes, alpha[i]/2); + double u = binomial_distribution<>::find_upper_bound_on_p(trials, successes, alpha[i]/2); + // Print Clopper Pearson Limits: + cout << fixed << setprecision(5) << setw(15) << right << l; + cout << fixed << setprecision(5) << setw(15) << right << u; + // Calculate Jeffreys Prior Bounds: + l = binomial_distribution<>::find_lower_bound_on_p(trials, successes, alpha[i]/2, binomial_distribution<>::jeffreys_prior_interval); + u = binomial_distribution<>::find_upper_bound_on_p(trials, successes, alpha[i]/2, binomial_distribution<>::jeffreys_prior_interval); + // Print Jeffreys Prior Limits: + cout << fixed << setprecision(5) << setw(15) << right << l; + cout << fixed << setprecision(5) << setw(15) << right << u << std::endl; + } + cout << endl; +} // void confidence_limits_on_frequency() + +int main() +{ + confidence_limits_on_frequency(20, 4); + confidence_limits_on_frequency(200, 40); + confidence_limits_on_frequency(2000, 400); + + return 0; +} // int main() + +/* + +------ Build started: Project: binomial_confidence_limits, Configuration: Debug Win32 ------ +Compiling... +binomial_confidence_limits.cpp +Linking... +Autorun "i:\boost-06-05-03-1300\libs\math\test\Math_test\debug\binomial_confidence_limits.exe" +___________________________________________ +2-Sided Confidence Limits For Success Ratio +___________________________________________ + +Number of Observations = 20 +Number of successes = 4 +Sample frequency of occurrence = 0.2 + + +_______________________________________________________________________ +Confidence Lower CP Upper CP Lower JP Upper JP + Value (%) Limit Limit Limit Limit +_______________________________________________________________________ + 50.000 0.12840 0.29588 0.14974 0.26916 + 75.000 0.09775 0.34633 0.11653 0.31861 + 90.000 0.07135 0.40103 0.08734 0.37274 + 95.000 0.05733 0.43661 0.07152 0.40823 + 99.000 0.03576 0.50661 0.04655 0.47859 + 99.900 0.01905 0.58632 0.02634 0.55960 + 99.990 0.01042 0.64997 0.01530 0.62495 + 99.999 0.00577 0.70216 0.00901 0.67897 + +___________________________________________ +2-Sided Confidence Limits For Success Ratio +___________________________________________ + +Number of Observations = 200 +Number of successes = 40 +Sample frequency of occurrence = 0.2000000 + + +_______________________________________________________________________ +Confidence Lower CP Upper CP Lower JP Upper JP + Value (%) Limit Limit Limit Limit +_______________________________________________________________________ + 50.000 0.17949 0.22259 0.18190 0.22001 + 75.000 0.16701 0.23693 0.16934 0.23429 + 90.000 0.15455 0.25225 0.15681 0.24956 + 95.000 0.14689 0.26223 0.14910 0.25951 + 99.000 0.13257 0.28218 0.13468 0.27940 + 99.900 0.11703 0.30601 0.11902 0.30318 + 99.990 0.10489 0.32652 0.10677 0.32366 + 99.999 0.09492 0.34485 0.09670 0.34197 + +___________________________________________ +2-Sided Confidence Limits For Success Ratio +___________________________________________ + +Number of Observations = 2000 +Number of successes = 400 +Sample frequency of occurrence = 0.2000000 + + +_______________________________________________________________________ +Confidence Lower CP Upper CP Lower JP Upper JP + Value (%) Limit Limit Limit Limit +_______________________________________________________________________ + 50.000 0.19382 0.20638 0.19406 0.20613 + 75.000 0.18965 0.21072 0.18990 0.21047 + 90.000 0.18537 0.21528 0.18561 0.21503 + 95.000 0.18267 0.21821 0.18291 0.21796 + 99.000 0.17745 0.22400 0.17769 0.22374 + 99.900 0.17150 0.23079 0.17173 0.23053 + 99.990 0.16658 0.23657 0.16681 0.23631 + 99.999 0.16233 0.24169 0.16256 0.24143 + +*/ + + + diff --git a/src/boost/libs/math/example/binomial_example_nag.cpp b/src/boost/libs/math/example/binomial_example_nag.cpp new file mode 100644 index 000000000..152558c76 --- /dev/null +++ b/src/boost/libs/math/example/binomial_example_nag.cpp @@ -0,0 +1,91 @@ +// Copyright Paul A. 2007, 2010 +// Copyright John Maddock 2007 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Simple example of computing probabilities for a binomial random variable. +// Replication of source nag_binomial_dist (g01bjc). + +// Shows how to replace NAG C library calls by Boost Math Toolkit C++ calls. +// Note that the default policy does not replicate the way that NAG +// library calls handle 'bad' arguments, but you can define policies that do, +// as well as other policies that may suit your application even better. +// See the examples of changing default policies for details. + +#include <boost/math/distributions/binomial.hpp> + +#include <iostream> + using std::cout; using std::endl; using std::ios; using std::showpoint; +#include <iomanip> + using std::fixed; using std::setw; + +int main() +{ + cout << "Using the binomial distribution to replicate a NAG library call." << endl; + using boost::math::binomial_distribution; + + // This replicates the computation of the examples of using nag-binomial_dist + // using g01bjc in section g01 Simple Calculations on Statistical Data. + // http://www.nag.co.uk/numeric/cl/manual/pdf/G01/g01bjc.pdf + // Program results section 8.3 page 3.g01bjc.3 + //8.2. Program Data + //g01bjc Example Program Data + //4 0.50 2 : n, p, k + //19 0.44 13 + //100 0.75 67 + //2000 0.33 700 + //8.3. Program Results + //g01bjc Example Program Results + //n p k plek pgtk peqk + //4 0.500 2 0.68750 0.31250 0.37500 + //19 0.440 13 0.99138 0.00862 0.01939 + //100 0.750 67 0.04460 0.95540 0.01700 + //2000 0.330 700 0.97251 0.02749 0.00312 + + cout.setf(ios::showpoint); // Trailing zeros to show significant decimal digits. + cout.precision(5); // Might calculate this from trials in distribution? + cout << fixed; + // Binomial distribution. + + // Note that cdf(dist, k) is equivalent to NAG library plek probability of <= k + // cdf(complement(dist, k)) is equivalent to NAG library pgtk probability of > k + // pdf(dist, k) is equivalent to NAG library peqk probability of == k + + cout << " n p k plek pgtk peqk " << endl; + binomial_distribution<>my_dist(4, 0.5); + cout << setw(4) << (int)my_dist.trials() << " " << my_dist.success_fraction() + << " " << 2 << " " << cdf(my_dist, 2) << " " + << cdf(complement(my_dist, 2)) << " " << pdf(my_dist, 2) << endl; + + binomial_distribution<>two(19, 0.440); + cout << setw(4) << (int)two.trials() << " " << two.success_fraction() + << " " << 13 << " " << cdf(two, 13) << " " + << cdf(complement(two, 13)) << " " << pdf(two, 13) << endl; + + binomial_distribution<>three(100, 0.750); + cout << setw(4) << (int)three.trials() << " " << three.success_fraction() + << " " << 67 << " " << cdf(three, 67) << " " << cdf(complement(three, 67)) + << " " << pdf(three, 67) << endl; + binomial_distribution<>four(2000, 0.330); + cout << setw(4) << (int)four.trials() << " " << four.success_fraction() + << " " << 700 << " " + << cdf(four, 700) << " " << cdf(complement(four, 700)) + << " " << pdf(four, 700) << endl; + + return 0; +} // int main() + +/* + +Example of using the binomial distribution to replicate a NAG library call. + n p k plek pgtk peqk + 4 0.50000 2 0.68750 0.31250 0.37500 + 19 0.44000 13 0.99138 0.00862 0.01939 + 100 0.75000 67 0.04460 0.95540 0.01700 +2000 0.33000 700 0.97251 0.02749 0.00312 + + + */ + diff --git a/src/boost/libs/math/example/binomial_quiz_example.cpp b/src/boost/libs/math/example/binomial_quiz_example.cpp new file mode 100644 index 000000000..acf06e2da --- /dev/null +++ b/src/boost/libs/math/example/binomial_quiz_example.cpp @@ -0,0 +1,525 @@ +// Copyright Paul A. Bristow 2007, 2009, 2010 +// Copyright John Maddock 2006 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// binomial_examples_quiz.cpp + +// Simple example of computing probabilities and quantiles for a binomial random variable +// representing the correct guesses on a multiple-choice test. + +// source http://www.stat.wvu.edu/SRS/Modules/Binomial/test.html + +//[binomial_quiz_example1 +/*` +A multiple choice test has four possible answers to each of 16 questions. +A student guesses the answer to each question, +so the probability of getting a correct answer on any given question is +one in four, a quarter, 1/4, 25% or fraction 0.25. +The conditions of the binomial experiment are assumed to be met: +n = 16 questions constitute the trials; +each question results in one of two possible outcomes (correct or incorrect); +the probability of being correct is 0.25 and is constant if no knowledge about the subject is assumed; +the questions are answered independently if the student's answer to a question +in no way influences his/her answer to another question. + +First, we need to be able to use the binomial distribution constructor +(and some std input/output, of course). +*/ + +#include <boost/math/distributions/binomial.hpp> + using boost::math::binomial; + +#include <iostream> + using std::cout; using std::endl; + using std::ios; using std::flush; using std::left; using std::right; using std::fixed; +#include <iomanip> + using std::setw; using std::setprecision; +#include <exception> + + + +//][/binomial_quiz_example1] + +int main() +{ + try + { + cout << "Binomial distribution example - guessing in a quiz." << endl; +//[binomial_quiz_example2 +/*` +The number of correct answers, X, is distributed as a binomial random variable +with binomial distribution parameters: questions n and success fraction probability p. +So we construct a binomial distribution: +*/ + int questions = 16; // All the questions in the quiz. + int answers = 4; // Possible answers to each question. + double success_fraction = 1. / answers; // If a random guess, p = 1/4 = 0.25. + binomial quiz(questions, success_fraction); +/*` +and display the distribution parameters we used thus: +*/ + cout << "In a quiz with " << quiz.trials() + << " questions and with a probability of guessing right of " + << quiz.success_fraction() * 100 << " %" + << " or 1 in " << static_cast<int>(1. / quiz.success_fraction()) << endl; +/*` +Show a few probabilities of just guessing: +*/ + cout << "Probability of getting none right is " << pdf(quiz, 0) << endl; // 0.010023 + cout << "Probability of getting exactly one right is " << pdf(quiz, 1) << endl; + cout << "Probability of getting exactly two right is " << pdf(quiz, 2) << endl; + int pass_score = 11; + cout << "Probability of getting exactly " << pass_score << " answers right by chance is " + << pdf(quiz, pass_score) << endl; + cout << "Probability of getting all " << questions << " answers right by chance is " + << pdf(quiz, questions) << endl; +/*` +[pre +Probability of getting none right is 0.0100226 +Probability of getting exactly one right is 0.0534538 +Probability of getting exactly two right is 0.133635 +Probability of getting exactly 11 right is 0.000247132 +Probability of getting exactly all 16 answers right by chance is 2.32831e-010 +] +These don't give any encouragement to guessers! + +We can tabulate the 'getting exactly right' ( == ) probabilities thus: +*/ + cout << "\n" "Guessed Probability" << right << endl; + for (int successes = 0; successes <= questions; successes++) + { + double probability = pdf(quiz, successes); + cout << setw(2) << successes << " " << probability << endl; + } + cout << endl; +/*` +[pre +Guessed Probability + 0 0.0100226 + 1 0.0534538 + 2 0.133635 + 3 0.207876 + 4 0.225199 + 5 0.180159 + 6 0.110097 + 7 0.0524273 + 8 0.0196602 + 9 0.00582526 +10 0.00135923 +11 0.000247132 +12 3.43239e-005 +13 3.5204e-006 +14 2.51457e-007 +15 1.11759e-008 +16 2.32831e-010 +] +Then we can add the probabilities of some 'exactly right' like this: +*/ + cout << "Probability of getting none or one right is " << pdf(quiz, 0) + pdf(quiz, 1) << endl; + +/*` +[pre +Probability of getting none or one right is 0.0634764 +] +But if more than a couple of scores are involved, it is more convenient (and may be more accurate) +to use the Cumulative Distribution Function (cdf) instead: +*/ + cout << "Probability of getting none or one right is " << cdf(quiz, 1) << endl; +/*` +[pre +Probability of getting none or one right is 0.0634764 +] +Since the cdf is inclusive, we can get the probability of getting up to 10 right ( <= ) +*/ + cout << "Probability of getting <= 10 right (to fail) is " << cdf(quiz, 10) << endl; +/*` +[pre +Probability of getting <= 10 right (to fail) is 0.999715 +] +To get the probability of getting 11 or more right (to pass), +it is tempting to use ``1 - cdf(quiz, 10)`` to get the probability of > 10 +*/ + cout << "Probability of getting > 10 right (to pass) is " << 1 - cdf(quiz, 10) << endl; +/*` +[pre +Probability of getting > 10 right (to pass) is 0.000285239 +] +But this should be resisted in favor of using the __complements function (see __why_complements). +*/ + cout << "Probability of getting > 10 right (to pass) is " << cdf(complement(quiz, 10)) << endl; +/*` +[pre +Probability of getting > 10 right (to pass) is 0.000285239 +] +And we can check that these two, <= 10 and > 10, add up to unity. +*/ +BOOST_ASSERT((cdf(quiz, 10) + cdf(complement(quiz, 10))) == 1.); +/*` +If we want a < rather than a <= test, because the CDF is inclusive, we must subtract one from the score. +*/ + cout << "Probability of getting less than " << pass_score + << " (< " << pass_score << ") answers right by guessing is " + << cdf(quiz, pass_score -1) << endl; +/*` +[pre +Probability of getting less than 11 (< 11) answers right by guessing is 0.999715 +] +and similarly to get a >= rather than a > test +we also need to subtract one from the score (and can again check the sum is unity). +This is because if the cdf is /inclusive/, +then its complement must be /exclusive/ otherwise there would be one possible +outcome counted twice! +*/ + cout << "Probability of getting at least " << pass_score + << "(>= " << pass_score << ") answers right by guessing is " + << cdf(complement(quiz, pass_score-1)) + << ", only 1 in " << 1/cdf(complement(quiz, pass_score-1)) << endl; + + BOOST_ASSERT((cdf(quiz, pass_score -1) + cdf(complement(quiz, pass_score-1))) == 1); + +/*` +[pre +Probability of getting at least 11 (>= 11) answers right by guessing is 0.000285239, only 1 in 3505.83 +] +Finally we can tabulate some probabilities: +*/ + cout << "\n" "At most (<=)""\n""Guessed OK Probability" << right << endl; + for (int score = 0; score <= questions; score++) + { + cout << setw(2) << score << " " << setprecision(10) + << cdf(quiz, score) << endl; + } + cout << endl; +/*` +[pre +At most (<=) +Guessed OK Probability + 0 0.01002259576 + 1 0.0634764398 + 2 0.1971110499 + 3 0.4049871101 + 4 0.6301861752 + 5 0.8103454274 + 6 0.9204427481 + 7 0.9728700437 + 8 0.9925302796 + 9 0.9983555346 +10 0.9997147608 +11 0.9999618928 +12 0.9999962167 +13 0.9999997371 +14 0.9999999886 +15 0.9999999998 +16 1 +] +*/ + cout << "\n" "At least (>)""\n""Guessed OK Probability" << right << endl; + for (int score = 0; score <= questions; score++) + { + cout << setw(2) << score << " " << setprecision(10) + << cdf(complement(quiz, score)) << endl; + } +/*` +[pre +At least (>) +Guessed OK Probability + 0 0.9899774042 + 1 0.9365235602 + 2 0.8028889501 + 3 0.5950128899 + 4 0.3698138248 + 5 0.1896545726 + 6 0.07955725188 + 7 0.02712995629 + 8 0.00746972044 + 9 0.001644465374 +10 0.0002852391917 +11 3.810715862e-005 +12 3.783265129e-006 +13 2.628657967e-007 +14 1.140870154e-008 +15 2.328306437e-010 +16 0 +] +We now consider the probabilities of *ranges* of correct guesses. + +First, calculate the probability of getting a range of guesses right, +by adding the exact probabilities of each from low ... high. +*/ + int low = 3; // Getting at least 3 right. + int high = 5; // Getting as most 5 right. + double sum = 0.; + for (int i = low; i <= high; i++) + { + sum += pdf(quiz, i); + } + cout.precision(4); + cout << "Probability of getting between " + << low << " and " << high << " answers right by guessing is " + << sum << endl; // 0.61323 +/*` +[pre +Probability of getting between 3 and 5 answers right by guessing is 0.6132 +] +Or, usually better, we can use the difference of cdfs instead: +*/ + cout << "Probability of getting between " << low << " and " << high << " answers right by guessing is " + << cdf(quiz, high) - cdf(quiz, low - 1) << endl; // 0.61323 +/*` +[pre +Probability of getting between 3 and 5 answers right by guessing is 0.6132 +] +And we can also try a few more combinations of high and low choices: +*/ + low = 1; high = 6; + cout << "Probability of getting between " << low << " and " << high << " answers right by guessing is " + << cdf(quiz, high) - cdf(quiz, low - 1) << endl; // 1 and 6 P= 0.91042 + low = 1; high = 8; + cout << "Probability of getting between " << low << " and " << high << " answers right by guessing is " + << cdf(quiz, high) - cdf(quiz, low - 1) << endl; // 1 <= x 8 P = 0.9825 + low = 4; high = 4; + cout << "Probability of getting between " << low << " and " << high << " answers right by guessing is " + << cdf(quiz, high) - cdf(quiz, low - 1) << endl; // 4 <= x 4 P = 0.22520 + +/*` +[pre +Probability of getting between 1 and 6 answers right by guessing is 0.9104 +Probability of getting between 1 and 8 answers right by guessing is 0.9825 +Probability of getting between 4 and 4 answers right by guessing is 0.2252 +] +[h4 Using Binomial distribution moments] +Using moments of the distribution, we can say more about the spread of results from guessing. +*/ + cout << "By guessing, on average, one can expect to get " << mean(quiz) << " correct answers." << endl; + cout << "Standard deviation is " << standard_deviation(quiz) << endl; + cout << "So about 2/3 will lie within 1 standard deviation and get between " + << ceil(mean(quiz) - standard_deviation(quiz)) << " and " + << floor(mean(quiz) + standard_deviation(quiz)) << " correct." << endl; + cout << "Mode (the most frequent) is " << mode(quiz) << endl; + cout << "Skewness is " << skewness(quiz) << endl; + +/*` +[pre +By guessing, on average, one can expect to get 4 correct answers. +Standard deviation is 1.732 +So about 2/3 will lie within 1 standard deviation and get between 3 and 5 correct. +Mode (the most frequent) is 4 +Skewness is 0.2887 +] +[h4 Quantiles] +The quantiles (percentiles or percentage points) for a few probability levels: +*/ + cout << "Quartiles " << quantile(quiz, 0.25) << " to " + << quantile(complement(quiz, 0.25)) << endl; // Quartiles + cout << "1 standard deviation " << quantile(quiz, 0.33) << " to " + << quantile(quiz, 0.67) << endl; // 1 sd + cout << "Deciles " << quantile(quiz, 0.1) << " to " + << quantile(complement(quiz, 0.1))<< endl; // Deciles + cout << "5 to 95% " << quantile(quiz, 0.05) << " to " + << quantile(complement(quiz, 0.05))<< endl; // 5 to 95% + cout << "2.5 to 97.5% " << quantile(quiz, 0.025) << " to " + << quantile(complement(quiz, 0.025)) << endl; // 2.5 to 97.5% + cout << "2 to 98% " << quantile(quiz, 0.02) << " to " + << quantile(complement(quiz, 0.02)) << endl; // 2 to 98% + + cout << "If guessing then percentiles 1 to 99% will get " << quantile(quiz, 0.01) + << " to " << quantile(complement(quiz, 0.01)) << " right." << endl; +/*` +Notice that these output integral values because the default policy is `integer_round_outwards`. +[pre +Quartiles 2 to 5 +1 standard deviation 2 to 5 +Deciles 1 to 6 +5 to 95% 0 to 7 +2.5 to 97.5% 0 to 8 +2 to 98% 0 to 8 +] +*/ + +//] [/binomial_quiz_example2] + +//[discrete_quantile_real +/*` +Quantiles values are controlled by the __understand_dis_quant quantile policy chosen. +The default is `integer_round_outwards`, +so the lower quantile is rounded down, and the upper quantile is rounded up. + +But we might believe that the real values tell us a little more - see __math_discrete. + +We could control the policy for *all* distributions by + + #define BOOST_MATH_DISCRETE_QUANTILE_POLICY real + + at the head of the program would make this policy apply +to this *one, and only*, translation unit. + +Or we can now create a (typedef for) policy that has discrete quantiles real +(here avoiding any 'using namespaces ...' statements): +*/ + using boost::math::policies::policy; + using boost::math::policies::discrete_quantile; + using boost::math::policies::real; + using boost::math::policies::integer_round_outwards; // Default. + typedef boost::math::policies::policy<discrete_quantile<real> > real_quantile_policy; +/*` +Add a custom binomial distribution called ``real_quantile_binomial`` that uses ``real_quantile_policy`` +*/ + using boost::math::binomial_distribution; + typedef binomial_distribution<double, real_quantile_policy> real_quantile_binomial; +/*` +Construct an object of this custom distribution: +*/ + real_quantile_binomial quiz_real(questions, success_fraction); +/*` +And use this to show some quantiles - that now have real rather than integer values. +*/ + cout << "Quartiles " << quantile(quiz, 0.25) << " to " + << quantile(complement(quiz_real, 0.25)) << endl; // Quartiles 2 to 4.6212 + cout << "1 standard deviation " << quantile(quiz_real, 0.33) << " to " + << quantile(quiz_real, 0.67) << endl; // 1 sd 2.6654 4.194 + cout << "Deciles " << quantile(quiz_real, 0.1) << " to " + << quantile(complement(quiz_real, 0.1))<< endl; // Deciles 1.3487 5.7583 + cout << "5 to 95% " << quantile(quiz_real, 0.05) << " to " + << quantile(complement(quiz_real, 0.05))<< endl; // 5 to 95% 0.83739 6.4559 + cout << "2.5 to 97.5% " << quantile(quiz_real, 0.025) << " to " + << quantile(complement(quiz_real, 0.025)) << endl; // 2.5 to 97.5% 0.42806 7.0688 + cout << "2 to 98% " << quantile(quiz_real, 0.02) << " to " + << quantile(complement(quiz_real, 0.02)) << endl; // 2 to 98% 0.31311 7.7880 + + cout << "If guessing, then percentiles 1 to 99% will get " << quantile(quiz_real, 0.01) + << " to " << quantile(complement(quiz_real, 0.01)) << " right." << endl; +/*` +[pre +Real Quantiles +Quartiles 2 to 4.621 +1 standard deviation 2.665 to 4.194 +Deciles 1.349 to 5.758 +5 to 95% 0.8374 to 6.456 +2.5 to 97.5% 0.4281 to 7.069 +2 to 98% 0.3131 to 7.252 +If guessing then percentiles 1 to 99% will get 0 to 7.788 right. +] +*/ + +//] [/discrete_quantile_real] + } + catch(const std::exception& e) + { // Always useful to include try & catch blocks because + // default policies are to throw exceptions on arguments that cause + // errors like underflow, overflow. + // Lacking try & catch blocks, the program will abort without a message below, + // which may give some helpful clues as to the cause of the exception. + std::cout << + "\n""Message from thrown exception was:\n " << e.what() << std::endl; + } + return 0; +} // int main() + + + +/* + +Output is: + +BAutorun "i:\boost-06-05-03-1300\libs\math\test\Math_test\debug\binomial_quiz_example.exe" +Binomial distribution example - guessing in a quiz. +In a quiz with 16 questions and with a probability of guessing right of 25 % or 1 in 4 +Probability of getting none right is 0.0100226 +Probability of getting exactly one right is 0.0534538 +Probability of getting exactly two right is 0.133635 +Probability of getting exactly 11 answers right by chance is 0.000247132 +Probability of getting all 16 answers right by chance is 2.32831e-010 +Guessed Probability + 0 0.0100226 + 1 0.0534538 + 2 0.133635 + 3 0.207876 + 4 0.225199 + 5 0.180159 + 6 0.110097 + 7 0.0524273 + 8 0.0196602 + 9 0.00582526 +10 0.00135923 +11 0.000247132 +12 3.43239e-005 +13 3.5204e-006 +14 2.51457e-007 +15 1.11759e-008 +16 2.32831e-010 +Probability of getting none or one right is 0.0634764 +Probability of getting none or one right is 0.0634764 +Probability of getting <= 10 right (to fail) is 0.999715 +Probability of getting > 10 right (to pass) is 0.000285239 +Probability of getting > 10 right (to pass) is 0.000285239 +Probability of getting less than 11 (< 11) answers right by guessing is 0.999715 +Probability of getting at least 11(>= 11) answers right by guessing is 0.000285239, only 1 in 3505.83 +At most (<=) +Guessed OK Probability + 0 0.01002259576 + 1 0.0634764398 + 2 0.1971110499 + 3 0.4049871101 + 4 0.6301861752 + 5 0.8103454274 + 6 0.9204427481 + 7 0.9728700437 + 8 0.9925302796 + 9 0.9983555346 +10 0.9997147608 +11 0.9999618928 +12 0.9999962167 +13 0.9999997371 +14 0.9999999886 +15 0.9999999998 +16 1 +At least (>) +Guessed OK Probability + 0 0.9899774042 + 1 0.9365235602 + 2 0.8028889501 + 3 0.5950128899 + 4 0.3698138248 + 5 0.1896545726 + 6 0.07955725188 + 7 0.02712995629 + 8 0.00746972044 + 9 0.001644465374 +10 0.0002852391917 +11 3.810715862e-005 +12 3.783265129e-006 +13 2.628657967e-007 +14 1.140870154e-008 +15 2.328306437e-010 +16 0 +Probability of getting between 3 and 5 answers right by guessing is 0.6132 +Probability of getting between 3 and 5 answers right by guessing is 0.6132 +Probability of getting between 1 and 6 answers right by guessing is 0.9104 +Probability of getting between 1 and 8 answers right by guessing is 0.9825 +Probability of getting between 4 and 4 answers right by guessing is 0.2252 +By guessing, on average, one can expect to get 4 correct answers. +Standard deviation is 1.732 +So about 2/3 will lie within 1 standard deviation and get between 3 and 5 correct. +Mode (the most frequent) is 4 +Skewness is 0.2887 +Quartiles 2 to 5 +1 standard deviation 2 to 5 +Deciles 1 to 6 +5 to 95% 0 to 7 +2.5 to 97.5% 0 to 8 +2 to 98% 0 to 8 +If guessing then percentiles 1 to 99% will get 0 to 8 right. +Quartiles 2 to 4.621 +1 standard deviation 2.665 to 4.194 +Deciles 1.349 to 5.758 +5 to 95% 0.8374 to 6.456 +2.5 to 97.5% 0.4281 to 7.069 +2 to 98% 0.3131 to 7.252 +If guessing, then percentiles 1 to 99% will get 0 to 7.788 right. + +*/ + diff --git a/src/boost/libs/math/example/binomial_sample_sizes.cpp b/src/boost/libs/math/example/binomial_sample_sizes.cpp new file mode 100644 index 000000000..db9f85978 --- /dev/null +++ b/src/boost/libs/math/example/binomial_sample_sizes.cpp @@ -0,0 +1,176 @@ +// Copyright John Maddock 2006 +// Copyright Paul A. Bristow 2010 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifdef _MSC_VER +# pragma warning(disable: 4512) // assignment operator could not be generated. +# pragma warning(disable: 4510) // default constructor could not be generated. +# pragma warning(disable: 4610) // can never be instantiated - user defined constructor required. +#endif + +#include <iostream> +using std::cout; using std::endl; +#include <iomanip> +using std::fixed; using std::left; using std::right; using std::right; using std::setw; +using std::setprecision; + +#include <boost/math/distributions/binomial.hpp> + +void find_max_sample_size(double p, unsigned successes) +{ + // + // p = success ratio. + // successes = Total number of observed successes. + // + // Calculate how many trials we can have to ensure the + // maximum number of successes does not exceed "successes". + // A typical use would be failure analysis, where you want + // zero or fewer "successes" with some probability. + // + // using namespace boost::math; + // Avoid potential binomial_distribution name ambiguity with std <random> + using boost::math::binomial_distribution; + + // Print out general info: + cout << + "________________________\n" + "Maximum Number of Trials\n" + "________________________\n\n"; + cout << setprecision(7); + cout << setw(40) << left << "Success ratio" << "= " << p << "\n"; + cout << setw(40) << left << "Maximum Number of \"successes\" permitted" << "= " << successes << "\n"; + // + // Define a table of confidence intervals: + // + double alpha[] = { 0.5, 0.25, 0.1, 0.05, 0.01, 0.001, 0.0001, 0.00001 }; + // + // Print table header: + // + cout << "\n\n" + "____________________________\n" + "Confidence Max Number\n" + " Value (%) Of Trials \n" + "____________________________\n"; + // + // Now print out the data for the table rows. + // + for(unsigned i = 0; i < sizeof(alpha)/sizeof(alpha[0]); ++i) + { + // Confidence value: + cout << fixed << setprecision(3) << setw(10) << right << 100 * (1-alpha[i]); + // calculate trials: + double t = binomial_distribution<>::find_maximum_number_of_trials(successes, p, alpha[i]); + t = floor(t); + // Print Trials: + cout << fixed << setprecision(0) << setw(15) << right << t << endl; + } + cout << endl; +} + +int main() +{ + find_max_sample_size(1.0/1000, 0); + find_max_sample_size(1.0/10000, 0); + find_max_sample_size(1.0/100000, 0); + find_max_sample_size(1.0/1000000, 0); + + return 0; +} + + +/* + +Output: + + binomial_sample_sizes.cpp + binomial_sample_sizes_example.vcxproj -> J:\Cpp\MathToolkit\test\Math_test\Debug\binomial_sample_sizes_example.exe + ________________________ + Maximum Number of Trials + ________________________ + + Success ratio = 0.001 + Maximum Number of "successes" permitted = 0 + + + ____________________________ + Confidence Max Number + Value (%) Of Trials + ____________________________ + 50.000 692 + 75.000 287 + 90.000 105 + 95.000 51 + 99.000 10 + 99.900 0 + 99.990 0 + 99.999 0 + + ________________________ + Maximum Number of Trials + ________________________ + + Success ratio = 0.0001000 + Maximum Number of "successes" permitted = 0 + + + ____________________________ + Confidence Max Number + Value (%) Of Trials + ____________________________ + 50.000 6931 + 75.000 2876 + 90.000 1053 + 95.000 512 + 99.000 100 + 99.900 10 + 99.990 0 + 99.999 0 + + ________________________ + Maximum Number of Trials + ________________________ + + Success ratio = 0.0000100 + Maximum Number of "successes" permitted = 0 + + + ____________________________ + Confidence Max Number + Value (%) Of Trials + ____________________________ + 50.000 69314 + 75.000 28768 + 90.000 10535 + 95.000 5129 + 99.000 1005 + 99.900 100 + 99.990 10 + 99.999 1 + + ________________________ + Maximum Number of Trials + ________________________ + + Success ratio = 0.0000010 + Maximum Number of "successes" permitted = 0 + + + ____________________________ + Confidence Max Number + Value (%) Of Trials + ____________________________ + 50.000 693146 + 75.000 287681 + 90.000 105360 + 95.000 51293 + 99.000 10050 + 99.900 1000 + 99.990 100 + 99.999 10 + + +*/ diff --git a/src/boost/libs/math/example/brent_minimise_example.cpp b/src/boost/libs/math/example/brent_minimise_example.cpp new file mode 100644 index 000000000..09053bd03 --- /dev/null +++ b/src/boost/libs/math/example/brent_minimise_example.cpp @@ -0,0 +1,730 @@ +//! \file +//! \brief Brent_minimise_example.cpp + +// Copyright Paul A. Bristow 2015, 2018. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains Quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +// For some diagnostic information: +//#define BOOST_MATH_INSTRUMENT +// If quadmath float128 is available: +//#define BOOST_HAVE_QUADMATH + +// Example of finding minimum of a function with Brent's method. +//[brent_minimise_include_1 +#include <boost/math/tools/minima.hpp> +//] [/brent_minimise_include_1] + +#include <boost/math/special_functions/next.hpp> +#include <boost/multiprecision/cpp_dec_float.hpp> +#include <boost/math/special_functions/pow.hpp> +#include <boost/math/constants/constants.hpp> +#include <boost/test/tools/floating_point_comparison.hpp> // For is_close_at)tolerance and is_small + +//[brent_minimise_mp_include_0 +#include <boost/multiprecision/cpp_dec_float.hpp> // For decimal boost::multiprecision::cpp_dec_float_50. +#include <boost/multiprecision/cpp_bin_float.hpp> // For binary boost::multiprecision::cpp_bin_float_50; +//] [/brent_minimise_mp_include_0] + +//#ifndef _MSC_VER // float128 is not yet supported by Microsoft compiler at 2018. +#ifdef BOOST_HAVE_QUADMATH // Define only if GCC or Intel, and have quadmath.lib or .dll library available. +# include <boost/multiprecision/float128.hpp> +#endif + +#include <iostream> +// using std::cout; using std::endl; +#include <iomanip> +// using std::setw; using std::setprecision; +#include <limits> +using std::numeric_limits; +#include <tuple> +#include <utility> // pair, make_pair +#include <type_traits> +#include <typeinfo> + + //typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<50>, + // boost::multiprecision::et_off> + // cpp_dec_float_50_et_off; + // + // typedef boost::multiprecision::number<boost::multiprecision::cpp_bin_float<50>, + // boost::multiprecision::et_off> + // cpp_bin_float_50_et_off; + +// http://en.wikipedia.org/wiki/Brent%27s_method Brent's method + +// An example of a function for which we want to find a minimum. +double f(double x) +{ + return (x + 3) * (x - 1) * (x - 1); +} + +//[brent_minimise_double_functor +struct funcdouble +{ + double operator()(double const& x) + { + return (x + 3) * (x - 1) * (x - 1); // (x + 3)(x - 1)^2 + } +}; +//] [/brent_minimise_double_functor] + +//[brent_minimise_T_functor +struct func +{ + template <class T> + T operator()(T const& x) + { + return (x + 3) * (x - 1) * (x - 1); // (x + 3)(x - 1)^2 + } +}; +//] [/brent_minimise_T_functor] + +//! Test if two values are close within a given tolerance. +template<typename FPT> +inline bool +is_close_to(FPT left, FPT right, FPT tolerance) +{ + return boost::math::fpc::close_at_tolerance<FPT>(tolerance) (left, right); +} + +//[brent_minimise_close + +//! Compare if value got is close to expected, +//! checking first if expected is very small +//! (to avoid divide by tiny or zero during comparison) +//! before comparing expect with value got. + +template <class T> +bool is_close(T expect, T got, T tolerance) +{ + using boost::math::fpc::close_at_tolerance; + using boost::math::fpc::is_small; + using boost::math::fpc::FPC_STRONG; + + if (is_small<T>(expect, tolerance)) + { + return is_small<T>(got, tolerance); + } + + return close_at_tolerance<T>(tolerance, FPC_STRONG) (expect, got); +} // bool is_close(T expect, T got, T tolerance) + +//] [/brent_minimise_close] + +//[brent_minimise_T_show + +//! Example template function to find and show minima. +//! \tparam T floating-point or fixed_point type. +template <class T> +void show_minima() +{ + using boost::math::tools::brent_find_minima; + using std::sqrt; + try + { // Always use try'n'catch blocks with Boost.Math to ensure you get any error messages. + + int bits = std::numeric_limits<T>::digits/2; // Maximum is digits/2; + std::streamsize prec = static_cast<int>(2 + sqrt((double)bits)); // Number of significant decimal digits. + std::streamsize precision = std::cout.precision(prec); // Save and set. + + std::cout << "\n\nFor type: " << typeid(T).name() + << ",\n epsilon = " << std::numeric_limits<T>::epsilon() + // << ", precision of " << bits << " bits" + << ",\n the maximum theoretical precision from Brent's minimization is " + << sqrt(std::numeric_limits<T>::epsilon()) + << "\n Displaying to std::numeric_limits<T>::digits10 " << prec << ", significant decimal digits." + << std::endl; + + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + // Construct using string, not double, avoids loss of precision. + //T bracket_min = static_cast<T>("-4"); + //T bracket_max = static_cast<T>("1.3333333333333333333333333333333333333333333333333"); + + // Construction from double may cause loss of precision for multiprecision types like cpp_bin_float, + // but brackets values are good enough for using Brent minimization. + T bracket_min = static_cast<T>(-4); + T bracket_max = static_cast<T>(1.3333333333333333333333333333333333333333333333333); + + std::pair<T, T> r = brent_find_minima<func, T>(func(), bracket_min, bracket_max, bits, it); + + std::cout << " x at minimum = " << r.first << ", f(" << r.first << ") = " << r.second; + if (it < maxit) + { + std::cout << ",\n met " << bits << " bits precision" << ", after " << it << " iterations." << std::endl; + } + else + { + std::cout << ",\n did NOT meet " << bits << " bits precision" << " after " << it << " iterations!" << std::endl; + } + // Check that result is that expected (compared to theoretical uncertainty). + T uncertainty = sqrt(std::numeric_limits<T>::epsilon()); + std::cout << std::boolalpha << "x == 1 (compared to uncertainty " << uncertainty << ") is " + << is_close(static_cast<T>(1), r.first, uncertainty) << std::endl; + std::cout << std::boolalpha << "f(x) == (0 compared to uncertainty " << uncertainty << ") is " + << is_close(static_cast<T>(0), r.second, uncertainty) << std::endl; + // Problems with this using multiprecision with expression template on? + std::cout.precision(precision); // Restore. + } + catch (const std::exception& e) + { // Always useful to include try & catch blocks because default policies + // are to throw exceptions on arguments that cause errors like underflow, overflow. + // Lacking try & catch blocks, the program will abort without a message below, + // which may give some helpful clues as to the cause of the exception. + std::cout << + "\n""Message from thrown exception was:\n " << e.what() << std::endl; + } +} // void show_minima() + +//] [/brent_minimise_T_show] + +int main() +{ + using boost::math::tools::brent_find_minima; + using std::sqrt; + std::cout << "Brent's minimisation examples." << std::endl; + std::cout << std::boolalpha << std::endl; + std::cout << std::showpoint << std::endl; // Show trailing zeros. + + // Tip - using + // std::cout.precision(std::numeric_limits<T>::digits10); + // during debugging is wise because it warns + // if construction of multiprecision involves conversion from double + // by finding random or zero digits after 17th decimal digit. + + // Specific type double - unlimited iterations (unwise?). + { + std::cout << "\nType double - unlimited iterations (unwise?)" << std::endl; + //[brent_minimise_double_1 + const int double_bits = std::numeric_limits<double>::digits; + std::pair<double, double> r = brent_find_minima(funcdouble(), -4., 4. / 3, double_bits); + + std::streamsize precision_1 = std::cout.precision(std::numeric_limits<double>::digits10); + // Show all double precision decimal digits and trailing zeros. + std::cout << "x at minimum = " << r.first + << ", f(" << r.first << ") = " << r.second << std::endl; + //] [/brent_minimise_double_1] + std::cout << "x at minimum = " << (r.first - 1.) / r.first << std::endl; + // x at minimum = 1.00000000112345, f(1.00000000112345) = 5.04852568272458e-018 + double uncertainty = sqrt(std::numeric_limits<double>::epsilon()); + std::cout << "Uncertainty sqrt(epsilon) = " << uncertainty << std::endl; + // sqrt(epsilon) = 1.49011611938477e-008 + // (epsilon is always > 0, so no need to take abs value). + + std::cout.precision(precision_1); // Restore. + //[brent_minimise_double_1a + + using boost::math::fpc::close_at_tolerance; + using boost::math::fpc::is_small; + + std::cout << "x = " << r.first << ", f(x) = " << r.second << std::endl; + std::cout << std::boolalpha << "x == 1 (compared to uncertainty " + << uncertainty << ") is " << is_close(1., r.first, uncertainty) << std::endl; // true + std::cout << std::boolalpha << "f(x) == 0 (compared to uncertainty " + << uncertainty << ") is " << is_close(0., r.second, uncertainty) << std::endl; // true +//] [/brent_minimise_double_1a] + + } + std::cout << "\nType double with limited iterations." << std::endl; + { + const int bits = std::numeric_limits<double>::digits; + // Specific type double - limit maxit to 20 iterations. + std::cout << "Precision bits = " << bits << std::endl; + //[brent_minimise_double_2 + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + std::pair<double, double> r = brent_find_minima(funcdouble(), -4., 4. / 3, bits, it); + std::cout << "x at minimum = " << r.first << ", f(" << r.first << ") = " << r.second + << " after " << it << " iterations. " << std::endl; + //] [/brent_minimise_double_2] + // x at minimum = 1.00000000112345, f(1.00000000112345) = 5.04852568272458e-018 +//[brent_minimise_double_3 + std::streamsize prec = static_cast<int>(2 + sqrt((double)bits)); // Number of significant decimal digits. + std::streamsize precision_3 = std::cout.precision(prec); // Save and set new precision. + std::cout << "Showing " << bits << " bits " + "precision with " << prec + << " decimal digits from tolerance " << sqrt(std::numeric_limits<double>::epsilon()) + << std::endl; + + std::cout << "x at minimum = " << r.first + << ", f(" << r.first << ") = " << r.second + << " after " << it << " iterations. " << std::endl; + std::cout.precision(precision_3); // Restore. +//] [/brent_minimise_double_3] + // Showing 53 bits precision with 9 decimal digits from tolerance 1.49011611938477e-008 + // x at minimum = 1, f(1) = 5.04852568e-018 + } + + std::cout << "\nType double with limited iterations and half double bits." << std::endl; + { + +//[brent_minimise_double_4 + const int bits_div_2 = std::numeric_limits<double>::digits / 2; // Half digits precision (effective maximum). + double epsilon_2 = boost::math::pow<-(std::numeric_limits<double>::digits/2 - 1), double>(2); + std::streamsize prec = static_cast<int>(2 + sqrt((double)bits_div_2)); // Number of significant decimal digits. + + std::cout << "Showing " << bits_div_2 << " bits precision with " << prec + << " decimal digits from tolerance " << sqrt(epsilon_2) + << std::endl; + std::streamsize precision_4 = std::cout.precision(prec); // Save. + const boost::uintmax_t maxit = 20; + boost::uintmax_t it_4 = maxit; + std::pair<double, double> r = brent_find_minima(funcdouble(), -4., 4. / 3, bits_div_2, it_4); + std::cout << "x at minimum = " << r.first << ", f(" << r.first << ") = " << r.second << std::endl; + std::cout << it_4 << " iterations. " << std::endl; + std::cout.precision(precision_4); // Restore. + +//] [/brent_minimise_double_4] + } + // x at minimum = 1, f(1) = 5.04852568e-018 + + { + std::cout << "\nType double with limited iterations and quarter double bits." << std::endl; + //[brent_minimise_double_5 + const int bits_div_4 = std::numeric_limits<double>::digits / 4; // Quarter precision. + double epsilon_4 = boost::math::pow<-(std::numeric_limits<double>::digits / 4 - 1), double>(2); + std::streamsize prec = static_cast<int>(2 + sqrt((double)bits_div_4)); // Number of significant decimal digits. + std::cout << "Showing " << bits_div_4 << " bits precision with " << prec + << " decimal digits from tolerance " << sqrt(epsilon_4) + << std::endl; + std::streamsize precision_5 = std::cout.precision(prec); // Save & set. + const boost::uintmax_t maxit = 20; + + boost::uintmax_t it_5 = maxit; + std::pair<double, double> r = brent_find_minima(funcdouble(), -4., 4. / 3, bits_div_4, it_5); + std::cout << "x at minimum = " << r.first << ", f(" << r.first << ") = " << r.second + << ", after " << it_5 << " iterations. " << std::endl; + std::cout.precision(precision_5); // Restore. + + //] [/brent_minimise_double_5] + } + + // Showing 13 bits precision with 9 decimal digits from tolerance 0.015625 + // x at minimum = 0.9999776, f(0.9999776) = 2.0069572e-009 + // 7 iterations. + + { + std::cout << "\nType long double with limited iterations and all long double bits." << std::endl; +//[brent_minimise_template_1 + std::streamsize precision_t1 = std::cout.precision(std::numeric_limits<long double>::digits10); // Save & set. + long double bracket_min = -4.; + long double bracket_max = 4. / 3; + const int bits = std::numeric_limits<long double>::digits; + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + + std::pair<long double, long double> r = brent_find_minima(func(), bracket_min, bracket_max, bits, it); + std::cout << "x at minimum = " << r.first << ", f(" << r.first << ") = " << r.second + << ", after " << it << " iterations. " << std::endl; + std::cout.precision(precision_t1); // Restore. +//] [/brent_minimise_template_1] + } + + // Show use of built-in type Template versions. + // (Will not work if construct bracket min and max from string). + +//[brent_minimise_template_fd + show_minima<float>(); + show_minima<double>(); + show_minima<long double>(); + + //] [/brent_minimise_template_fd] + +//[brent_minimise_mp_include_1 +#ifdef BOOST_HAVE_QUADMATH // Defined only if GCC or Intel and have quadmath.lib or .dll library available. + using boost::multiprecision::float128; +#endif +//] [/brent_minimise_mp_include_1] + +//[brent_minimise_template_quad +#ifdef BOOST_HAVE_QUADMATH // Defined only if GCC or Intel and have quadmath.lib or .dll library available. + show_minima<float128>(); // Needs quadmath_snprintf, sqrtQ, fabsq that are in in quadmath library. +#endif +//] [/brent_minimise_template_quad + + // User-defined floating-point template. + +//[brent_minimise_mp_typedefs + using boost::multiprecision::cpp_bin_float_50; // binary multiprecision typedef. + using boost::multiprecision::cpp_dec_float_50; // decimal multiprecision typedef. + + // One might also need typedefs like these to switch expression templates off and on (default is on). + typedef boost::multiprecision::number<boost::multiprecision::cpp_bin_float<50>, + boost::multiprecision::et_on> + cpp_bin_float_50_et_on; // et_on is default so is same as cpp_bin_float_50. + + typedef boost::multiprecision::number<boost::multiprecision::cpp_bin_float<50>, + boost::multiprecision::et_off> + cpp_bin_float_50_et_off; + + typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<50>, + boost::multiprecision::et_on> // et_on is default so is same as cpp_dec_float_50. + cpp_dec_float_50_et_on; + + typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<50>, + boost::multiprecision::et_off> + cpp_dec_float_50_et_off; +//] [/brent_minimise_mp_typedefs] + + { // binary ET on by default. +//[brent_minimise_mp_1 + std::cout.precision(std::numeric_limits<cpp_bin_float_50>::digits10); + int bits = std::numeric_limits<cpp_bin_float_50>::digits / 2 - 2; + cpp_bin_float_50 bracket_min = static_cast<cpp_bin_float_50>("-4"); + cpp_bin_float_50 bracket_max = static_cast<cpp_bin_float_50>("1.3333333333333333333333333333333333333333333333333"); + + std::cout << "Bracketing " << bracket_min << " to " << bracket_max << std::endl; + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; // Will be updated with actual iteration count. + std::pair<cpp_bin_float_50, cpp_bin_float_50> r + = brent_find_minima(func(), bracket_min, bracket_max, bits, it); + + std::cout << "x at minimum = " << r.first << ",\n f(" << r.first << ") = " << r.second + // x at minimum = 1, f(1) = 5.04853e-018 + << ", after " << it << " iterations. " << std::endl; + + is_close_to(static_cast<cpp_bin_float_50>("1"), r.first, sqrt(std::numeric_limits<cpp_bin_float_50>::epsilon())); + is_close_to(static_cast<cpp_bin_float_50>("0"), r.second, sqrt(std::numeric_limits<cpp_bin_float_50>::epsilon())); + +//] [/brent_minimise_mp_1] + +/* +//[brent_minimise_mp_output_1 +For type class boost::multiprecision::number<class boost::multiprecision::backends::cpp_bin_float<50,10,void,int,0,0>,1>, +epsilon = 5.3455294202e-51, +the maximum theoretical precision from Brent minimization is 7.311312755e-26 +Displaying to std::numeric_limits<T>::digits10 11 significant decimal digits. +x at minimum = 1, f(1) = 5.6273022713e-58, +met 84 bits precision, after 14 iterations. +x == 1 (compared to uncertainty 7.311312755e-26) is true +f(x) == (0 compared to uncertainty 7.311312755e-26) is true +-4 1.3333333333333333333333333333333333333333333333333 +x at minimum = 0.99999999999999999999999999998813903221565569205253, +f(0.99999999999999999999999999998813903221565569205253) = + 5.6273022712501408640665300316078046703496236636624e-58 +14 iterations +//] [/brent_minimise_mp_output_1] +*/ +//[brent_minimise_mp_2 + show_minima<cpp_bin_float_50_et_on>(); // +//] [/brent_minimise_mp_2] + +/* +//[brent_minimise_mp_output_2 + For type class boost::multiprecision::number<class boost::multiprecision::backends::cpp_bin_float<50, 10, void, int, 0, 0>, 1>, + +//] [/brent_minimise_mp_output_1] +*/ + } + + { // binary ET on explicit + std::cout.precision(std::numeric_limits<cpp_bin_float_50_et_on>::digits10); + + int bits = std::numeric_limits<cpp_bin_float_50_et_on>::digits / 2 - 2; + + cpp_bin_float_50_et_on bracket_min = static_cast<cpp_bin_float_50_et_on>("-4"); + cpp_bin_float_50_et_on bracket_max = static_cast<cpp_bin_float_50_et_on>("1.3333333333333333333333333333333333333333333333333"); + + std::cout << bracket_min << " " << bracket_max << std::endl; + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + std::pair<cpp_bin_float_50_et_on, cpp_bin_float_50_et_on> r = brent_find_minima(func(), bracket_min, bracket_max, bits, it); + + std::cout << "x at minimum = " << r.first << ", f(" << r.first << ") = " << r.second << std::endl; + // x at minimum = 1, f(1) = 5.04853e-018 + std::cout << it << " iterations. " << std::endl; + + show_minima<cpp_bin_float_50_et_on>(); // + + } + return 0; + + // Some examples of switching expression templates on and off follow. + + { // binary ET off + std::cout.precision(std::numeric_limits<cpp_bin_float_50_et_off>::digits10); + + int bits = std::numeric_limits<cpp_bin_float_50_et_off>::digits / 2 - 2; + cpp_bin_float_50_et_off bracket_min = static_cast<cpp_bin_float_50_et_off>("-4"); + cpp_bin_float_50_et_off bracket_max = static_cast<cpp_bin_float_50_et_off>("1.3333333333333333333333333333333333333333333333333"); + + std::cout << bracket_min << " " << bracket_max << std::endl; + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + std::pair<cpp_bin_float_50_et_off, cpp_bin_float_50_et_off> r = brent_find_minima(func(), bracket_min, bracket_max, bits, it); + + std::cout << "x at minimum = " << r.first << ", f(" << r.first << ") = " << r.second << std::endl; + // x at minimum = 1, f(1) = 5.04853e-018 + std::cout << it << " iterations. " << std::endl; + + show_minima<cpp_bin_float_50_et_off>(); // + } + + { // decimal ET on by default + std::cout.precision(std::numeric_limits<cpp_dec_float_50>::digits10); + + int bits = std::numeric_limits<cpp_dec_float_50>::digits / 2 - 2; + + cpp_dec_float_50 bracket_min = static_cast<cpp_dec_float_50>("-4"); + cpp_dec_float_50 bracket_max = static_cast<cpp_dec_float_50>("1.3333333333333333333333333333333333333333333333333"); + + std::cout << bracket_min << " " << bracket_max << std::endl; + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + std::pair<cpp_dec_float_50, cpp_dec_float_50> r = brent_find_minima(func(), bracket_min, bracket_max, bits, it); + + std::cout << "x at minimum = " << r.first << ", f(" << r.first << ") = " << r.second << std::endl; + // x at minimum = 1, f(1) = 5.04853e-018 + std::cout << it << " iterations. " << std::endl; + + show_minima<cpp_dec_float_50>(); + } + + { // decimal ET on + std::cout.precision(std::numeric_limits<cpp_dec_float_50_et_on>::digits10); + + int bits = std::numeric_limits<cpp_dec_float_50_et_on>::digits / 2 - 2; + + cpp_dec_float_50_et_on bracket_min = static_cast<cpp_dec_float_50_et_on>("-4"); + cpp_dec_float_50_et_on bracket_max = static_cast<cpp_dec_float_50_et_on>("1.3333333333333333333333333333333333333333333333333"); + std::cout << bracket_min << " " << bracket_max << std::endl; + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + std::pair<cpp_dec_float_50_et_on, cpp_dec_float_50_et_on> r = brent_find_minima(func(), bracket_min, bracket_max, bits, it); + + std::cout << "x at minimum = " << r.first << ", f(" << r.first << ") = " << r.second << std::endl; + // x at minimum = 1, f(1) = 5.04853e-018 + std::cout << it << " iterations. " << std::endl; + + show_minima<cpp_dec_float_50_et_on>(); + + } + + { // decimal ET off + std::cout.precision(std::numeric_limits<cpp_dec_float_50_et_off>::digits10); + + int bits = std::numeric_limits<cpp_dec_float_50_et_off>::digits / 2 - 2; + + cpp_dec_float_50_et_off bracket_min = static_cast<cpp_dec_float_50_et_off>("-4"); + cpp_dec_float_50_et_off bracket_max = static_cast<cpp_dec_float_50_et_off>("1.3333333333333333333333333333333333333333333333333"); + + std::cout << bracket_min << " " << bracket_max << std::endl; + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + std::pair<cpp_dec_float_50_et_off, cpp_dec_float_50_et_off> r = brent_find_minima(func(), bracket_min, bracket_max, bits, it); + + std::cout << "x at minimum = " << r.first << ", f(" << r.first << ") = " << r.second << std::endl; + // x at minimum = 1, f(1) = 5.04853e-018 + std::cout << it << " iterations. " << std::endl; + + show_minima<cpp_dec_float_50_et_off>(); + } + + return 0; +} // int main() + + +/* + +Typical output MSVC 15.7.3 + +brent_minimise_example.cpp +Generating code +7 of 2746 functions ( 0.3%) were compiled, the rest were copied from previous compilation. +0 functions were new in current compilation +1 functions had inline decision re-evaluated but remain unchanged +Finished generating code +brent_minimise_example.vcxproj -> J:\Cpp\MathToolkit\test\Math_test\Release\brent_minimise_example.exe +Autorun "J:\Cpp\MathToolkit\test\Math_test\Release\brent_minimise_example.exe" +Brent's minimisation examples. + + + +Type double - unlimited iterations (unwise?) +x at minimum = 1.00000000112345, f(1.00000000112345) = 5.04852568272458e-18 +x at minimum = 1.12344622367552e-09 +Uncertainty sqrt(epsilon) = 1.49011611938477e-08 +x = 1.00000, f(x) = 5.04853e-18 +x == 1 (compared to uncertainty 1.49012e-08) is true +f(x) == 0 (compared to uncertainty 1.49012e-08) is true + +Type double with limited iterations. +Precision bits = 53 +x at minimum = 1.00000, f(1.00000) = 5.04853e-18 after 10 iterations. +Showing 53 bits precision with 9 decimal digits from tolerance 1.49011612e-08 +x at minimum = 1.00000000, f(1.00000000) = 5.04852568e-18 after 10 iterations. + +Type double with limited iterations and half double bits. +Showing 26 bits precision with 7 decimal digits from tolerance 0.000172633 +x at minimum = 1.000000, f(1.000000) = 5.048526e-18 +10 iterations. + +Type double with limited iterations and quarter double bits. +Showing 13 bits precision with 5 decimal digits from tolerance 0.0156250 +x at minimum = 0.99998, f(0.99998) = 2.0070e-09, after 7 iterations. + +Type long double with limited iterations and all long double bits. +x at minimum = 1.00000000112345, f(1.00000000112345) = 5.04852568272458e-18, after 10 iterations. + + +For type: float, +epsilon = 1.1921e-07, +the maximum theoretical precision from Brent's minimization is 0.00034527 +Displaying to std::numeric_limits<T>::digits10 5, significant decimal digits. +x at minimum = 1.0002, f(1.0002) = 1.9017e-07, +met 12 bits precision, after 7 iterations. +x == 1 (compared to uncertainty 0.00034527) is true +f(x) == (0 compared to uncertainty 0.00034527) is true + + +For type: double, +epsilon = 2.220446e-16, +the maximum theoretical precision from Brent's minimization is 1.490116e-08 +Displaying to std::numeric_limits<T>::digits10 7, significant decimal digits. +x at minimum = 1.000000, f(1.000000) = 5.048526e-18, +met 26 bits precision, after 10 iterations. +x == 1 (compared to uncertainty 1.490116e-08) is true +f(x) == (0 compared to uncertainty 1.490116e-08) is true + + +For type: long double, +epsilon = 2.220446e-16, +the maximum theoretical precision from Brent's minimization is 1.490116e-08 +Displaying to std::numeric_limits<T>::digits10 7, significant decimal digits. +x at minimum = 1.000000, f(1.000000) = 5.048526e-18, +met 26 bits precision, after 10 iterations. +x == 1 (compared to uncertainty 1.490116e-08) is true +f(x) == (0 compared to uncertainty 1.490116e-08) is true +Bracketing -4.0000000000000000000000000000000000000000000000000 to 1.3333333333333333333333333333333333333333333333333 +x at minimum = 0.99999999999999999999999999998813903221565569205253, +f(0.99999999999999999999999999998813903221565569205253) = 5.6273022712501408640665300316078046703496236636624e-58, after 14 iterations. + + +For type: class boost::multiprecision::number<class boost::multiprecision::backends::cpp_bin_float<50,10,void,int,0,0>,1>, +epsilon = 5.3455294202e-51, +the maximum theoretical precision from Brent's minimization is 7.3113127550e-26 +Displaying to std::numeric_limits<T>::digits10 11, significant decimal digits. +x at minimum = 1.0000000000, f(1.0000000000) = 5.6273022713e-58, +met 84 bits precision, after 14 iterations. +x == 1 (compared to uncertainty 7.3113127550e-26) is true +f(x) == (0 compared to uncertainty 7.3113127550e-26) is true +-4.0000000000000000000000000000000000000000000000000 1.3333333333333333333333333333333333333333333333333 +x at minimum = 0.99999999999999999999999999998813903221565569205253, f(0.99999999999999999999999999998813903221565569205253) = 5.6273022712501408640665300316078046703496236636624e-58 +14 iterations. + + +For type: class boost::multiprecision::number<class boost::multiprecision::backends::cpp_bin_float<50,10,void,int,0,0>,1>, +epsilon = 5.3455294202e-51, +the maximum theoretical precision from Brent's minimization is 7.3113127550e-26 +Displaying to std::numeric_limits<T>::digits10 11, significant decimal digits. +x at minimum = 1.0000000000, f(1.0000000000) = 5.6273022713e-58, +met 84 bits precision, after 14 iterations. +x == 1 (compared to uncertainty 7.3113127550e-26) is true +f(x) == (0 compared to uncertainty 7.3113127550e-26) is true + + +============================================================================================================ + + // GCC 7.2.0 with quadmath + +Brent's minimisation examples. + +Type double - unlimited iterations (unwise?) +x at minimum = 1.00000000112345, f(1.00000000112345) = 5.04852568272458e-018 +x at minimum = 1.12344622367552e-009 +Uncertainty sqrt(epsilon) = 1.49011611938477e-008 +x = 1.00000, f(x) = 5.04853e-018 +x == 1 (compared to uncertainty 1.49012e-008) is true +f(x) == 0 (compared to uncertainty 1.49012e-008) is true + +Type double with limited iterations. +Precision bits = 53 +x at minimum = 1.00000, f(1.00000) = 5.04853e-018 after 10 iterations. +Showing 53 bits precision with 9 decimal digits from tolerance 1.49011612e-008 +x at minimum = 1.00000000, f(1.00000000) = 5.04852568e-018 after 10 iterations. + +Type double with limited iterations and half double bits. +Showing 26 bits precision with 7 decimal digits from tolerance 0.000172633 +x at minimum = 1.000000, f(1.000000) = 5.048526e-018 +10 iterations. + +Type double with limited iterations and quarter double bits. +Showing 13 bits precision with 5 decimal digits from tolerance 0.0156250 +x at minimum = 0.99998, f(0.99998) = 2.0070e-009, after 7 iterations. + +Type long double with limited iterations and all long double bits. +x at minimum = 1.00000000000137302, f(1.00000000000137302) = 7.54079013697311930e-024, after 10 iterations. + + +For type: f, +epsilon = 1.1921e-007, +the maximum theoretical precision from Brent's minimization is 0.00034527 +Displaying to std::numeric_limits<T>::digits10 5, significant decimal digits. +x at minimum = 1.0002, f(1.0002) = 1.9017e-007, +met 12 bits precision, after 7 iterations. +x == 1 (compared to uncertainty 0.00034527) is true +f(x) == (0 compared to uncertainty 0.00034527) is true + + +For type: d, +epsilon = 2.220446e-016, +the maximum theoretical precision from Brent's minimization is 1.490116e-008 +Displaying to std::numeric_limits<T>::digits10 7, significant decimal digits. +x at minimum = 1.000000, f(1.000000) = 5.048526e-018, +met 26 bits precision, after 10 iterations. +x == 1 (compared to uncertainty 1.490116e-008) is true +f(x) == (0 compared to uncertainty 1.490116e-008) is true + + +For type: e, +epsilon = 1.084202e-019, +the maximum theoretical precision from Brent's minimization is 3.292723e-010 +Displaying to std::numeric_limits<T>::digits10 7, significant decimal digits. +x at minimum = 1.000000, f(1.000000) = 7.540790e-024, +met 32 bits precision, after 10 iterations. +x == 1 (compared to uncertainty 3.292723e-010) is true +f(x) == (0 compared to uncertainty 3.292723e-010) is true + + +For type: N5boost14multiprecision6numberINS0_8backends16float128_backendELNS0_26expression_template_optionE0EEE, +epsilon = 1.92592994e-34, +the maximum theoretical precision from Brent's minimization is 1.38777878e-17 +Displaying to std::numeric_limits<T>::digits10 9, significant decimal digits. +x at minimum = 1.00000000, f(1.00000000) = 1.48695468e-43, +met 56 bits precision, after 12 iterations. +x == 1 (compared to uncertainty 1.38777878e-17) is true +f(x) == (0 compared to uncertainty 1.38777878e-17) is true +Bracketing -4.0000000000000000000000000000000000000000000000000 to 1.3333333333333333333333333333333333333333333333333 +x at minimum = 0.99999999999999999999999999998813903221565569205253, +f(0.99999999999999999999999999998813903221565569205253) = 5.6273022712501408640665300316078046703496236636624e-58, after 14 iterations. + + +For type: N5boost14multiprecision6numberINS0_8backends13cpp_bin_floatILj50ELNS2_15digit_base_typeE10EviLi0ELi0EEELNS0_26expression_template_optionE1EEE, +epsilon = 5.3455294202e-51, +the maximum theoretical precision from Brent's minimization is 7.3113127550e-26 +Displaying to std::numeric_limits<T>::digits10 11, significant decimal digits. +x at minimum = 1.0000000000, f(1.0000000000) = 5.6273022713e-58, +met 84 bits precision, after 14 iterations. +x == 1 (compared to uncertainty 7.3113127550e-26) is true +f(x) == (0 compared to uncertainty 7.3113127550e-26) is true +-4.0000000000000000000000000000000000000000000000000 1.3333333333333333333333333333333333333333333333333 +x at minimum = 0.99999999999999999999999999998813903221565569205253, f(0.99999999999999999999999999998813903221565569205253) = 5.6273022712501408640665300316078046703496236636624e-58 +14 iterations. + + +For type: N5boost14multiprecision6numberINS0_8backends13cpp_bin_floatILj50ELNS2_15digit_base_typeE10EviLi0ELi0EEELNS0_26expression_template_optionE1EEE, +epsilon = 5.3455294202e-51, +the maximum theoretical precision from Brent's minimization is 7.3113127550e-26 +Displaying to std::numeric_limits<T>::digits10 11, significant decimal digits. +x at minimum = 1.0000000000, f(1.0000000000) = 5.6273022713e-58, +met 84 bits precision, after 14 iterations. +x == 1 (compared to uncertainty 7.3113127550e-26) is true +f(x) == (0 compared to uncertainty 7.3113127550e-26) is true + +*/ diff --git a/src/boost/libs/math/example/c_error_policy_example.cpp b/src/boost/libs/math/example/c_error_policy_example.cpp new file mode 100644 index 000000000..73ae024b0 --- /dev/null +++ b/src/boost/libs/math/example/c_error_policy_example.cpp @@ -0,0 +1,83 @@ +// C_error_policy_example.cpp + +// Copyright Paul A. Bristow 2007, 2010. +// Copyright John Maddock 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Suppose we want a call to tgamma to behave in a C-compatible way +// and set global ::errno rather than throw an exception. + +#include <cerrno> // for ::errno + +#include <boost/math/special_functions/gamma.hpp> +using boost::math::tgamma; + +using boost::math::policies::policy; +// Possible errors +using boost::math::policies::overflow_error; +using boost::math::policies::underflow_error; +using boost::math::policies::domain_error; +using boost::math::policies::pole_error; +using boost::math::policies::denorm_error; +using boost::math::policies::evaluation_error; + +using boost::math::policies::errno_on_error; +using boost::math::policies::ignore_error; + +//using namespace boost::math::policies; +//using namespace boost::math; // avoid potential ambiguity with std:: <random> + +// Define a policy: +typedef policy< + domain_error<errno_on_error>, // 'bad' arguments. + pole_error<errno_on_error>, // argument is pole value. + overflow_error<errno_on_error>, // argument value causes overflow. + evaluation_error<errno_on_error> // evaluation does not converge and may be inaccurate, or worse, + // or there is no way known (yet) to implement this evaluation, + // for example, kurtosis of non-central beta distribution. + > C_error_policy; + +// std +#include <iostream> + using std::cout; + using std::endl; + +int main() +{ + // We can achieve this at the function call site + // with the previously defined policy C_error_policy. + double t = tgamma(4., C_error_policy()); + cout << "tgamma(4., C_error_policy() = " << t << endl; // 6 + + // Alternatively we could use the function make_policy, + // provided for convenience, + // and define everything at the call site: + t = tgamma(4., make_policy( + domain_error<errno_on_error>(), + pole_error<errno_on_error>(), + overflow_error<errno_on_error>(), + evaluation_error<errno_on_error>() + )); + cout << "tgamma(4., make_policy(...) = " << t << endl; // 6 + + return 0; +} // int main() + +/* + +Output + + c_error_policy_example.cpp + Generating code + Finished generating code + c_error_policy_example.vcxproj -> J:\Cpp\MathToolkit\test\Math_test\Release\c_error_policy_example.exe + tgamma(4., C_error_policy() = 6 + tgamma(4., make_policy(...) = 6 + tgamma(4., C_error_policy() = 6 + tgamma(4., make_policy(...) = 6 + +*/ diff --git a/src/boost/libs/math/example/cardinal_cubic_b_spline_example.cpp b/src/boost/libs/math/example/cardinal_cubic_b_spline_example.cpp new file mode 100644 index 000000000..3a709f449 --- /dev/null +++ b/src/boost/libs/math/example/cardinal_cubic_b_spline_example.cpp @@ -0,0 +1,147 @@ +// Copyright Nicholas Thompson 2017. +// Copyright Paul A. Bristow 2017. +// Copyright John Maddock 2017. + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http://www.boost.org/LICENSE_1_0.txt). + +#include <iostream> +#include <limits> +#include <vector> +#include <algorithm> +#include <iomanip> +#include <iterator> +#include <cmath> +#include <random> +#include <cstdint> +#include <boost/random/uniform_real_distribution.hpp> +#include <boost/math/tools/roots.hpp> + +//[cubic_b_spline_example + +/*`This example demonstrates how to use the cubic b spline interpolator for regularly spaced data. +*/ +#include <boost/math/interpolators/cardinal_cubic_b_spline.hpp> + +int main() +{ + // We begin with an array of samples: + std::vector<double> v(500); + // And decide on a stepsize: + double step = 0.01; + + // Initialize the vector with a function we'd like to interpolate: + for (size_t i = 0; i < v.size(); ++i) + { + v[i] = sin(i*step); + } + // We could define an arbitrary start time, but for now we'll just use 0: + boost::math::interpolators::cardinal_cubic_b_spline<double> spline(v.data(), v.size(), 0 /* start time */, step); + + // Now we can evaluate the spline wherever we please. + std::mt19937 gen; + boost::random::uniform_real_distribution<double> absissa(0, v.size()*step); + for (size_t i = 0; i < 10; ++i) + { + double x = absissa(gen); + std::cout << "sin(" << x << ") = " << sin(x) << ", spline interpolation gives " << spline(x) << std::endl; + std::cout << "cos(" << x << ") = " << cos(x) << ", spline derivative interpolation gives " << spline.prime(x) << std::endl; + } + + // The next example is less trivial: + // We will try to figure out when the population of the United States crossed 100 million. + // Since the census is taken every 10 years, the data is equally spaced, so we can use the cubic b spline. + // Data taken from https://en.wikipedia.org/wiki/United_States_Census + // We'll start at the year 1860: + double t0 = 1860; + double time_step = 10; + std::vector<double> population{31443321, /* 1860 */ + 39818449, /* 1870 */ + 50189209, /* 1880 */ + 62947714, /* 1890 */ + 76212168, /* 1900 */ + 92228496, /* 1910 */ + 106021537, /* 1920 */ + 122775046, /* 1930 */ + 132164569, /* 1940 */ + 150697361, /* 1950 */ + 179323175};/* 1960 */ + + // An eyeball estimate indicates that the population crossed 100 million around 1915. + // Let's see what interpolation says: + boost::math::interpolators::cardinal_cubic_b_spline<double> p(population.data(), population.size(), t0, time_step); + + // Now create a function which has a zero at p = 100,000,000: + auto f = [=](double t){ return p(t) - 100000000; }; + + // Boost includes a bisection algorithm, which is robust, though not as fast as some others + // we provide, but let's try that first. We need a termination condition for it, which + // takes the two endpoints of the range and returns either true (stop) or false (keep going), + // we could use a predefined one such as boost::math::tools::eps_tolerance<double>, but that + // won't stop until we have full double precision which is overkill, since we just need the + // endpoint to yield the same month. While we're at it, we'll keep track of the number of + // iterations required too, though this is strictly optional: + + auto termination = [](double left, double right) + { + double left_month = std::round((left - std::floor(left)) * 12 + 1); + double right_month = std::round((right - std::floor(right)) * 12 + 1); + return (left_month == right_month) && (std::floor(left) == std::floor(right)); + }; + std::uintmax_t iterations = 1000; + auto result = boost::math::tools::bisect(f, 1910.0, 1920.0, termination, iterations); + auto time = result.first; // termination condition ensures that both endpoints yield the same result + auto month = std::round((time - std::floor(time))*12 + 1); + auto year = std::floor(time); + std::cout << "The population of the United States surpassed 100 million on the "; + std::cout << month << "th month of " << year << std::endl; + std::cout << "Found in " << iterations << " iterations" << std::endl; + + // Since the cubic B spline offers the first derivative, we could equally have used Newton iterations, + // this takes "number of bits correct" as a termination condition - 20 should be plenty for what we need, + // and once again, we track how many iterations are taken: + + auto f_n = [=](double t) { return std::make_pair(p(t) - 100000000, p.prime(t)); }; + iterations = 1000; + time = boost::math::tools::newton_raphson_iterate(f_n, 1910.0, 1900.0, 2000.0, 20, iterations); + month = std::round((time - std::floor(time))*12 + 1); + year = std::floor(time); + std::cout << "The population of the United States surpassed 100 million on the "; + std::cout << month << "th month of " << year << std::endl; + std::cout << "Found in " << iterations << " iterations" << std::endl; + +} + +//] [/cubic_b_spline_example] + +//[cubic_b_spline_example_out +/*` Program output is: +[pre +sin(4.07362) = -0.802829, spline interpolation gives - 0.802829 +cos(4.07362) = -0.596209, spline derivative interpolation gives - 0.596209 +sin(0.677385) = 0.626758, spline interpolation gives 0.626758 +cos(0.677385) = 0.779214, spline derivative interpolation gives 0.779214 +sin(4.52896) = -0.983224, spline interpolation gives - 0.983224 +cos(4.52896) = -0.182402, spline derivative interpolation gives - 0.182402 +sin(4.17504) = -0.85907, spline interpolation gives - 0.85907 +cos(4.17504) = -0.511858, spline derivative interpolation gives - 0.511858 +sin(0.634934) = 0.593124, spline interpolation gives 0.593124 +cos(0.634934) = 0.805111, spline derivative interpolation gives 0.805111 +sin(4.84434) = -0.991307, spline interpolation gives - 0.991307 +cos(4.84434) = 0.131567, spline derivative interpolation gives 0.131567 +sin(4.56688) = -0.989432, spline interpolation gives - 0.989432 +cos(4.56688) = -0.144997, spline derivative interpolation gives - 0.144997 +sin(1.10517) = 0.893541, spline interpolation gives 0.893541 +cos(1.10517) = 0.448982, spline derivative interpolation gives 0.448982 +sin(3.1618) = -0.0202022, spline interpolation gives - 0.0202022 +cos(3.1618) = -0.999796, spline derivative interpolation gives - 0.999796 +sin(1.54084) = 0.999551, spline interpolation gives 0.999551 +cos(1.54084) = 0.0299566, spline derivative interpolation gives 0.0299566 +The population of the United States surpassed 100 million on the 11th month of 1915 +Found in 12 iterations +The population of the United States surpassed 100 million on the 11th month of 1915 +Found in 3 iterations +] +*/ +//] diff --git a/src/boost/libs/math/example/catmull_rom_example.cpp b/src/boost/libs/math/example/catmull_rom_example.cpp new file mode 100644 index 000000000..69a497070 --- /dev/null +++ b/src/boost/libs/math/example/catmull_rom_example.cpp @@ -0,0 +1,45 @@ +// Copyright Nick Thompson, 2017 + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http://www.boost.org/LICENSE_1_0.txt). + +#include <iostream> +#include <vector> +#include <array> +#include <cmath> +#include <boost/math/interpolators/catmull_rom.hpp> +#include <boost/math/constants/constants.hpp> + +using std::sin; +using std::cos; +using boost::math::catmull_rom; + +int main() +{ + std::cout << "This shows how to use Boost's Catmull-Rom spline to create an Archimedean spiral.\n"; + + // The Archimedean spiral is given by r = a*theta. We have set a = 1. + std::vector<std::array<double, 2>> spiral_points(500); + double theta_max = boost::math::constants::pi<double>(); + for (size_t i = 0; i < spiral_points.size(); ++i) + { + double theta = ((double) i/ (double) spiral_points.size())*theta_max; + spiral_points[i] = {theta*cos(theta), theta*sin(theta)}; + } + + auto archimedean = catmull_rom<std::array<double,2>>(std::move(spiral_points)); + double max_s = archimedean.max_parameter(); + std::cout << "Max s = " << max_s << std::endl; + for (double s = 0; s < max_s; s += 0.01) + { + auto p = archimedean(s); + double x = p[0]; + double y = p[1]; + double r = sqrt(x*x + y*y); + double theta = atan2(y/r, x/r); + std::cout << "r = " << r << ", theta = " << theta << ", r - theta = " << r - theta << std::endl; + } + + return 0; +} diff --git a/src/boost/libs/math/example/chi_square_std_dev_test.cpp b/src/boost/libs/math/example/chi_square_std_dev_test.cpp new file mode 100644 index 000000000..9743240bd --- /dev/null +++ b/src/boost/libs/math/example/chi_square_std_dev_test.cpp @@ -0,0 +1,555 @@ +// Copyright John Maddock 2006, 2007 +// Copyright Paul A. Bristow 2010 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <iostream> +using std::cout; using std::endl; +using std::left; using std::fixed; using std::right; using std::scientific; +#include <iomanip> +using std::setw; +using std::setprecision; + +#include <boost/math/distributions/chi_squared.hpp> + +int error_result = 0; + +void confidence_limits_on_std_deviation( + double Sd, // Sample Standard Deviation + unsigned N) // Sample size +{ + // Calculate confidence intervals for the standard deviation. + // For example if we set the confidence limit to + // 0.95, we know that if we repeat the sampling + // 100 times, then we expect that the true standard deviation + // will be between out limits on 95 occasions. + // Note: this is not the same as saying a 95% + // confidence interval means that there is a 95% + // probability that the interval contains the true standard deviation. + // The interval computed from a given sample either + // contains the true standard deviation or it does not. + // See http://www.itl.nist.gov/div898/handbook/eda/section3/eda358.htm + + // using namespace boost::math; // potential name ambiguity with std <random> + using boost::math::chi_squared; + using boost::math::quantile; + using boost::math::complement; + + // Print out general info: + cout << + "________________________________________________\n" + "2-Sided Confidence Limits For Standard Deviation\n" + "________________________________________________\n\n"; + cout << setprecision(7); + cout << setw(40) << left << "Number of Observations" << "= " << N << "\n"; + cout << setw(40) << left << "Standard Deviation" << "= " << Sd << "\n"; + // + // Define a table of significance/risk levels: + double alpha[] = { 0.5, 0.25, 0.1, 0.05, 0.01, 0.001, 0.0001, 0.00001 }; + // + // Start by declaring the distribution we'll need: + chi_squared dist(N - 1); + // + // Print table header: + // + cout << "\n\n" + "_____________________________________________\n" + "Confidence Lower Upper\n" + " Value (%) Limit Limit\n" + "_____________________________________________\n"; + // + // Now print out the data for the table rows. + for(unsigned i = 0; i < sizeof(alpha)/sizeof(alpha[0]); ++i) + { + // Confidence value: + cout << fixed << setprecision(3) << setw(10) << right << 100 * (1-alpha[i]); + // Calculate limits: + double lower_limit = sqrt((N - 1) * Sd * Sd / quantile(complement(dist, alpha[i] / 2))); + double upper_limit = sqrt((N - 1) * Sd * Sd / quantile(dist, alpha[i] / 2)); + // Print Limits: + cout << fixed << setprecision(5) << setw(15) << right << lower_limit; + cout << fixed << setprecision(5) << setw(15) << right << upper_limit << endl; + } + cout << endl; +} // void confidence_limits_on_std_deviation + +void confidence_limits_on_std_deviation_alpha( + double Sd, // Sample Standard Deviation + double alpha // confidence + ) +{ // Calculate confidence intervals for the standard deviation. + // for the alpha parameter, for a range number of observations, + // from a mere 2 up to a million. + // O. L. Davies, Statistical Methods in Research and Production, ISBN 0 05 002437 X, + // 4.33 Page 68, Table H, pp 452 459. + + // using namespace std; + // using namespace boost::math; + using boost::math::chi_squared; + using boost::math::quantile; + using boost::math::complement; + + // Define a table of numbers of observations: + unsigned int obs[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 30, 40 , 50, 60, 100, 120, 1000, 10000, 50000, 100000, 1000000}; + + cout << // Print out heading: + "________________________________________________\n" + "2-Sided Confidence Limits For Standard Deviation\n" + "________________________________________________\n\n"; + cout << setprecision(7); + cout << setw(40) << left << "Confidence level (two-sided) " << "= " << alpha << "\n"; + cout << setw(40) << left << "Standard Deviation" << "= " << Sd << "\n"; + + cout << "\n\n" // Print table header: + "_____________________________________________\n" + "Observations Lower Upper\n" + " Limit Limit\n" + "_____________________________________________\n"; + for(unsigned i = 0; i < sizeof(obs)/sizeof(obs[0]); ++i) + { + unsigned int N = obs[i]; // Observations + // Start by declaring the distribution with the appropriate : + chi_squared dist(N - 1); + + // Now print out the data for the table row. + cout << fixed << setprecision(3) << setw(10) << right << N; + // Calculate limits: (alpha /2 because it is a two-sided (upper and lower limit) test. + double lower_limit = sqrt((N - 1) * Sd * Sd / quantile(complement(dist, alpha / 2))); + double upper_limit = sqrt((N - 1) * Sd * Sd / quantile(dist, alpha / 2)); + // Print Limits: + cout << fixed << setprecision(4) << setw(15) << right << lower_limit; + cout << fixed << setprecision(4) << setw(15) << right << upper_limit << endl; + } + cout << endl; +}// void confidence_limits_on_std_deviation_alpha + +void chi_squared_test( + double Sd, // Sample std deviation + double D, // True std deviation + unsigned N, // Sample size + double alpha) // Significance level +{ + // + // A Chi Squared test applied to a single set of data. + // We are testing the null hypothesis that the true + // standard deviation of the sample is D, and that any variation is down + // to chance. We can also test the alternative hypothesis + // that any difference is not down to chance. + // See http://www.itl.nist.gov/div898/handbook/eda/section3/eda358.htm + // + // using namespace boost::math; + using boost::math::chi_squared; + using boost::math::quantile; + using boost::math::complement; + using boost::math::cdf; + + // Print header: + cout << + "______________________________________________\n" + "Chi Squared test for sample standard deviation\n" + "______________________________________________\n\n"; + cout << setprecision(5); + cout << setw(55) << left << "Number of Observations" << "= " << N << "\n"; + cout << setw(55) << left << "Sample Standard Deviation" << "= " << Sd << "\n"; + cout << setw(55) << left << "Expected True Standard Deviation" << "= " << D << "\n\n"; + // + // Now we can calculate and output some stats: + // + // test-statistic: + double t_stat = (N - 1) * (Sd / D) * (Sd / D); + cout << setw(55) << left << "Test Statistic" << "= " << t_stat << "\n"; + // + // Finally define our distribution, and get the probability: + // + chi_squared dist(N - 1); + double p = cdf(dist, t_stat); + cout << setw(55) << left << "CDF of test statistic: " << "= " + << setprecision(3) << scientific << p << "\n"; + double ucv = quantile(complement(dist, alpha)); + double ucv2 = quantile(complement(dist, alpha / 2)); + double lcv = quantile(dist, alpha); + double lcv2 = quantile(dist, alpha / 2); + cout << setw(55) << left << "Upper Critical Value at alpha: " << "= " + << setprecision(3) << scientific << ucv << "\n"; + cout << setw(55) << left << "Upper Critical Value at alpha/2: " << "= " + << setprecision(3) << scientific << ucv2 << "\n"; + cout << setw(55) << left << "Lower Critical Value at alpha: " << "= " + << setprecision(3) << scientific << lcv << "\n"; + cout << setw(55) << left << "Lower Critical Value at alpha/2: " << "= " + << setprecision(3) << scientific << lcv2 << "\n\n"; + // + // Finally print out results of alternative hypothesis: + // + cout << setw(55) << left << + "Results for Alternative Hypothesis and alpha" << "= " + << setprecision(4) << fixed << alpha << "\n\n"; + cout << "Alternative Hypothesis Conclusion\n"; + cout << "Standard Deviation != " << setprecision(3) << fixed << D << " "; + if((ucv2 < t_stat) || (lcv2 > t_stat)) + cout << "NOT REJECTED\n"; + else + cout << "REJECTED\n"; + cout << "Standard Deviation < " << setprecision(3) << fixed << D << " "; + if(lcv > t_stat) + cout << "NOT REJECTED\n"; + else + cout << "REJECTED\n"; + cout << "Standard Deviation > " << setprecision(3) << fixed << D << " "; + if(ucv < t_stat) + cout << "NOT REJECTED\n"; + else + cout << "REJECTED\n"; + cout << endl << endl; +} // void chi_squared_test + +void chi_squared_sample_sized( + double diff, // difference from variance to detect + double variance) // true variance +{ + using namespace std; + // using boost::math; + using boost::math::chi_squared; + using boost::math::quantile; + using boost::math::complement; + using boost::math::cdf; + + try + { + cout << // Print out general info: + "_____________________________________________________________\n" + "Estimated sample sizes required for various confidence levels\n" + "_____________________________________________________________\n\n"; + cout << setprecision(5); + cout << setw(40) << left << "True Variance" << "= " << variance << "\n"; + cout << setw(40) << left << "Difference to detect" << "= " << diff << "\n"; + // + // Define a table of significance levels: + // + double alpha[] = { 0.5, 0.33333333333333333333333, 0.25, 0.1, 0.05, 0.01, 0.001, 0.0001, 0.00001 }; + // + // Print table header: + // + cout << "\n\n" + "_______________________________________________________________\n" + "Confidence Estimated Estimated\n" + " Value (%) Sample Size Sample Size\n" + " (lower one- (upper one-\n" + " sided test) sided test)\n" + "_______________________________________________________________\n"; + // + // Now print out the data for the table rows. + // + for(unsigned i = 0; i < sizeof(alpha)/sizeof(alpha[0]); ++i) + { + // Confidence value: + cout << fixed << setprecision(3) << setw(10) << right << 100 * (1-alpha[i]); + // Calculate df for a lower single-sided test: + double df = chi_squared::find_degrees_of_freedom( + -diff, alpha[i], alpha[i], variance); + // Convert to integral sample size (df is a floating point value in this implementation): + double size = ceil(df) + 1; + // Print size: + cout << fixed << setprecision(0) << setw(16) << right << size; + // Calculate df for an upper single-sided test: + df = chi_squared::find_degrees_of_freedom( + diff, alpha[i], alpha[i], variance); + // Convert to integral sample size: + size = ceil(df) + 1; + // Print size: + cout << fixed << setprecision(0) << setw(16) << right << size << endl; + } + cout << endl; + } + catch(const std::exception& e) + { // Always useful to include try & catch blocks because default policies + // are to throw exceptions on arguments that cause errors like underflow, overflow. + // Lacking try & catch blocks, the program will abort without a message below, + // which may give some helpful clues as to the cause of the exception. + std::cout << + "\n""Message from thrown exception was:\n " << e.what() << std::endl; + ++error_result; + } +} // chi_squared_sample_sized + +int main() +{ + // Run tests for Gear data + // see http://www.itl.nist.gov/div898/handbook/eda/section3/eda3581.htm + // Tests measurements of gear diameter. + // + confidence_limits_on_std_deviation(0.6278908E-02, 100); + chi_squared_test(0.6278908E-02, 0.1, 100, 0.05); + chi_squared_sample_sized(0.1 - 0.6278908E-02, 0.1); + // + // Run tests for silicon wafer fabrication data. + // see http://www.itl.nist.gov/div898/handbook/prc/section2/prc23.htm + // A supplier of 100 ohm.cm silicon wafers claims that his fabrication + // process can produce wafers with sufficient consistency so that the + // standard deviation of resistivity for the lot does not exceed + // 10 ohm.cm. A sample of N = 10 wafers taken from the lot has a + // standard deviation of 13.97 ohm.cm + // + confidence_limits_on_std_deviation(13.97, 10); + chi_squared_test(13.97, 10.0, 10, 0.05); + chi_squared_sample_sized(13.97 * 13.97 - 100, 100); + chi_squared_sample_sized(55, 100); + chi_squared_sample_sized(1, 100); + + // List confidence interval multipliers for standard deviation + // for a range of numbers of observations from 2 to a million, + // and for a few alpha values, 0.1, 0.05, 0.01 for confidences 90, 95, 99 % + confidence_limits_on_std_deviation_alpha(1., 0.1); + confidence_limits_on_std_deviation_alpha(1., 0.05); + confidence_limits_on_std_deviation_alpha(1., 0.01); + + return error_result; +} + +/* + +________________________________________________ +2-Sided Confidence Limits For Standard Deviation +________________________________________________ +Number of Observations = 100 +Standard Deviation = 0.006278908 +_____________________________________________ +Confidence Lower Upper + Value (%) Limit Limit +_____________________________________________ + 50.000 0.00601 0.00662 + 75.000 0.00582 0.00685 + 90.000 0.00563 0.00712 + 95.000 0.00551 0.00729 + 99.000 0.00530 0.00766 + 99.900 0.00507 0.00812 + 99.990 0.00489 0.00855 + 99.999 0.00474 0.00895 +______________________________________________ +Chi Squared test for sample standard deviation +______________________________________________ +Number of Observations = 100 +Sample Standard Deviation = 0.00628 +Expected True Standard Deviation = 0.10000 +Test Statistic = 0.39030 +CDF of test statistic: = 1.438e-099 +Upper Critical Value at alpha: = 1.232e+002 +Upper Critical Value at alpha/2: = 1.284e+002 +Lower Critical Value at alpha: = 7.705e+001 +Lower Critical Value at alpha/2: = 7.336e+001 +Results for Alternative Hypothesis and alpha = 0.0500 +Alternative Hypothesis Conclusion +Standard Deviation != 0.100 NOT REJECTED +Standard Deviation < 0.100 NOT REJECTED +Standard Deviation > 0.100 REJECTED +_____________________________________________________________ +Estimated sample sizes required for various confidence levels +_____________________________________________________________ +True Variance = 0.10000 +Difference to detect = 0.09372 +_______________________________________________________________ +Confidence Estimated Estimated + Value (%) Sample Size Sample Size + (lower one- (upper one- + sided test) sided test) +_______________________________________________________________ + 50.000 2 2 + 66.667 2 5 + 75.000 2 10 + 90.000 4 32 + 95.000 5 52 + 99.000 8 102 + 99.900 13 178 + 99.990 18 257 + 99.999 23 337 +________________________________________________ +2-Sided Confidence Limits For Standard Deviation +________________________________________________ +Number of Observations = 10 +Standard Deviation = 13.9700000 +_____________________________________________ +Confidence Lower Upper + Value (%) Limit Limit +_____________________________________________ + 50.000 12.41880 17.25579 + 75.000 11.23084 19.74131 + 90.000 10.18898 22.98341 + 95.000 9.60906 25.50377 + 99.000 8.62898 31.81825 + 99.900 7.69466 42.51593 + 99.990 7.04085 55.93352 + 99.999 6.54517 73.00132 +______________________________________________ +Chi Squared test for sample standard deviation +______________________________________________ +Number of Observations = 10 +Sample Standard Deviation = 13.97000 +Expected True Standard Deviation = 10.00000 +Test Statistic = 17.56448 +CDF of test statistic: = 9.594e-001 +Upper Critical Value at alpha: = 1.692e+001 +Upper Critical Value at alpha/2: = 1.902e+001 +Lower Critical Value at alpha: = 3.325e+000 +Lower Critical Value at alpha/2: = 2.700e+000 +Results for Alternative Hypothesis and alpha = 0.0500 +Alternative Hypothesis Conclusion +Standard Deviation != 10.000 REJECTED +Standard Deviation < 10.000 REJECTED +Standard Deviation > 10.000 NOT REJECTED +_____________________________________________________________ +Estimated sample sizes required for various confidence levels +_____________________________________________________________ +True Variance = 100.00000 +Difference to detect = 95.16090 +_______________________________________________________________ +Confidence Estimated Estimated + Value (%) Sample Size Sample Size + (lower one- (upper one- + sided test) sided test) +_______________________________________________________________ + 50.000 2 2 + 66.667 2 5 + 75.000 2 10 + 90.000 4 32 + 95.000 5 51 + 99.000 7 99 + 99.900 11 174 + 99.990 15 251 + 99.999 20 330 +_____________________________________________________________ +Estimated sample sizes required for various confidence levels +_____________________________________________________________ +True Variance = 100.00000 +Difference to detect = 55.00000 +_______________________________________________________________ +Confidence Estimated Estimated + Value (%) Sample Size Sample Size + (lower one- (upper one- + sided test) sided test) +_______________________________________________________________ + 50.000 2 2 + 66.667 4 10 + 75.000 8 21 + 90.000 23 71 + 95.000 36 115 + 99.000 71 228 + 99.900 123 401 + 99.990 177 580 + 99.999 232 762 +_____________________________________________________________ +Estimated sample sizes required for various confidence levels +_____________________________________________________________ +True Variance = 100.00000 +Difference to detect = 1.00000 +_______________________________________________________________ +Confidence Estimated Estimated + Value (%) Sample Size Sample Size + (lower one- (upper one- + sided test) sided test) +_______________________________________________________________ + 50.000 2 2 + 66.667 14696 14993 + 75.000 36033 36761 + 90.000 130079 132707 + 95.000 214283 218612 + 99.000 428628 437287 + 99.900 756333 771612 + 99.990 1095435 1117564 + 99.999 1440608 1469711 +________________________________________________ +2-Sided Confidence Limits For Standard Deviation +________________________________________________ +Confidence level (two-sided) = 0.1000000 +Standard Deviation = 1.0000000 +_____________________________________________ +Observations Lower Upper + Limit Limit +_____________________________________________ + 2 0.5102 15.9472 + 3 0.5778 4.4154 + 4 0.6196 2.9200 + 5 0.6493 2.3724 + 6 0.6720 2.0893 + 7 0.6903 1.9154 + 8 0.7054 1.7972 + 9 0.7183 1.7110 + 10 0.7293 1.6452 + 15 0.7688 1.4597 + 20 0.7939 1.3704 + 30 0.8255 1.2797 + 40 0.8454 1.2320 + 50 0.8594 1.2017 + 60 0.8701 1.1805 + 100 0.8963 1.1336 + 120 0.9045 1.1203 + 1000 0.9646 1.0383 + 10000 0.9885 1.0118 + 50000 0.9948 1.0052 + 100000 0.9963 1.0037 + 1000000 0.9988 1.0012 +________________________________________________ +2-Sided Confidence Limits For Standard Deviation +________________________________________________ +Confidence level (two-sided) = 0.0500000 +Standard Deviation = 1.0000000 +_____________________________________________ +Observations Lower Upper + Limit Limit +_____________________________________________ + 2 0.4461 31.9102 + 3 0.5207 6.2847 + 4 0.5665 3.7285 + 5 0.5991 2.8736 + 6 0.6242 2.4526 + 7 0.6444 2.2021 + 8 0.6612 2.0353 + 9 0.6755 1.9158 + 10 0.6878 1.8256 + 15 0.7321 1.5771 + 20 0.7605 1.4606 + 30 0.7964 1.3443 + 40 0.8192 1.2840 + 50 0.8353 1.2461 + 60 0.8476 1.2197 + 100 0.8780 1.1617 + 120 0.8875 1.1454 + 1000 0.9580 1.0459 + 10000 0.9863 1.0141 + 50000 0.9938 1.0062 + 100000 0.9956 1.0044 + 1000000 0.9986 1.0014 +________________________________________________ +2-Sided Confidence Limits For Standard Deviation +________________________________________________ +Confidence level (two-sided) = 0.0100000 +Standard Deviation = 1.0000000 +_____________________________________________ +Observations Lower Upper + Limit Limit +_____________________________________________ + 2 0.3562 159.5759 + 3 0.4344 14.1244 + 4 0.4834 6.4675 + 5 0.5188 4.3960 + 6 0.5464 3.4848 + 7 0.5688 2.9798 + 8 0.5875 2.6601 + 9 0.6036 2.4394 + 10 0.6177 2.2776 + 15 0.6686 1.8536 + 20 0.7018 1.6662 + 30 0.7444 1.4867 + 40 0.7718 1.3966 + 50 0.7914 1.3410 + 60 0.8065 1.3026 + 100 0.8440 1.2200 + 120 0.8558 1.1973 + 1000 0.9453 1.0609 + 10000 0.9821 1.0185 + 50000 0.9919 1.0082 + 100000 0.9943 1.0058 + 1000000 0.9982 1.0018 +*/ + diff --git a/src/boost/libs/math/example/constants_eg1.cpp b/src/boost/libs/math/example/constants_eg1.cpp new file mode 100644 index 000000000..53516145e --- /dev/null +++ b/src/boost/libs/math/example/constants_eg1.cpp @@ -0,0 +1,192 @@ +// Copyright Paul Bristow 2013. +// Copyright John Maddock 2010. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +/*! \brief Examples of using the enhanced math constants. + \details This allows for access to constants via functions like @c pi(), + and also via namespaces, @c using @c namespace boost::math::double_constants; + called simply @c pi. +*/ + +#include <boost/math/constants/constants.hpp> + +#include <iostream> +using std::cout; +using std::endl; + +#include <limits> +using std::numeric_limits; + +/*! \brief Examples of a template function using constants. + \details This example shows using of constants from function calls like @c pi(), + rather than the 'cute' plain @c pi use in non-template applications. + + \tparam Real radius parameter that can be a built-in like float, double, + or a user-defined type like multiprecision. + \returns Area = pi * radius ^ 2 +*/ + +//[math_constants_eg1 +template<class Real> +Real area(Real r) +{ + using namespace boost::math::constants; + + return pi<Real>() * r * r; +} +//] [/math_constants_eg1] + +int main() +{ + + { // Boost.Math constants using function calls like pi(). + // using namespace boost::math::constants; + + using boost::math::constants::pi; + using boost::math::constants::one_div_two_pi; + +#ifdef BOOST_NO_CXX11_NUMERIC_LIMITS + std::size_t max_digits10 = 2 + std::numeric_limits<double>::digits * 3010/10000; +#else + std::size_t max_digits10 = std::numeric_limits<double>::max_digits10; +#endif + + std::cout.precision(max_digits10); + cout << "double pi = boost::math::double_constants::pi = " << pi<double>() << endl; + // double pi = boost::math::double_constants::pi = 3.1415926535897931 + double r = 1.234567890123456789; + double d = pi<double>() * r * r; + + cout << "d = " << d << ", r = " << r << endl; + + float rf = 0.987654321987654321f; + + float pif = boost::math::constants::pi<float>(); + cout << "pidf = boost::math::constants::pi() = " << pif << endl; + // pidf = boost::math::float_constants::pi = 3.1415927410125732 + + //float df = pi * rf * rf; // conversion from 'const double' to 'float', possible loss of data. + float df = pif * rf * rf; + + cout << "df = " << df << ", rf = " << rf << endl; + + cout << "one_div_two_pi " << one_div_two_pi<double>() << endl; + + using boost::math::constants::one_div_two_pi; + + cout << "one_div_root_two_pi " << one_div_two_pi<double>() << endl; + } + + { // Boost math new constants using namespace selected values, like pi. + + //using namespace boost::math::float_constants; + using namespace boost::math::double_constants; + + double my2pi = two_pi; // Uses boost::math::double_constants::two_pi; + + cout << "double my2pi = " << my2pi << endl; + + using boost::math::float_constants::e; + float my_e = e; + cout << "float my_e " << my_e << endl; + + double my_pi = boost::math::double_constants::pi; + cout << "double my_pi = boost::math::double_constants::pi = " << my_pi << endl; + + // If you try to use two namespaces, this may, of course, create ambiguity: + // it is not too difficult to do this inadvertently. + using namespace boost::math::float_constants; + //cout << pi << endl; // error C2872: 'pi' : ambiguous symbol. + + } + { + +//[math_constants_ambiguity + // If you use more than one namespace, this will, of course, create ambiguity: + using namespace boost::math::double_constants; + using namespace boost::math::constants; + + //double my_pi = pi(); // error C2872: 'pi' : ambiguous symbol + //double my_pi2 = pi; // Context does not allow for disambiguation of overloaded function + + // It is also possible to create ambiguity inadvertently, + // perhaps in other peoples code, + // by making the scope of a namespace declaration wider than necessary, + // therefore is it prudent to avoid this risk by localising the scope of such definitions. +//] [/math_constants_ambiguity] + + } + + { // You can, of course, use both methods of access if both are fully qualified, for examples: + + //cout.precision(std::numeric_limits<double>::max_digits10);// Ideally. + cout.precision(2 + std::numeric_limits<double>::digits * 3010/10000); // If no max_digits10. + + double my_pi1 = boost::math::constants::pi<double>(); + double my_pid = boost::math::double_constants::pi; + cout << "boost::math::constants::pi<double>() = " << my_pi1 << endl + << "boost::math::double_constants::pi = " << my_pid << endl; + + // cout.precision(std::numeric_limits<float>::max_digits10); // Ideally. + cout.precision(2 + std::numeric_limits<double>::digits * 3010/10000); // If no max_digits10. + float my_pif = boost::math::float_constants::pi; + cout << "boost::math::float_constants::pi = " << my_pif << endl; + + } + + { // Use with templates + + // \warning it is important to be very careful with the type provided as parameter. + // For example, naively providing an @b integer instead of a floating-point type can be disastrous. + // cout << "Area = " << area(2) << endl; // warning : 'return' : conversion from 'double' to 'int', possible loss of data + // Failure to heed this warning can lead to very wrong answers! + // Area = 12 !! = 3 * 2 * 2 +//[math_constants_template_integer_type + //cout << "Area = " << area(2) << endl; // Area = 12! + cout << "Area = " << area(2.) << endl; // Area = 12.566371 + + // You can also avoid this by being explicit about the type of @c area. + cout << "Area = " << area<double>(2) << endl; + +//] [/math_constants_template_integer_type] + + + } +/* +{ + using boost::math::constants::pi; + //double my_pi3 = pi<double>(); // OK + //double my_pi4 = pi<>(); cannot find template type. + //double my_pi4 = pi(); // Can't find a function. + + } +*/ + +} // int main() + +/*[constants_eq1_output + +Output: + + double pi = boost::math::double_constants::pi = 3.1415926535897931 + d = 4.7882831840285398, r = 1.2345678901234567 + pidf = boost::math::constants::pi() = 3.1415927410125732 + df = 3.0645015239715576, rf = 0.98765432834625244 + one_div_two_pi 0.15915494309189535 + one_div_root_two_pi 0.15915494309189535 + double my2pi = 6.2831853071795862 + float my_e 2.7182817459106445 + double my_pi = boost::math::double_constants::pi = 3.1415926535897931 + boost::math::constants::pi<double>() = 3.1415926535897931 + boost::math::double_constants::pi = 3.1415926535897931 + boost::math::float_constants::pi = 3.1415927410125732 + Area = 12.566370614359172 + Area = 12.566370614359172 + + +] [/constants_eq1_output] +*/ diff --git a/src/boost/libs/math/example/continued_fractions.cpp b/src/boost/libs/math/example/continued_fractions.cpp new file mode 100644 index 000000000..23f479fc9 --- /dev/null +++ b/src/boost/libs/math/example/continued_fractions.cpp @@ -0,0 +1,150 @@ +// (C) Copyright John Maddock 2018. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/math/tools/fraction.hpp> +#include <iostream> +#include <complex> +#include <boost/multiprecision/cpp_complex.hpp> + +//[golden_ratio_1 +template <class T> +struct golden_ratio_fraction +{ + typedef T result_type; + + result_type operator()() + { + return 1; + } +}; +//] + +//[cf_tan_fraction +template <class T> +struct tan_fraction +{ +private: + T a, b; +public: + tan_fraction(T v) + : a(-v * v), b(-1) + {} + + typedef std::pair<T, T> result_type; + + std::pair<T, T> operator()() + { + b += 2; + return std::make_pair(a, b); + } +}; +//] +//[cf_tan +template <class T> +T tan(T a) +{ + tan_fraction<T> fract(a); + return a / continued_fraction_b(fract, std::numeric_limits<T>::epsilon()); +} +//] +//[cf_expint_fraction +template <class T> +struct expint_fraction +{ + typedef std::pair<T, T> result_type; + expint_fraction(unsigned n_, T z_) : b(z_ + T(n_)), i(-1), n(n_) {} + std::pair<T, T> operator()() + { + std::pair<T, T> result = std::make_pair(-static_cast<T>((i + 1) * (n + i)), b); + b += 2; + ++i; + return result; + } +private: + T b; + int i; + unsigned n; +}; +//] +//[cf_expint +template <class T> +inline std::complex<T> expint_as_fraction(unsigned n, std::complex<T> const& z) +{ + boost::uintmax_t max_iter = 1000; + expint_fraction<std::complex<T> > f(n, z); + std::complex<T> result = boost::math::tools::continued_fraction_b( + f, + std::complex<T>(std::numeric_limits<T>::epsilon()), + max_iter); + result = exp(-z) / result; + return result; +} +//] +//[cf_upper_gamma_fraction +template <class T> +struct upper_incomplete_gamma_fract +{ +private: + typedef typename T::value_type scalar_type; + T z, a; + int k; +public: + typedef std::pair<T, T> result_type; + + upper_incomplete_gamma_fract(T a1, T z1) + : z(z1 - a1 + scalar_type(1)), a(a1), k(0) + { + } + + result_type operator()() + { + ++k; + z += scalar_type(2); + return result_type(scalar_type(k) * (a - scalar_type(k)), z); + } +}; +//] +//[cf_gamma_Q +template <class T> +inline std::complex<T> gamma_Q_as_fraction(const std::complex<T>& a, const std::complex<T>& z) +{ + upper_incomplete_gamma_fract<std::complex<T> > f(a, z); + std::complex<T> eps(std::numeric_limits<T>::epsilon()); + return pow(z, a) / (exp(z) *(z - a + T(1) + boost::math::tools::continued_fraction_a(f, eps))); +} +//] +inline boost::multiprecision::cpp_complex_50 gamma_Q_as_fraction(const boost::multiprecision::cpp_complex_50& a, const boost::multiprecision::cpp_complex_50& z) +{ + upper_incomplete_gamma_fract<boost::multiprecision::cpp_complex_50> f(a, z); + boost::multiprecision::cpp_complex_50 eps(std::numeric_limits<boost::multiprecision::cpp_complex_50::value_type>::epsilon()); + return pow(z, a) / (exp(z) * (z - a + 1 + boost::math::tools::continued_fraction_a(f, eps))); +} + + +int main() +{ + using namespace boost::math::tools; + + //[cf_gr + golden_ratio_fraction<double> func; + double gr = continued_fraction_a( + func, + std::numeric_limits<double>::epsilon()); + std::cout << "The golden ratio is: " << gr << std::endl; + //] + + std::cout << tan(0.5) << std::endl; + + std::complex<double> arg(3, 2); + std::cout << expint_as_fraction(5, arg) << std::endl; + + std::complex<double> a(3, 3), z(3, 2); + std::cout << gamma_Q_as_fraction(a, z) << std::endl; + + boost::multiprecision::cpp_complex_50 am(3, 3), zm(3, 2); + std::cout << gamma_Q_as_fraction(am, zm) << std::endl; + + return 0; +} diff --git a/src/boost/libs/math/example/cstdfloat_example.cpp b/src/boost/libs/math/example/cstdfloat_example.cpp new file mode 100644 index 000000000..761e811b1 --- /dev/null +++ b/src/boost/libs/math/example/cstdfloat_example.cpp @@ -0,0 +1,488 @@ +// Copyright John Maddock 2014 +// Copyright Christopher Kormanyos 2014. +// Copyright Paul A. Bristow 2016. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Contains Quickbook snippets as C++ comments - do not remove. + +/* +`This example shows use of a specified-width floating-point typedef +to evaluate a moderately complex math function using +[@http://en.wikipedia.org/wiki/Double-precision_floating-point_format IEEE754 64-bit double-precision]. +about 15 decimal digits `std::numeric_limits<boost::float64_t>::digits10`, +(but never exceeding 17 decimal digits `std::numeric_limits<boost::float64_t>::max_digits10`). + +The Jahnke-Emden lambda function is described at + +Weisstein, Eric W. "Lambda Function." From MathWorld--A Wolfram Web Resource. +http://mathworld.wolfram.com/LambdaFunction.html + +E. Jahnke and F. Emden, "Tables of Functions with Formulae and Curves," +Dover, New York, 4th ed., (1945), pages 180-188. + +*/ + +//[cstdfloat_example_1 +#include <boost/cstdfloat.hpp> // For float_64_t, float128_t. Must be first include! +#include <cmath> // for pow function. +#include <boost/math/special_functions.hpp> // For gamma function. +//] [/cstdfloat_example_1] +#include <boost/type_traits/is_same.hpp> + +#include <iostream> + +/*! +Function max_digits10 +Returns maximum number of possibly significant decimal digits for a floating-point type FPT, +even for older compilers/standard libraries that +lack support for std::numeric_limits<FPT>::max_digits10, +when the Kahan formula 2 + binary_digits * 0.3010 is used instead. +Also provides the correct result for Visual Studio 2010 +(where the value 8 provided for float is wrong). +*/ +namespace boost +{ +template <typename FPT> +const int max_digits10() +{ +// Since max_digits10 is not defined (or wrong) on older systems, define a local max_digits10. + // Usage: int m = max_digits10<boost::float64_t>(); + const int m = +#if (defined BOOST_NO_CXX11_NUMERIC_LIMITS) || (_MSC_VER == 1600) // is wrongly 8 not 9 for VS2010. + 2 + std::numeric_limits<FPT>::digits * 3010/10000; +#else + std::numeric_limits<FPT>::max_digits10; +#endif + return m; +} +} // namespace boost + +//`Define the Jahnke-Emden_lambda function. +//[cstdfloat_example_2 +boost::float64_t jahnke_emden_lambda(boost::float64_t v, boost::float64_t x) +{ + const boost::float64_t gamma_v_plus_one = boost::math::tgamma(v + 1); + const boost::float64_t x_half_pow_v = std::pow(x /2, v); + + return gamma_v_plus_one * boost::math::cyl_bessel_j(x, v) / x_half_pow_v; +} +//] [/cstdfloat_example_2] + +int main() +{ + std::cout.setf(std::ios::showpoint); // show all significant trailing zeros. + + long double p = 1.L; + //std::cout.precision(std::numeric_limits<long double>::digits10); + + std::cout << "pi = " << p << std::endl; + +//[cstdfloat_example_3 +//`Ensure that all possibly significant digits (17) including trailing zeros are shown. + + std::cout.precision(std::numeric_limits<boost::float64_t>::max_digits10); + std::cout.setf(std::ios::showpoint); // Show trailing zeros. + + try + { // Always use try'n'catch blocks to ensure any error messages are displayed. + + // Evaluate and display an evaluation of the Jahnke-Emden lambda function: + boost::float64_t v = 1.; + boost::float64_t x = 1.; + std::cout << jahnke_emden_lambda(v, x) << std::endl; // 0.88010117148986700 +//] [/cstdfloat_example_3] + + // We can show some evaluations with various precisions: + { // float64_t + for (int i = 0; i < 10; i++) + { + std::cout << std::setprecision(2) << boost::float64_t(i) << ' ' + << std::setprecision(std::numeric_limits<boost::float64_t>::max_digits10) + << jahnke_emden_lambda(boost::float64_t(i), v) << std::endl; // + } + } + { // floatmax_t = the maximum available on this platform. + for (int i = 0; i < 10; i++) + { + std::cout << std::setprecision(2) << boost::floatmax_t(i) << ' ' + << std::setprecision(std::numeric_limits<boost::floatmax_t>::max_digits10) + << jahnke_emden_lambda(boost::floatmax_t(i), v) << std::endl; // + } + } + // Show the precision of long double (this might be 64, 80 or 128 bits). + std::cout << "Floating-point type long double is available with:" << std::endl; + std::cout << " std::numeric_limits<long double>::digits10 == " + << std::numeric_limits<long double>::digits10 << std::endl; // 18 + std::cout << " std::numeric_limits<long double>::max_digits10 == " + << std::numeric_limits<long double>::max_digits10 << std::endl; // 21 + long double p = boost::math::constants::pi<double>(); + std::cout.precision(std::numeric_limits<long double>::digits10); + std::cout << "pi = " << p << std::endl; + +//[cstdfloat_constant_2 +//`These allow floating-point [*constants of at least the specified width] to be declared: + + // Declare Archimedes' constant using float32_t with approximately 7 decimal digits of precision. + static const boost::float32_t pi = BOOST_FLOAT32_C(3.1415926536); + + // Declare the Euler-gamma constant with approximately 15 decimal digits of precision. + static const boost::float64_t euler = + BOOST_FLOAT64_C(0.57721566490153286060651209008240243104216); + + // Declare the Golden Ratio constant with the maximum decimal digits of precision that the platform supports. + static const boost::floatmax_t golden_ratio = + BOOST_FLOATMAX_C(1.61803398874989484820458683436563811772); +//] [/cstdfloat_constant_2] + +// http://www.boost.org/doc/libs/1_55_0/libs/multiprecision/doc/html/boost_multiprecision/tut/floats/float128.html +//[cstdfloat_constant_1 +// Display the constant pi to the maximum available precision. + boost::floatmax_t pi_max = boost::math::constants::pi<boost::floatmax_t>(); + std::cout.precision(std::numeric_limits<boost::floatmax_t>::digits10); + std::cout << "Most precise pi = " << pi_max << std::endl; +// If floatmax_t is float_128_t, then +// Most precise pi = 3.141592653589793238462643383279503 +//] [/cstdfloat_constant_1] + +// Test all the floating-point precisions in turn, and if they are available +// then display how many decimal digits of precision. +#ifdef BOOST_FLOAT16_C + std::cout << "Floating-point type boost::float16_t is available." << std::endl; +#else + std::cout << "Floating-point type boost::float16_t is NOT available." << std::endl; +#endif + +#ifdef BOOST_FLOAT32_C + std::cout << "Floating-point type boost::float32_t is available." << std::endl; + std::cout << " std::numeric_limits<boost::float32_t>::digits10 == " + << std::numeric_limits<boost::float32_t>::digits10 << std::endl; + std::cout << " std::numeric_limits<boost::float32_t>::max_digits10 == " + << std::numeric_limits<boost::float32_t>::max_digits10 << std::endl; +#else + std::cout << "Floating-point type boost::float32_t is NOT available." << std::endl; +#endif + +#ifdef BOOST_FLOAT64_C + std::cout << "Floating-point type boost::float64_t is available." << std::endl; + std::cout << " std::numeric_limits<boost::float64_t>::digits10 == " + << std::numeric_limits<boost::float64_t>::digits10 << std::endl; + std::cout << " std::numeric_limits<boost::float64_t>::max_digits10 == " + << std::numeric_limits<boost::float64_t>::max_digits10 << std::endl; +#else + std::cout << "Floating-point type boost::float64_t is NOT available." << std::endl; +#endif + +#ifdef BOOST_FLOAT80_C + std::cout << "Floating-point type boost::float80_t is available." << std::endl; + std::cout << " std::numeric_limits<boost::float80_t>::digits10 == " + << std::numeric_limits<boost::float80_t>::digits10 << std::endl; + std::cout << " std::numeric_limits<boost::float80_t>::max_digits10 == " + << std::numeric_limits<boost::float80_t>::max_digits10 << std::endl; +#else + std::cout << "Floating-point type boost::float80_t is NOT available." << std::endl; +#endif + +#ifdef BOOST_FLOAT128_C + std::cout << "Floating-point type boost::float128_t is available." << std::endl; + std::cout << " std::numeric_limits<boost::float128_t>::digits10 == " + << std::numeric_limits<boost::float128_t>::digits10 << std::endl; + std::cout << " std::numeric_limits<boost::float128_t>::max_digits10 == " + << std::numeric_limits<boost::float128_t>::max_digits10 << std::endl; +#else + std::cout << "Floating-point type boost::float128_t is NOT available." << std::endl; +#endif + +// Show some constants at a precision depending on the available type(s). +#ifdef BOOST_FLOAT16_C + std::cout.precision(boost::max_digits10<boost::float16_t>()); // Show all significant decimal digits, + std::cout.setf(std::ios::showpoint); // including all significant trailing zeros. + + std::cout << "BOOST_FLOAT16_C(123.456789012345678901234567890) = " + << BOOST_FLOAT16_C(123.456789012345678901234567890) << std::endl; + // BOOST_FLOAT16_C(123.456789012345678901234567890) = 123.45678901234568 +#endif + +//[floatmax_widths_1 +#ifdef BOOST_FLOAT32_C + std::cout.precision(boost::max_digits10<boost::float32_t>()); // Show all significant decimal digits, + std::cout.setf(std::ios::showpoint); // including all significant trailing zeros. + std::cout << "BOOST_FLOAT32_C(123.4567890123456789012345678901234567890) = " + << BOOST_FLOAT32_C(123.4567890123456789012345678901234567890) << std::endl; + // BOOST_FLOAT32_C(123.4567890123456789012345678901234567890) = 123.456787 +#endif +//] [/floatmax_widths_1] + +#ifdef BOOST_FLOAT64_C + std::cout.precision(boost::max_digits10<boost::float64_t>()); // Show all significant decimal digits, + std::cout.setf(std::ios::showpoint); // including all significant trailing zeros. + std::cout << "BOOST_FLOAT64_C(123.4567890123456789012345678901234567890) = " + << BOOST_FLOAT64_C(123.4567890123456789012345678901234567890) << std::endl; + // BOOST_FLOAT64_C(123.4567890123456789012345678901234567890) = 123.45678901234568 +#endif + +#ifdef BOOST_FLOAT80_C + std::cout.precision(boost::max_digits10<boost::float80_t>()); // Show all significant decimal digits, + std::cout.setf(std::ios::showpoint); // including all significant trailing zeros. + std::cout << "BOOST_FLOAT80_C(123.4567890123456789012345678901234567890) = " + << BOOST_FLOAT80_C(123.4567890123456789012345678901234567890) << std::endl; + // BOOST_FLOAT80_C(123.4567890123456789012345678901234567890) = 123.456789012345678903 +#endif + +#ifdef BOOST_FLOAT128_C + std::cout.precision(boost::max_digits10<boost::float128_t>()); // Show all significant decimal digits, + std::cout.setf(std::ios::showpoint); // including all significant trailing zeros. + std::cout << "BOOST_FLOAT128_C(123.4567890123456789012345678901234567890) = " + << BOOST_FLOAT128_C(123.4567890123456789012345678901234567890) << std::endl; + // BOOST_FLOAT128_C(123.4567890123456789012345678901234567890) = 123.456789012345678901234567890123453 +#endif + +/* +//[floatmax_widths_2 +BOOST_FLOAT32_C(123.4567890123456789012345678901234567890) = 123.456787 +BOOST_FLOAT64_C(123.4567890123456789012345678901234567890) = 123.45678901234568 +BOOST_FLOAT80_C(123.4567890123456789012345678901234567890) = 123.456789012345678903 +BOOST_FLOAT128_C(123.4567890123456789012345678901234567890) = 123.456789012345678901234567890123453 +//] [/floatmax_widths_2] +*/ + +// Display the precisions available for floatmax_t + +#ifdef BOOST_FLOATMAX_C + BOOST_ASSERT(std::numeric_limits<boost::floatmax_t>::is_specialized == true); + BOOST_ASSERT(std::numeric_limits<boost::floatmax_t>::is_iec559 == true); + BOOST_ASSERT(BOOST_FLOATMAX_C(0.) == 0); + + std::cout << "floatmax_t " << std::numeric_limits<boost::floatmax_t>::digits << " bits\n" // 113 + << std::numeric_limits<boost::floatmax_t>::digits10 << " decimal digits\n" // 34 + << std::numeric_limits<boost::floatmax_t>::max_digits10 << " max_digits\n" // 36 + << std::numeric_limits<boost::floatmax_t>::radix << " radix\n" + << std::endl; + + int significand_bits = std::numeric_limits<boost::floatmax_t>::digits; + int exponent_max = std::numeric_limits<boost::floatmax_t>::max_exponent; + int exponent_min = std::numeric_limits<boost::floatmax_t>::min_exponent; + int exponent_bits = 1 + static_cast<int>(std::log2(std::numeric_limits<boost::floatmax_t>::max_exponent)); + int sign_bits = std::numeric_limits<boost::floatmax_t>::is_signed; + + std::cout << "significand_bits (including one implicit bit)" << significand_bits + << ", exponent_bits " << exponent_bits + << ", sign_bits " << sign_bits << std::endl; + + // One can compute the total number of bits in the floatmax_t, + // but probably not at compile time. + + std::cout << "bits = " << significand_bits + exponent_bits + sign_bits -1 << std::endl; + // -1 to take account of the implicit bit that is not part of the physical layout. + + // One can compare typedefs (but, of course, only those that are defined for the platform in use.) + std::cout.setf(std::ios::boolalpha); + std::cout << "double, double: " << std::is_same<double, double>::value << std::endl; + bool b = boost::is_same<boost::floatmax_t, boost::float64_t>::value; + std::cout << "boost::is_same<boost::floatmax_t, boost::float64_t>::value; " << b << std::endl; + std::cout << "floatmax_t, float64_t: " + << std::is_same<boost::floatmax_t, boost::float64_t>::value << std::endl; + +/*`So the simplest way of obtaining the total number of bits in the floatmax_t +is to infer it from the std::numeric_limits<>::digits value. +This is possible because the type, must be a IEEE754 layout. */ +//[floatmax_1 + const int fpbits = + (std::numeric_limits<boost::floatmax_t>::digits == 113) ? 128 : + (std::numeric_limits<boost::floatmax_t>::digits == 64) ? 80 : + (std::numeric_limits<boost::floatmax_t>::digits == 53) ? 64 : + (std::numeric_limits<boost::floatmax_t>::digits == 24) ? 32 : + (std::numeric_limits<boost::floatmax_t>::digits == 11) ? 16 : + 0; // Unknown - not IEEE754 format. + std::cout << fpbits << " bits." << std::endl; +//] [/floatmax_1] +#endif + + } + catch (std::exception ex) + { // Display details about why any exceptions are thrown. + std::cout << "Thrown exception " << ex.what() << std::endl; + } + +} // int main() + +/* +[cstdfloat_output + +GCC 4.8.1 with quadmath + + pi = 1.00000 + 0.88010117148986700 + 0.0 0.0000000000000000 + 1.0 0.88010117148986700 + 2.0 4.6137984620549872 + 3.0 16.274830009244951 + 4.0 -25.360637961042869 + 5.0 -1257.9038883512264 + 6.0 -12749.592182518225 + 7.0 -3020.9830849309437 + 8.0 2421897.6013183584 + 9.0 45577595.449204877 + 0.0 0.00000000000000000000000000000000000 + 1.0 0.880101171489866995756301548681221902 + 2.0 4.61379846205498722611082484945654869 + 3.0 16.2748300092449511566883302293717861 + 4.0 -25.3606379610428689375112298876047134 + 5.0 -1257.90388835122644195507746189832687 + 6.0 -12749.5921825182249449426308274269104 + 7.0 -3020.98308493094373261556029319763184 + 8.0 2421897.60131835844367742538452148438 + 9.0 45577595.4492048770189285278320312500 + Floating-point type long double is available with: + std::numeric_limits<long double>::digits10 == 18 + std::numeric_limits<long double>::max_digits10 == 21 + pi = 3.14159265358979312 + Most precise pi = 3.141592653589793238462643383279503 + Floating-point type boost::float16_t is NOT available. + Floating-point type boost::float32_t is available. + std::numeric_limits<boost::float32_t>::digits10 == 6 + std::numeric_limits<boost::float32_t>::max_digits10 == 9 + Floating-point type boost::float64_t is available. + std::numeric_limits<boost::float64_t>::digits10 == 15 + std::numeric_limits<boost::float64_t>::max_digits10 == 17 + Floating-point type boost::float80_t is available. + std::numeric_limits<boost::float80_t>::digits10 == 18 + std::numeric_limits<boost::float80_t>::max_digits10 == 21 + Floating-point type boost::float128_t is available. + std::numeric_limits<boost::float128_t>::digits10 == 34 + std::numeric_limits<boost::float128_t>::max_digits10 == 36 + BOOST_FLOAT32_C(123.4567890123456789012345678901234567890) = 123.456787 + BOOST_FLOAT64_C(123.4567890123456789012345678901234567890) = 123.45678901234568 + BOOST_FLOAT80_C(123.4567890123456789012345678901234567890) = 123.456789012345678903 + BOOST_FLOAT128_C(123.4567890123456789012345678901234567890) = 123.456789012345678901234567890123453 + floatmax_t 113 bits + 34 decimal digits + 36 max_digits + 2 radix + + significand_bits (including one implicit bit)113, exponent_bits 15, sign_bits 1 + bits = 128 + double, double: true + boost::is_same<boost::floatmax_t, boost::float64_t>::value; false + floatmax_t, float64_t: false + 128 bits. + + RUN SUCCESSFUL (total time: 53ms) + +GCC 6.1.1 + +pi = 1.00000 +0.88010117148986700 +0.0 0.0000000000000000 +1.0 0.88010117148986700 +2.0 4.6137984620549872 +3.0 16.274830009244951 +4.0 -25.360637961042869 +5.0 -1257.9038883512264 +6.0 -12749.592182518225 +7.0 -3020.9830849309437 +8.0 2421897.6013183584 +9.0 45577595.449204877 +0.0 0.00000000000000000000000000000000000 +1.0 0.880101171489866995756301548681221902 +2.0 4.61379846205498722611082484945654869 +3.0 16.2748300092449511566883302293717861 +4.0 -25.3606379610428689375112298876047134 +5.0 -1257.90388835122644195507746189832687 +6.0 -12749.5921825182249449426308274269104 +7.0 -3020.98308493094373261556029319763184 +8.0 2421897.60131835844367742538452148438 +9.0 45577595.4492048770189285278320312500 +Floating-point type long double is available with: + std::numeric_limits<long double>::digits10 == 18 + std::numeric_limits<long double>::max_digits10 == 21 +pi = 3.14159265358979312 +Most precise pi = 3.14159265358979323846264338327950 +Floating-point type boost::float16_t is NOT available. +Floating-point type boost::float32_t is available. + std::numeric_limits<boost::float32_t>::digits10 == 6 + std::numeric_limits<boost::float32_t>::max_digits10 == 9 +Floating-point type boost::float64_t is available. + std::numeric_limits<boost::float64_t>::digits10 == 15 + std::numeric_limits<boost::float64_t>::max_digits10 == 17 +Floating-point type boost::float80_t is available. + std::numeric_limits<boost::float80_t>::digits10 == 18 + std::numeric_limits<boost::float80_t>::max_digits10 == 21 +Floating-point type boost::float128_t is available. + std::numeric_limits<boost::float128_t>::digits10 == 33 + std::numeric_limits<boost::float128_t>::max_digits10 == 36 +BOOST_FLOAT32_C(123.4567890123456789012345678901234567890) = 123.456787 +BOOST_FLOAT64_C(123.4567890123456789012345678901234567890) = 123.45678901234568 +BOOST_FLOAT80_C(123.4567890123456789012345678901234567890) = 123.456789012345678903 +BOOST_FLOAT128_C(123.4567890123456789012345678901234567890) = 123.456789012345678901234567890123453 +floatmax_t 113 bits +33 decimal digits +36 max_digits +2 radix + +significand_bits (including one implicit bit)113, exponent_bits 15, sign_bits 1 +bits = 128 +double, double: true +boost::is_same<boost::floatmax_t, boost::float64_t>::value; false +floatmax_t, float64_t: false +128 bits. + + + MSVC 2013 64-bit + + 1> pi = 1.00000 + 1> 0.88010117148986700 + 1> 0.00 0.00000000000000000 + 1> 1.0 0.88010117148986700 + 1> 2.0 4.6137984620549854 + 1> 3.0 16.274830009244948 + 1> 4.0 -25.360637961042869 + 1> 5.0 -1257.9038883512258 + 1> 6.0 -12749.592182518225 + 1> 7.0 -3020.9830849309396 + 1> 8.0 2421897.6013183575 + 1> 9.0 45577595.449204892 + 1> 0.00 0.00000000000000000 + 1> 1.0 0.88010117148986700 + 1> 2.0 4.6137984620549854 + 1> 3.0 16.274830009244948 + 1> 4.0 -25.360637961042869 + 1> 5.0 -1257.9038883512258 + 1> 6.0 -12749.592182518225 + 1> 7.0 -3020.9830849309396 + 1> 8.0 2421897.6013183575 + 1> 9.0 45577595.449204892 + 1> Floating-point type long double is available with: + 1> std::numeric_limits<long double>::digits10 == 15 + 1> std::numeric_limits<long double>::max_digits10 == 17 + 1> pi = 3.14159265358979 + 1> Most precise pi = 3.14159265358979 + 1> Floating-point type boost::float16_t is NOT available. + 1> Floating-point type boost::float32_t is available. + 1> std::numeric_limits<boost::float32_t>::digits10 == 6 + 1> std::numeric_limits<boost::float32_t>::max_digits10 == 9 + 1> Floating-point type boost::float64_t is available. + 1> std::numeric_limits<boost::float64_t>::digits10 == 15 + 1> std::numeric_limits<boost::float64_t>::max_digits10 == 17 + 1> Floating-point type boost::float80_t is NOT available. + 1> Floating-point type boost::float128_t is NOT available. + 1> BOOST_FLOAT32_C(123.4567890123456789012345678901234567890) = 123.456787 + 1> BOOST_FLOAT64_C(123.4567890123456789012345678901234567890) = 123.45678901234568 + 1> floatmax_t 53 bits + 1> 15 decimal digits + 1> 17 max_digits + 1> 2 radix + 1> + 1> significand_bits (including one implicit bit)53, exponent_bits 11, sign_bits 1 + 1> bits = 64 + 1> double, double: true + 1> boost::is_same<boost::floatmax_t, boost::float64_t>::value; true + 1> floatmax_t, float64_t: true + 1> 64 bits. +] [/cstdfloat_output] + + +*/ + diff --git a/src/boost/libs/math/example/daubechies_wavelets/bench.cpp b/src/boost/libs/math/example/daubechies_wavelets/bench.cpp new file mode 100644 index 000000000..db2846130 --- /dev/null +++ b/src/boost/libs/math/example/daubechies_wavelets/bench.cpp @@ -0,0 +1,489 @@ +/* + * Copyright Nick Thompson, 2020 + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ + +#include <cmath> +#include <random> +#include <benchmark/benchmark.h> +#include <boost/random/uniform_real_distribution.hpp> +#include <boost/math/special_functions/daubechies_scaling.hpp> +#include <boost/math/interpolators/cubic_hermite.hpp> +#include <boost/math/interpolators/detail/quintic_hermite_detail.hpp> +#include <boost/math/interpolators/detail/septic_hermite_detail.hpp> + +double exponential(benchmark::IterationCount j) +{ + return std::pow(2, j); +} + + +template<typename Real, int p> +void DyadicGrid(benchmark::State & state) +{ + int j = state.range(0); + size_t s = 0; + for (auto _ : state) + { + auto v = boost::math::daubechies_scaling_dyadic_grid<Real, 4, 0>(j); + benchmark::DoNotOptimize(v[0]); + s = v.size(); + } + + state.counters["RAM"] = s*sizeof(Real); + state.SetComplexityN(state.range(0)); +} + +BENCHMARK_TEMPLATE(DyadicGrid, double, 4)->DenseRange(3, 22, 1)->Unit(benchmark::kMillisecond)->Complexity(exponential); +//BENCHMARK_TEMPLATE(DyadicGrid, double, 8)->DenseRange(3, 22, 1)->Unit(benchmark::kMillisecond)->Complexity(exponential); +//BENCHMARK_TEMPLATE(DyadicGrid, double, 11)->DenseRange(3,22,1)->Unit(benchmark::kMillisecond)->Complexity(exponential); + +uint64_t s[2] = { 0x41, 0x29837592 }; + +static inline uint64_t rotl(const uint64_t x, int k) { + return (x << k) | (x >> (64 - k)); +} + +uint64_t next(void) { + const uint64_t s0 = s[0]; + uint64_t s1 = s[1]; + const uint64_t result = s0 + s1; + + s1 ^= s0; + s[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b + s[1] = rotl(s1, 36); // c + + return result; +} + +double uniform() { + return next()*(1.0/18446744073709551616.0); +} + +template<typename Real, int p> +void ScalingEvaluation(benchmark::State & state) +{ + auto phi = boost::math::daubechies_scaling<Real, p>(); + Real xmax = phi.support().second; + Real x = 0; + Real step = uniform()/2048; + for (auto _ : state) + { + benchmark::DoNotOptimize(phi(x)); + x += step; + if (x > xmax) { + x = 0; + step = uniform()/2048; + } + } +} + + +BENCHMARK_TEMPLATE(ScalingEvaluation, double, 2); +BENCHMARK_TEMPLATE(ScalingEvaluation, double, 3); +BENCHMARK_TEMPLATE(ScalingEvaluation, double, 4); +BENCHMARK_TEMPLATE(ScalingEvaluation, double, 5); +BENCHMARK_TEMPLATE(ScalingEvaluation, double, 6); +BENCHMARK_TEMPLATE(ScalingEvaluation, double, 7); +BENCHMARK_TEMPLATE(ScalingEvaluation, double, 8); +BENCHMARK_TEMPLATE(ScalingEvaluation, double, 9); +BENCHMARK_TEMPLATE(ScalingEvaluation, double, 10); +BENCHMARK_TEMPLATE(ScalingEvaluation, double, 11); +BENCHMARK_TEMPLATE(ScalingEvaluation, double, 12); +BENCHMARK_TEMPLATE(ScalingEvaluation, double, 13); +BENCHMARK_TEMPLATE(ScalingEvaluation, double, 14); +BENCHMARK_TEMPLATE(ScalingEvaluation, double, 15); + + +template<typename Real, int p> +void ScalingConstructor(benchmark::State & state) +{ + for (auto _ : state) + { + benchmark::DoNotOptimize(boost::math::daubechies_scaling<Real, p>()); + } +} + +BENCHMARK_TEMPLATE(ScalingConstructor, float, 2)->Unit(benchmark::kMillisecond); +BENCHMARK_TEMPLATE(ScalingConstructor, double, 2)->Unit(benchmark::kMillisecond); +BENCHMARK_TEMPLATE(ScalingConstructor, long double, 2)->Unit(benchmark::kMillisecond); + +BENCHMARK_TEMPLATE(ScalingConstructor, float, 3)->Unit(benchmark::kMillisecond); +BENCHMARK_TEMPLATE(ScalingConstructor, double, 3)->Unit(benchmark::kMillisecond); +BENCHMARK_TEMPLATE(ScalingConstructor, long double, 3)->Unit(benchmark::kMillisecond); + +BENCHMARK_TEMPLATE(ScalingConstructor, float, 4)->Unit(benchmark::kMillisecond); +BENCHMARK_TEMPLATE(ScalingConstructor, double, 4)->Unit(benchmark::kMillisecond); +BENCHMARK_TEMPLATE(ScalingConstructor, long double, 4)->Unit(benchmark::kMillisecond); + +BENCHMARK_TEMPLATE(ScalingConstructor, float, 5)->Unit(benchmark::kMillisecond); +BENCHMARK_TEMPLATE(ScalingConstructor, double, 5)->Unit(benchmark::kMillisecond); +BENCHMARK_TEMPLATE(ScalingConstructor, long double, 5)->Unit(benchmark::kMillisecond); + +BENCHMARK_TEMPLATE(ScalingConstructor, float, 11)->Unit(benchmark::kMillisecond); +BENCHMARK_TEMPLATE(ScalingConstructor, double, 11)->Unit(benchmark::kMillisecond); +BENCHMARK_TEMPLATE(ScalingConstructor, long double, 11)->Unit(benchmark::kMillisecond); + +template<typename Real> +void CubicHermite(benchmark::State & state) +{ + using boost::math::interpolators::cubic_hermite; + auto n = state.range(0); + std::vector<Real> x(n); + std::vector<Real> y(n); + std::vector<Real> dydx(n); + std::random_device rd; + boost::random::uniform_real_distribution<Real> dis(Real(0), Real(1)); + x[0] = dis(rd); + y[0] = dis(rd); + dydx[0] = dis(rd); + for (size_t i = 1; i < y.size(); ++i) + { + x[i] = x[i-1] + dis(rd); + y[i] = dis(rd); + dydx[i] = dis(rd); + } + Real x0 = x.front(); + Real xf = x.back(); + + auto qh = cubic_hermite(std::move(x), std::move(y), std::move(dydx)); + Real t = x0; + Real step = uniform()*(xf-x0)/2048; + for (auto _ : state) + { + benchmark::DoNotOptimize(qh(t)); + t += step; + if (t >= xf) + { + t = x0; + step = uniform()*(xf-x0)/2048; + } + } + state.SetComplexityN(state.range(0)); +} + +BENCHMARK_TEMPLATE(CubicHermite, double)->RangeMultiplier(2)->Range(1<<8, 1<<20)->Complexity(benchmark::oLogN); + +template<typename Real> +void CardinalCubicHermite(benchmark::State & state) +{ + using boost::math::interpolators::detail::cardinal_cubic_hermite_detail; + auto n = state.range(0); + std::vector<Real> y(n); + std::vector<Real> dydx(n); + std::random_device rd; + boost::random::uniform_real_distribution<Real> dis(Real(0), Real(1)); + for (size_t i = 0; i < y.size(); ++i) + { + y[i] = uniform(); + dydx[i] = uniform(); + } + + Real dx = Real(1)/Real(8); + Real x0 = 0; + Real xf = x0 + (y.size()-1)*dx; + + auto qh = cardinal_cubic_hermite_detail(std::move(y), std::move(dydx), x0, dx); + Real x = x0; + Real step = uniform()*(xf-x0)/2048; + for (auto _ : state) + { + benchmark::DoNotOptimize(qh.unchecked_evaluation(x)); + x += step; + if (x >= xf) + { + x = x0; + step = uniform()*(xf-x0)/2048; + } + } + state.SetComplexityN(state.range(0)); +} + +template<typename Real> +void CardinalCubicHermiteAOS(benchmark::State & state) +{ + auto n = state.range(0); + std::vector<std::array<Real, 2>> dat(n); + std::random_device rd; + boost::random::uniform_real_distribution<Real> dis(Real(0), Real(1)); + for (size_t i = 0; i < dat.size(); ++i) + { + dat[i][0] = uniform(); + dat[i][1] = uniform(); + } + + using boost::math::interpolators::detail::cardinal_cubic_hermite_detail_aos; + Real dx = Real(1)/Real(8); + Real x0 = 0; + Real xf = x0 + (dat.size()-1)*dx; + auto qh = cardinal_cubic_hermite_detail_aos(std::move(dat), x0, dx); + Real x = 0; + Real step = uniform()*(xf-x0)/2048; + for (auto _ : state) + { + benchmark::DoNotOptimize(qh.unchecked_evaluation(x)); + x += step; + if (x >= xf) + { + x = x0; + step = uniform()*(xf-x0)/2048; + } + } + state.SetComplexityN(state.range(0)); +} + +BENCHMARK_TEMPLATE(CardinalCubicHermiteAOS, double)->RangeMultiplier(2)->Range(1<<8, 1<<21)->Complexity(benchmark::o1); +BENCHMARK_TEMPLATE(CardinalCubicHermite, double)->RangeMultiplier(2)->Range(1<<8, 1<<21)->Complexity(benchmark::o1); + +template<class Real> +void SineEvaluation(benchmark::State& state) +{ + std::default_random_engine gen; + std::uniform_real_distribution<Real> x_dis(0, 3.14159); + + Real x = x_dis(gen); + for (auto _ : state) + { + benchmark::DoNotOptimize(std::sin(x)); + x += std::numeric_limits<Real>::epsilon(); + } +} + +BENCHMARK_TEMPLATE(SineEvaluation, float); +BENCHMARK_TEMPLATE(SineEvaluation, double); +BENCHMARK_TEMPLATE(SineEvaluation, long double); + +template<class Real> +void ExpEvaluation(benchmark::State& state) +{ + std::default_random_engine gen; + std::uniform_real_distribution<Real> x_dis(0, 3.14159); + + Real x = x_dis(gen); + for (auto _ : state) + { + benchmark::DoNotOptimize(std::exp(x)); + x += std::numeric_limits<Real>::epsilon(); + } +} + +BENCHMARK_TEMPLATE(ExpEvaluation, float); +BENCHMARK_TEMPLATE(ExpEvaluation, double); +BENCHMARK_TEMPLATE(ExpEvaluation, long double); + +template<class Real> +void PowEvaluation(benchmark::State& state) +{ + std::default_random_engine gen; + std::uniform_real_distribution<Real> x_dis(0, 3.14159); + + Real x = x_dis(gen); + for (auto _ : state) + { + benchmark::DoNotOptimize(std::pow(x, x+1)); + x += std::numeric_limits<Real>::epsilon(); + } +} + +BENCHMARK_TEMPLATE(PowEvaluation, float); +BENCHMARK_TEMPLATE(PowEvaluation, double); +BENCHMARK_TEMPLATE(PowEvaluation, long double); + + +template<typename Real> +void CardinalQuinticHermite(benchmark::State & state) +{ + using boost::math::interpolators::detail::cardinal_quintic_hermite_detail; + auto n = state.range(0); + std::vector<Real> y(n); + std::vector<Real> dydx(n); + std::vector<Real> d2ydx2(n); + std::random_device rd; + boost::random::uniform_real_distribution<Real> dis(Real(0), Real(1)); + for (size_t i = 0; i < y.size(); ++i) + { + y[i] = uniform(); + dydx[i] = uniform(); + d2ydx2[i] = uniform(); + } + + Real dx = Real(1)/Real(8); + Real x0 = 0; + Real xf = x0 + (y.size()-1)*dx; + + auto qh = cardinal_quintic_hermite_detail(std::move(y), std::move(dydx), std::move(d2ydx2), x0, dx); + Real x = 0; + Real step = uniform()*(xf-x0)/2048; + for (auto _ : state) + { + benchmark::DoNotOptimize(qh.unchecked_evaluation(x)); + x += step; + if (x >= xf) + { + x = x0; + step = uniform()*(xf-x0)/2048; + } + } + state.SetComplexityN(state.range(0)); +} + +template<typename Real> +void CardinalQuinticHermiteAOS(benchmark::State & state) +{ + auto n = state.range(0); + std::vector<std::array<Real, 3>> dat(n); + std::random_device rd; + boost::random::uniform_real_distribution<Real> dis(Real(0), Real(1)); + for (size_t i = 0; i < dat.size(); ++i) + { + dat[i][0] = uniform(); + dat[i][1] = uniform(); + dat[i][2] = uniform(); + } + + using boost::math::interpolators::detail::cardinal_quintic_hermite_detail_aos; + Real dx = Real(1)/Real(8); + Real x0 = 0; + Real xf = x0 + (dat.size()-1)*dx; + auto qh = cardinal_quintic_hermite_detail_aos(std::move(dat), x0, dx); + Real x = x0; + Real step = uniform()*(xf-x0)/2048; + for (auto _ : state) { + benchmark::DoNotOptimize(qh.unchecked_evaluation(x)); + x += step; + if (x >= xf) + { + x = x0; + step = uniform()*(xf-x0)/2048; + } + } + state.SetComplexityN(state.range(0)); +} + +BENCHMARK_TEMPLATE(CardinalQuinticHermiteAOS, double)->RangeMultiplier(2)->Range(1<<8, 1<<22)->Complexity(benchmark::o1); +BENCHMARK_TEMPLATE(CardinalQuinticHermite, double)->RangeMultiplier(2)->Range(1<<8, 1<<22)->Complexity(benchmark::o1); + +template<typename Real> +void SepticHermite(benchmark::State & state) +{ + using boost::math::interpolators::detail::septic_hermite_detail; + auto n = state.range(0); + std::vector<Real> x(n); + std::vector<Real> y(n); + std::vector<Real> dydx(n); + std::vector<Real> d2ydx2(n); + std::vector<Real> d3ydx3(n); + std::random_device rd; + boost::random::uniform_real_distribution<Real> dis(Real(0), Real(1)); + Real x0 = dis(rd); + x[0] = x0; + for (size_t i = 1; i < n; ++i) + { + x[i] = x[i-1] + dis(rd); + } + for (size_t i = 0; i < y.size(); ++i) + { + y[i] = dis(rd); + dydx[i] = dis(rd); + d2ydx2[i] = dis(rd); + d3ydx3[i] = dis(rd); + } + + Real xf = x.back(); + + auto sh = septic_hermite_detail(std::move(x), std::move(y), std::move(dydx), std::move(d2ydx2), std::move(d3ydx3)); + Real t = x0; + for (auto _ : state) + { + benchmark::DoNotOptimize(sh(t)); + t += xf/128; + if (t >= xf) + { + t = x0; + } + } + state.SetComplexityN(state.range(0)); +} + +BENCHMARK_TEMPLATE(SepticHermite, double)->RangeMultiplier(2)->Range(1<<8, 1<<20)->Complexity(); + + +template<typename Real> +void CardinalSepticHermite(benchmark::State & state) +{ + using boost::math::interpolators::detail::cardinal_septic_hermite_detail; + auto n = state.range(0); + std::vector<Real> y(n); + std::vector<Real> dydx(n); + std::vector<Real> d2ydx2(n); + std::vector<Real> d3ydx3(n); + std::random_device rd; + boost::random::uniform_real_distribution<Real> dis(Real(0), Real(1)); + for (size_t i = 0; i < y.size(); ++i) + { + y[i] = dis(rd); + dydx[i] = dis(rd); + d2ydx2[i] = dis(rd); + d3ydx3[i] = dis(rd); + } + + Real dx = Real(1)/Real(8); + Real x0 = 0; + Real xf = x0 + (y.size()-1)*dx; + + auto sh = cardinal_septic_hermite_detail(std::move(y), std::move(dydx), std::move(d2ydx2), std::move(d3ydx3), x0, dx); + Real x = 0; + for (auto _ : state) + { + benchmark::DoNotOptimize(sh.unchecked_evaluation(x)); + x += xf/128; + if (x >= xf) + { + x = x0; + } + } + state.SetComplexityN(state.range(0)); +} + +BENCHMARK_TEMPLATE(CardinalSepticHermite, double)->RangeMultiplier(2)->Range(1<<8, 1<<20)->Complexity(); + +template<typename Real> +void CardinalSepticHermiteAOS(benchmark::State & state) +{ + using boost::math::interpolators::detail::cardinal_septic_hermite_detail_aos; + auto n = state.range(0); + std::vector<std::array<Real, 4>> data(n); + std::random_device rd; + boost::random::uniform_real_distribution<Real> dis(Real(0), Real(1)); + for (size_t i = 0; i < data.size(); ++i) + { + for (size_t j = 0; j < 4; ++j) + { + data[i][j] = dis(rd); + } + } + + Real dx = Real(1)/Real(8); + Real x0 = 0; + Real xf = x0 + (data.size()-1)*dx; + + auto sh = cardinal_septic_hermite_detail_aos(std::move(data), x0, dx); + Real x = 0; + for (auto _ : state) + { + benchmark::DoNotOptimize(sh.unchecked_evaluation(x)); + x += xf/128; + if (x >= xf) + { + x = x0; + } + } + state.SetComplexityN(state.range(0)); +} + +BENCHMARK_TEMPLATE(CardinalSepticHermiteAOS, double)->RangeMultiplier(2)->Range(1<<8, 1<<20)->Complexity(); + + +BENCHMARK_MAIN(); diff --git a/src/boost/libs/math/example/daubechies_wavelets/bootstrap_chebyshev.cpp b/src/boost/libs/math/example/daubechies_wavelets/bootstrap_chebyshev.cpp new file mode 100644 index 000000000..b158fabcd --- /dev/null +++ b/src/boost/libs/math/example/daubechies_wavelets/bootstrap_chebyshev.cpp @@ -0,0 +1,18 @@ +#include <iostream> +#include <boost/math/special_functions/daubechies_scaling.hpp> +#include <boost/math/special_functions/chebyshev_transform.hpp> + +template<typename Real, int p> +void bootstrap() +{ + std::cout << "Computing phi. . .\n"; + auto phi = boost::math::daubechies_scaling<Real, p>(); + std::cout << "Computing Chebyshev transform of phi.\n"; + auto cheb = boost::math::chebyshev_transform(phi, phi.support().first, phi.support().second); + std::cout << "Number of coefficients = " << cheb.coefficients().size() << "\n"; +} + +int main() +{ + bootstrap<long double, 9>(); +}
\ No newline at end of file diff --git a/src/boost/libs/math/example/daubechies_wavelets/daubechies_coefficients.cpp b/src/boost/libs/math/example/daubechies_wavelets/daubechies_coefficients.cpp new file mode 100644 index 000000000..1366e921c --- /dev/null +++ b/src/boost/libs/math/example/daubechies_wavelets/daubechies_coefficients.cpp @@ -0,0 +1,267 @@ +/* + * Copyright Nick Thompson, 2018 + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#include <iostream> +#include <fstream> +#include <vector> +#include <string> +#include <complex> +#include <bitset> +#include <boost/assert.hpp> +#include <boost/multiprecision/cpp_bin_float.hpp> +#include <boost/math/constants/constants.hpp> +#include <boost/math/tools/polynomial.hpp> +#include <boost/math/tools/roots.hpp> +#include <boost/math/special_functions/binomial.hpp> +#include <boost/multiprecision/cpp_complex.hpp> +#ifdef BOOST_HAS_FLOAT128 +#include <boost/multiprecision/float128.hpp> + +typedef boost::multiprecision::float128 float128_t; +#else +typedef boost::multiprecision::cpp_bin_float_quad float128_t; +#endif +//#include <boost/multiprecision/complex128.hpp> +#include <boost/math/quadrature/gauss_kronrod.hpp> + +using std::string; +using boost::math::tools::polynomial; +using boost::math::binomial_coefficient; +using boost::math::tools::schroder_iterate; +using boost::math::tools::halley_iterate; +using boost::math::tools::newton_raphson_iterate; +using boost::math::tools::complex_newton; +using boost::math::constants::half; +using boost::math::constants::root_two; +using boost::math::constants::pi; +using boost::math::quadrature::gauss_kronrod; +using boost::multiprecision::cpp_bin_float_100; +using boost::multiprecision::cpp_complex_100; + +template<class Complex> +std::vector<std::pair<Complex, Complex>> find_roots(size_t p) +{ + // Initialize the polynomial; see Mallat, A Wavelet Tour of Signal Processing, equation 7.96 + BOOST_ASSERT(p>0); + typedef typename Complex::value_type Real; + std::vector<Complex> coeffs(p); + for (size_t k = 0; k < coeffs.size(); ++k) + { + coeffs[k] = Complex(binomial_coefficient<Real>(p-1+k, k), 0); + } + + polynomial<Complex> P(std::move(coeffs)); + polynomial<Complex> Pcopy = P; + polynomial<Complex> Pcopy_prime = P.prime(); + auto orig = [&](Complex z) { return std::make_pair<Complex, Complex>(Pcopy(z), Pcopy_prime(z)); }; + + polynomial<Complex> P_prime = P.prime(); + + // Polynomial is of degree p-1. + + std::vector<Complex> roots(p-1, {std::numeric_limits<Real>::quiet_NaN(),std::numeric_limits<Real>::quiet_NaN()}); + size_t i = 0; + while(P.size() > 1) + { + Complex guess = {0.0, 1.0}; + std::cout << std::setprecision(std::numeric_limits<Real>::digits10+3); + + auto f = [&](Complex x)->std::pair<Complex, Complex> + { + return std::make_pair<Complex, Complex>(P(x), P_prime(x)); + }; + + Complex r = complex_newton(f, guess); + using std::isnan; + if(isnan(r.real())) + { + int i = 50; + do { + // Try a different guess + guess *= Complex(1.0,-1.0); + r = complex_newton(f, guess); + std::cout << "New guess: " << guess << ", result? " << r << std::endl; + + } while (isnan(r.real()) && i-- > 0); + + if (isnan(r.real())) + { + std::cout << "Polynomial that killed the process: " << P << std::endl; + throw std::logic_error("Newton iteration did not converge"); + } + } + // Refine r with the original function. + // We only use the polynomial division to ensure we don't get the same root over and over. + // However, the division induces error which can grow quickly-or slowly! See Numerical Recipes, section 9.5.1. + r = complex_newton(orig, r); + if (isnan(r.real())) + { + throw std::logic_error("Found a root for the deflated polynomial which is not a root for the original. Indicative of catastrophic numerical error."); + } + // Test the root: + using std::sqrt; + Real tol = sqrt(sqrt(std::numeric_limits<Real>::epsilon())); + if (norm(Pcopy(r)) > tol) + { + std::cout << "This is a bad root: P" << r << " = " << Pcopy(r) << std::endl; + std::cout << "Reduced polynomial leading to bad root: " << P << std::endl; + throw std::logic_error("Donezo."); + } + + BOOST_ASSERT(i < roots.size()); + roots[i] = r; + ++i; + polynomial<Complex> q{-r, {1,0}}; + // This optimization breaks at p = 11. I have no clue why. + // Unfortunate, because I expect it to be considerably more stable than + // repeatedly dividing by the complex root. + /*polynomial<Complex> q; + if (r.imag() > sqrt(std::numeric_limits<Real>::epsilon())) + { + // Then the complex conjugate is also a root: + using std::conj; + using std::norm; + BOOST_ASSERT(i < roots.size()); + roots[i] = conj(r); + ++i; + q = polynomial<Complex>({{norm(r), 0}, {-2*r.real(),0}, {1,0}}); + } + else + { + // The imaginary part is numerical noise: + r.imag() = 0; + q = polynomial<Complex>({-r, {1,0}}); + }*/ + + + auto PR = quotient_remainder(P, q); + // I should validate that the remainder is small, but . . . + //std::cout << "Remainder = " << PR.second<< std::endl; + + P = PR.first; + P_prime = P.prime(); + } + + std::vector<std::pair<Complex, Complex>> Qroots(p-1); + for (size_t i = 0; i < Qroots.size(); ++i) + { + Complex y = roots[i]; + Complex z1 = static_cast<Complex>(1) - static_cast<Complex>(2)*y + static_cast<Complex>(2)*sqrt(y*(y-static_cast<Complex>(1))); + Complex z2 = static_cast<Complex>(1) - static_cast<Complex>(2)*y - static_cast<Complex>(2)*sqrt(y*(y-static_cast<Complex>(1))); + Qroots[i] = {z1, z2}; + } + + return Qroots; +} + +template<class Complex> +std::vector<typename Complex::value_type> daubechies_coefficients(std::vector<std::pair<Complex, Complex>> const & Qroots) +{ + typedef typename Complex::value_type Real; + size_t p = Qroots.size() + 1; + // Choose the minimum abs root; see Mallat, discussion just after equation 7.98 + std::vector<Complex> chosen_roots(p-1); + for (size_t i = 0; i < p - 1; ++i) + { + if(norm(Qroots[i].first) <= 1) + { + chosen_roots[i] = Qroots[i].first; + } + else + { + BOOST_ASSERT(norm(Qroots[i].second) <= 1); + chosen_roots[i] = Qroots[i].second; + } + } + + polynomial<Complex> R{1}; + for (size_t i = 0; i < p-1; ++i) + { + Complex ak = chosen_roots[i]; + R *= polynomial<Complex>({-ak/(static_cast<Complex>(1)-ak), static_cast<Complex>(1)/(static_cast<Complex>(1)-ak)}); + } + polynomial<Complex> a{{half<Real>(), 0}, {half<Real>(),0}}; + polynomial<Complex> poly = root_two<Real>()*pow(a, p)*R; + std::vector<Complex> result = poly.data(); + // If we reverse, we get the Numerical Recipes and Daubechies convention. + // If we don't reverse, we get the Pywavelets and Mallat convention. + // I believe this is because of the sign convention on the DFT, which differs between Daubechies and Mallat. + // You implement a dot product in Daubechies/NR convention, and a convolution in PyWavelets/Mallat convention. + std::reverse(result.begin(), result.end()); + std::vector<Real> h(result.size()); + for (size_t i = 0; i < result.size(); ++i) + { + Complex r = result[i]; + BOOST_ASSERT(r.imag() < sqrt(std::numeric_limits<Real>::epsilon())); + h[i] = r.real(); + } + + // Quick sanity check: We could check all vanishing moments, but that sum is horribly ill-conditioned too! + Real sum = 0; + Real scale = 0; + for (size_t i = 0; i < h.size(); ++i) + { + sum += h[i]; + scale += h[i]*h[i]; + } + BOOST_ASSERT(abs(scale -1) < sqrt(std::numeric_limits<Real>::epsilon())); + BOOST_ASSERT(abs(sum - root_two<Real>()) < sqrt(std::numeric_limits<Real>::epsilon())); + return h; +} + +int main() +{ + typedef boost::multiprecision::cpp_complex<500> Complex; + size_t p_max = 20; + std::ofstream fs{"daubechies_filters.hpp"}; + fs << "/*\n" + << " * Copyright Nick Thompson, 2019\n" + << " * Use, modification and distribution are subject to the\n" + << " * Boost Software License, Version 1.0. (See accompanying file\n" + << " * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n" + << " */\n" + << "#ifndef BOOST_MATH_FILTERS_DAUBECHIES_HPP\n" + << "#define BOOST_MATH_FILTERS_DAUBECHIES_HPP\n" + << "#include <array>\n" + << "#include <limits>\n" + << "#include <boost/math/tools/big_constant.hpp>\n\n" + << "namespace boost::math::filters {\n\n" + << "template <typename Real, unsigned p>\n" + << "constexpr std::array<Real, 2*p> daubechies_scaling_filter()\n" + << "{\n" + << " static_assert(p < " << p_max << ", \"Filter coefficients only implemented up to " << p_max - 1 << ".\");\n"; + + for(size_t p = 1; p < p_max; ++p) + { + fs << std::setprecision(std::numeric_limits<boost::multiprecision::cpp_bin_float_oct>::max_digits10); + auto roots = find_roots<Complex>(p); + auto h = daubechies_coefficients(roots); + fs << " if constexpr (p == " << p << ") {\n"; + fs << " return {"; + for (size_t i = 0; i < h.size() - 1; ++i) { + fs << "BOOST_MATH_BIG_CONSTANT(Real, std::numeric_limits<Real>::digits, " << h[i] << "), "; + } + fs << "BOOST_MATH_BIG_CONSTANT(Real, std::numeric_limits<Real>::digits, " << h[h.size()-1] << ") };\n"; + fs << " }\n"; + } + + fs << "}\n\n"; + + fs << "template<class Real, size_t p>\n"; + fs << "std::array<Real, 2*p> daubechies_wavelet_filter() {\n"; + fs << " std::array<Real, 2*p> g;\n"; + fs << " auto h = daubechies_scaling_filter<Real, p>();\n"; + fs << " for (size_t i = 0; i < g.size(); i += 2)\n"; + fs << " {\n"; + fs << " g[i] = h[g.size() - i - 1];\n"; + fs << " g[i+1] = -h[g.size() - i - 2];\n"; + fs << " }\n"; + fs << " return g;\n"; + fs << "}\n\n"; + fs << "} // namespaces\n"; + fs << "#endif\n"; + fs.close(); +} diff --git a/src/boost/libs/math/example/daubechies_wavelets/daubechies_plots.cpp b/src/boost/libs/math/example/daubechies_wavelets/daubechies_plots.cpp new file mode 100644 index 000000000..70172c98e --- /dev/null +++ b/src/boost/libs/math/example/daubechies_wavelets/daubechies_plots.cpp @@ -0,0 +1,165 @@ +/* + * Copyright Nick Thompson, 2020 + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#include <iostream> +#include <boost/core/demangle.hpp> +#include <boost/hana/for_each.hpp> +#include <boost/hana/ext/std/integer_sequence.hpp> + +#include <boost/multiprecision/float128.hpp> +#include <boost/math/special_functions/daubechies_scaling.hpp> +#include <quicksvg/graph_fn.hpp> +#include <quicksvg/ulp_plot.hpp> + + +using boost::multiprecision::float128; +constexpr const int GRAPH_WIDTH = 700; + +template<typename Real, int p> +void plot_phi(int grid_refinements = -1) +{ + auto phi = boost::math::daubechies_scaling<Real, p>(); + if (grid_refinements >= 0) + { + phi = boost::math::daubechies_scaling<Real, p>(grid_refinements); + } + Real a = 0; + Real b = phi.support().second; + std::string title = "Daubechies " + std::to_string(p) + " scaling function"; + title = ""; + std::string filename = "daubechies_" + std::to_string(p) + "_scaling.svg"; + int samples = 1024; + quicksvg::graph_fn daub(a, b, title, filename, samples, GRAPH_WIDTH); + daub.set_gridlines(8, 2*p-1); + daub.set_stroke_width(1); + daub.add_fn(phi); + daub.write_all(); +} + +template<typename Real, int p> +void plot_dphi(int grid_refinements = -1) +{ + auto phi = boost::math::daubechies_scaling<Real, p>(); + if (grid_refinements >= 0) + { + phi = boost::math::daubechies_scaling<Real, p>(grid_refinements); + } + Real a = 0; + Real b = phi.support().second; + std::string title = "Daubechies " + std::to_string(p) + " scaling function derivative"; + title = ""; + std::string filename = "daubechies_" + std::to_string(p) + "_scaling_prime.svg"; + int samples = 1024; + quicksvg::graph_fn daub(a, b, title, filename, samples, GRAPH_WIDTH); + daub.set_stroke_width(1); + daub.set_gridlines(8, 2*p-1); + auto dphi = [phi](Real x)->Real { return phi.prime(x); }; + daub.add_fn(dphi); + daub.write_all(); +} + +template<typename Real, int p> +void plot_convergence() +{ + auto phi0 = boost::math::daubechies_scaling<Real, p>(0); + Real a = 0; + Real b = phi0.support().second; + std::string title = "Daubechies " + std::to_string(p) + " scaling at 0 (green), 1 (orange), 2 (red), and 24 (blue) grid refinements"; + title = ""; + std::string filename = "daubechies_" + std::to_string(p) + "_scaling_convergence.svg"; + + quicksvg::graph_fn daub(a, b, title, filename, 1024, GRAPH_WIDTH); + daub.set_stroke_width(1); + daub.set_gridlines(8, 2*p-1); + + daub.add_fn(phi0, "green"); + auto phi1 = boost::math::daubechies_scaling<Real, p>(1); + daub.add_fn(phi1, "orange"); + auto phi2 = boost::math::daubechies_scaling<Real, p>(2); + daub.add_fn(phi2, "red"); + + auto phi21 = boost::math::daubechies_scaling<Real, p>(21); + daub.add_fn(phi21); + + daub.write_all(); +} + +template<typename Real, int p> +void plot_condition_number() +{ + using std::abs; + using std::log; + static_assert(p >= 3, "p = 2 is not differentiable, so condition numbers cannot be effectively evaluated."); + auto phi = boost::math::daubechies_scaling<Real, p>(); + Real a = std::sqrt(std::numeric_limits<Real>::epsilon()); + Real b = phi.support().second - 1000*std::sqrt(std::numeric_limits<Real>::epsilon()); + std::string title = "log10 of condition number of function evaluation for Daubechies " + std::to_string(p) + " scaling function."; + title = ""; + std::string filename = "daubechies_" + std::to_string(p) + "_scaling_condition_number.svg"; + + + quicksvg::graph_fn daub(a, b, title, filename, 2048, GRAPH_WIDTH); + daub.set_stroke_width(1); + daub.set_gridlines(8, 2*p-1); + + auto cond = [&phi](Real x) + { + Real y = phi(x); + Real dydx = phi.prime(x); + Real z = abs(x*dydx/y); + using std::isnan; + if (z==0) + { + return Real(-1); + } + if (isnan(z)) + { + // Graphing libraries don't like nan's: + return Real(1); + } + return log10(z); + }; + daub.add_fn(cond); + daub.write_all(); +} + +template<typename CoarseReal, typename PreciseReal, int p, class PhiPrecise> +void do_ulp(int coarse_refinements, PhiPrecise phi_precise) +{ + auto phi_coarse = boost::math::daubechies_scaling<CoarseReal, p>(coarse_refinements); + + std::string title = std::to_string(p) + " vanishing moment ULP plot at " + std::to_string(coarse_refinements) + " refinements and " + boost::core::demangle(typeid(CoarseReal).name()) + " precision"; + title = ""; + + std::string filename = "daubechies_" + std::to_string(p) + "_" + boost::core::demangle(typeid(CoarseReal).name()) + "_" + std::to_string(coarse_refinements) + "_refinements.svg"; + int samples = 20000; + int clip = 20; + int horizontal_lines = 8; + int vertical_lines = 2*p - 1; + quicksvg::ulp_plot<decltype(phi_coarse), CoarseReal, decltype(phi_precise), PreciseReal>(phi_coarse, phi_precise, CoarseReal(0), phi_coarse.support().second, title, filename, samples, GRAPH_WIDTH, clip, horizontal_lines, vertical_lines); +} + + +int main() +{ + boost::hana::for_each(std::make_index_sequence<18>(), [&](auto i){ plot_phi<double, i+2>(); }); + boost::hana::for_each(std::make_index_sequence<17>(), [&](auto i){ plot_dphi<double, i+3>(); }); + boost::hana::for_each(std::make_index_sequence<17>(), [&](auto i){ plot_condition_number<double, i+3>(); }); + boost::hana::for_each(std::make_index_sequence<18>(), [&](auto i){ plot_convergence<double, i+2>(); }); + + using PreciseReal = float128; + using CoarseReal = double; + int precise_refinements = 22; + constexpr const int p = 8; + std::cout << "Computing precise scaling function in " << boost::core::demangle(typeid(PreciseReal).name()) << " precision.\n"; + auto phi_precise = boost::math::daubechies_scaling<PreciseReal, p>(precise_refinements); + std::cout << "Beginning comparison with functions computed in " << boost::core::demangle(typeid(CoarseReal).name()) << " precision.\n"; + for (int i = 7; i <= precise_refinements-1; ++i) + { + std::cout << "\tCoarse refinement " << i << "\n"; + do_ulp<CoarseReal, PreciseReal, p>(i, phi_precise); + } +} diff --git a/src/boost/libs/math/example/daubechies_wavelets/daubechies_scaling_integer_grid.cpp b/src/boost/libs/math/example/daubechies_wavelets/daubechies_scaling_integer_grid.cpp new file mode 100644 index 000000000..c06bad5f1 --- /dev/null +++ b/src/boost/libs/math/example/daubechies_wavelets/daubechies_scaling_integer_grid.cpp @@ -0,0 +1,213 @@ +/* + * Copyright Nick Thompson, John Maddock 2020 + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ + +#define BOOST_MATH_GENERATE_DAUBECHIES_GRID + +#include <iostream> +#include <vector> +#include <numeric> +#include <list> +#include <cmath> +#include <cassert> +#include <fstream> +#include <Eigen/Eigenvalues> +#include <boost/hana/for_each.hpp> +#include <boost/hana/ext/std/integer_sequence.hpp> +#include <boost/core/demangle.hpp> +#ifdef BOOST_HAS_FLOAT128 +#include <boost/multiprecision/float128.hpp> +#endif +#include <boost/math/constants/constants.hpp> +#include <boost/math/filters/daubechies.hpp> +#include <boost/math/special_functions/factorials.hpp> +#include <boost/multiprecision/cpp_bin_float.hpp> + +typedef boost::multiprecision::number<boost::multiprecision::cpp_bin_float<237, boost::multiprecision::backends::digit_base_2, std::allocator<char>, boost::int32_t, -262142, 262143>, boost::multiprecision::et_off> octuple_type; + +#ifdef BOOST_HAS_FLOAT128 +typedef boost::multiprecision::float128 float128_t; +#else +typedef boost::multiprecision::cpp_bin_float_quad float128_t; +#endif + +template<class Real, int p> +std::list<std::vector<Real>> integer_grid() +{ + std::cout << std::setprecision(std::numeric_limits<Real>::digits10 + 3); + using std::abs; + using std::sqrt; + using std::pow; + std::list<std::vector<Real>> grids; + + auto c = boost::math::filters::daubechies_scaling_filter<Real, p>(); + for (auto & x : c) + { + x *= boost::math::constants::root_two<Real>(); + } + std::cout << "\n\nTaps in filter = " << c.size() << "\n"; + + + Eigen::Matrix<Real, 2*p - 2, 2*p-2> A; + for (int j = 0; j < 2*p-2; ++j) { + for (int k = 0; k < 2*p-2; ++k) { + if ( (2*j-k + 1) < 0 || (2*j - k + 1) >= 2*p) + { + A(j,k) = 0; + } + else { + A(j,k) = c[2*j - k + 1]; + } + } + } + + Eigen::EigenSolver<decltype(A)> es(A); + + auto complex_eigs = es.eigenvalues(); + + std::vector<Real> eigs(complex_eigs.size(), std::numeric_limits<Real>::quiet_NaN()); + + std::cout << "Eigenvalues = {"; + for (long i = 0; i < complex_eigs.size(); ++i) { + assert(abs(complex_eigs[i].imag()) < std::numeric_limits<Real>::epsilon()); + eigs[i] = complex_eigs[i].real(); + std::cout << eigs[i] << ", "; + } + std::cout << "}\n"; + + // Eigen does not sort the eigenpairs by any criteria on the eigenvalues. + // In any case, even if it did, some of the eigenpairs do not correspond to derivatives anyway. + for (size_t j = 0; j < eigs.size(); ++j) { + auto f = [&](Real x) { + return abs(x - Real(1)/Real(1 << j) ) < sqrt(std::numeric_limits<Real>::epsilon()); + }; + auto it = std::find_if(eigs.begin(), eigs.end(), f); + if (it == eigs.end()) { + std::cout << "couldn't find eigenvalue " << Real(1)/Real(1 << j) << "\n"; + continue; + } + size_t idx = std::distance(eigs.begin(), it); + std::cout << "Eigenvector for derivative " << j << " is at index " << idx << "\n"; + auto eigenvector_matrix = es.eigenvectors(); + auto complex_eigenvec = eigenvector_matrix.col(idx); + + std::vector<Real> eigenvec(complex_eigenvec.size() + 2, std::numeric_limits<Real>::quiet_NaN()); + eigenvec[0] = 0; + eigenvec[eigenvec.size()-1] = 0; + for (size_t i = 0; i < eigenvec.size() - 2; ++i) { + assert(abs(complex_eigenvec[i].imag()) < std::numeric_limits<Real>::epsilon()); + eigenvec[i+1] = complex_eigenvec[i].real(); + } + + Real sum = 0; + for(size_t k = 1; k < eigenvec.size(); ++k) { + sum += pow(k, j)*eigenvec[k]; + } + + Real alpha = pow(-1, j)*boost::math::factorial<Real>(j)/sum; + + for (size_t i = 1; i < eigenvec.size(); ++i) { + eigenvec[i] *= alpha; + } + + + std::cout << "Eigenvector = {"; + for (size_t i = 0; i < eigenvec.size() -1; ++i) { + std::cout << eigenvec[i] << ", "; + } + std::cout << eigenvec[eigenvec.size()-1] << "}\n"; + + sum = 0; + for(size_t k = 1; k < eigenvec.size(); ++k) { + sum += pow(k, j)*eigenvec[k]; + } + + std::cout << "Moment sum = " << sum << ", expected = " << pow(-1, j)*boost::math::factorial<Real>(j) << "\n"; + + assert(abs(sum - pow(-1, j)*boost::math::factorial<Real>(j))/abs(pow(-1, j)*boost::math::factorial<Real>(j)) < sqrt(std::numeric_limits<Real>::epsilon())); + + grids.push_back(eigenvec); + } + + + return grids; +} + +template<class Real, int p> +void write_grid(std::ofstream & fs) +{ + auto grids = integer_grid<Real, p>(); + size_t j = 0; + fs << std::setprecision(std::numeric_limits< boost::multiprecision::cpp_bin_float_quad>::max_digits10); + for (auto it = grids.begin(); it != grids.end(); ++it) + { + auto const& grid = *it; + fs << "template <typename Real> struct daubechies_scaling_integer_grid_imp <Real, " << p << ", "; + fs << j << "> { static inline constexpr std::array<Real, " << grid.size() << "> value = { "; + for (size_t i = 0; i < grid.size() -1; ++i){ + fs << "C_(" << static_cast<float128_t>(grid[i]) << "), "; + } + fs << "C_(" << static_cast<float128_t>(grid[grid.size()-1]) << ") }; };\n"; + ++j; + } +} + +int main() +{ + constexpr const size_t p_max = 18; + std::ofstream fs{"daubechies_scaling_integer_grid.hpp"}; + fs << "/*\n" + << " * Copyright Nick Thompson, John Maddock 2020\n" + << " * Use, modification and distribution are subject to the\n" + << " * Boost Software License, Version 1.0. (See accompanying file\n" + << " * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n" + << " */\n" + << "// THIS FILE GENERATED BY EXAMPLE/DAUBECHIES_SCALING_INTEGER_GRID.CPP, DO NOT EDIT.\n" + << "#ifndef BOOST_MATH_DAUBECHIES_SCALING_INTEGER_GRID_HPP\n" + << "#define BOOST_MATH_DAUBECHIES_SCALING_INTEGER_GRID_HPP\n" + << "#include <array>\n" + << "#include <float.h>\n" + << "#include <boost/config.hpp>\n" + << "/*\n" + << "In order to keep the character count as small as possible and speed up\n" + << "compiler parsing times, we define a macro C_ which appends an appropriate\n" + << "suffix to each literal, and then casts it to type Real.\n" + << "The suffix is as follows:\n\n" + << "* Q, when we have __float128 support.\n" + << "* L, when we have either 80 or 128 bit long doubles.\n" + << "* Nothing otherwise.\n" + << "*/\n\n" + << "#ifdef BOOST_HAS_FLOAT128\n" + << "# define C_(x) static_cast<Real>(x##Q)\n" + << "#elif (LDBL_MANT_DIG > DBL_MANT_DIG)\n" + << "# define C_(x) static_cast<Real>(x##L)\n" + << "#else\n" + << "# define C_(x) static_cast<Real>(x)\n" + << "#endif\n\n" + << "namespace boost::math::detail {\n\n" + << "template <typename Real, int p, int order> struct daubechies_scaling_integer_grid_imp;\n\n"; + + fs << std::hexfloat << std::setprecision(std::numeric_limits<boost::multiprecision::cpp_bin_float_quad>::max_digits10); + + boost::hana::for_each(std::make_index_sequence<p_max>(), [&](auto idx){ + write_grid<octuple_type, idx+2>(fs); + }); + + fs << "\n\ntemplate <typename Real, unsigned p, unsigned order>\n" + << "constexpr inline std::array<Real, 2*p> daubechies_scaling_integer_grid()\n" + << "{\n" + << " static_assert(sizeof(Real) <= 16, \"Integer grids only computed up to 128 bits of precision.\");\n" + << " static_assert(p <= " << p_max + 1 << ", \"Integer grids only implemented up to " << p_max + 1 << ".\");\n" + << " static_assert(p > 1, \"Integer grids only implemented for p >= 2.\");\n" + << " return daubechies_scaling_integer_grid_imp<Real, p, order>::value;\n" + << "}\n\n"; + + fs << "} // namespaces\n"; + fs << "#endif\n"; + fs.close(); + + return 0; +} diff --git a/src/boost/libs/math/example/daubechies_wavelets/daubechies_scaling_memory_occupation.cpp b/src/boost/libs/math/example/daubechies_wavelets/daubechies_scaling_memory_occupation.cpp new file mode 100644 index 000000000..43ae80779 --- /dev/null +++ b/src/boost/libs/math/example/daubechies_wavelets/daubechies_scaling_memory_occupation.cpp @@ -0,0 +1,59 @@ +#include <iostream> +#include <boost/math/special_functions/daubechies_scaling.hpp> +#include <boost/core/demangle.hpp> +#include <boost/hana/for_each.hpp> +#include <boost/hana/ext/std/integer_sequence.hpp> + +int main() +{ + boost::hana::for_each(std::make_index_sequence<18>(), + [](auto i) { + std::cout << std::right; + auto daub = boost::math::daubechies_scaling<float, i+2>(); + std::cout << "The Daubechies " << std::setw(2) << i + 2 << " scaling function occupies " + << std::setw(12) << daub.bytes()/1000.0 << " kilobytes in relative accuracy mode in " + << boost::core::demangle(typeid(float).name()) << " precision\n"; + }); + + std::cout << std::endl; + std::cout << std::endl; + std::cout << std::endl; + + boost::hana::for_each(std::make_index_sequence<18>(), + [](auto i) { + std::cout << std::right; + auto daub = boost::math::daubechies_scaling<float, i+2>(-2); + std::cout << "The Daubechies " << std::setw(2) << i + 2 << " scaling function occupies " + << std::setw(12) << daub.bytes()/1000.0 << " kilobytes in absolute accuracy mode in " + << boost::core::demangle(typeid(float).name()) << " precision\n"; + }); + + std::cout << std::endl; + std::cout << std::endl; + std::cout << std::endl; + + + boost::hana::for_each(std::make_index_sequence<18>(), + [](auto i) { + std::cout << std::right; + auto daub = boost::math::daubechies_scaling<double, i+2>(); + std::cout << "The Daubechies " << std::setw(2) << i + 2 << " scaling function occupies " + << std::setw(12) << daub.bytes()/1000.0 << " kilobytes in relative accuracy mode in " + << boost::core::demangle(typeid(double).name()) << " precision\n"; + }); + + std::cout << std::endl; + std::cout << std::endl; + std::cout << std::endl; + + boost::hana::for_each(std::make_index_sequence<18>(), + [](auto i) { + std::cout << std::right; + auto daub = boost::math::daubechies_scaling<double, i+2>(-2); + std::cout << "The Daubechies " << std::setw(2) << i + 2 << " scaling function occupies " + << std::setw(12) << daub.bytes()/1000.0 << " kilobytes in absolute accuracy mode in " + << boost::core::demangle(typeid(double).name()) << " precision\n"; + }); + + +} diff --git a/src/boost/libs/math/example/daubechies_wavelets/daubechies_wavelet_plots.cpp b/src/boost/libs/math/example/daubechies_wavelets/daubechies_wavelet_plots.cpp new file mode 100644 index 000000000..4d898ea4e --- /dev/null +++ b/src/boost/libs/math/example/daubechies_wavelets/daubechies_wavelet_plots.cpp @@ -0,0 +1,160 @@ +/* + * Copyright Nick Thompson, 2020 + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#include <iostream> +#include <boost/core/demangle.hpp> +#include <boost/hana/for_each.hpp> +#include <boost/hana/ext/std/integer_sequence.hpp> + +#include <boost/multiprecision/float128.hpp> +#include <boost/math/special_functions/daubechies_wavelet.hpp> +#include <quicksvg/graph_fn.hpp> +#include <quicksvg/ulp_plot.hpp> + + +using boost::multiprecision::float128; +constexpr const int GRAPH_WIDTH = 700; + +template<typename Real, int p> +void plot_psi(int grid_refinements = -1) +{ + auto psi = boost::math::daubechies_wavelet<Real, p>(); + if (grid_refinements >= 0) + { + psi = boost::math::daubechies_wavelet<Real, p>(grid_refinements); + } + auto [a, b] = psi.support(); + std::string title = "Daubechies " + std::to_string(p) + " wavelet"; + title = ""; + std::string filename = "daubechies_" + std::to_string(p) + "_wavelet.svg"; + int samples = 1024; + quicksvg::graph_fn daub(a, b, title, filename, samples, GRAPH_WIDTH); + daub.set_gridlines(8, 2*p-1); + daub.set_stroke_width(1); + daub.add_fn(psi); + daub.write_all(); +} + +template<typename Real, int p> +void plot_dpsi(int grid_refinements = -1) +{ + auto psi = boost::math::daubechies_wavelet<Real, p>(); + if (grid_refinements >= 0) + { + psi = boost::math::daubechies_wavelet<Real, p>(grid_refinements); + } + auto [a, b] = psi.support(); + std::string title = "Daubechies " + std::to_string(p) + " wavelet derivative"; + title = ""; + std::string filename = "daubechies_" + std::to_string(p) + "_wavelet_prime.svg"; + int samples = 1024; + quicksvg::graph_fn daub(a, b, title, filename, samples, GRAPH_WIDTH); + daub.set_stroke_width(1); + daub.set_gridlines(8, 2*p-1); + auto dpsi = [psi](Real x)->Real { return psi.prime(x); }; + daub.add_fn(dpsi); + daub.write_all(); +} + +template<typename Real, int p> +void plot_convergence() +{ + auto psi1 = boost::math::daubechies_wavelet<Real, p>(1); + auto [a, b] = psi1.support(); + std::string title = "Daubechies " + std::to_string(p) + " wavelet at 1 (orange), 2 (red), and 21 (blue) grid refinements"; + title = ""; + std::string filename = "daubechies_" + std::to_string(p) + "_wavelet_convergence.svg"; + + quicksvg::graph_fn daub(a, b, title, filename, 1024, GRAPH_WIDTH); + daub.set_stroke_width(1); + daub.set_gridlines(8, 2*p-1); + + daub.add_fn(psi1, "orange"); + auto psi2 = boost::math::daubechies_wavelet<Real, p>(2); + daub.add_fn(psi2, "red"); + + auto psi21 = boost::math::daubechies_wavelet<Real, p>(21); + daub.add_fn(psi21); + + daub.write_all(); +} + +template<typename Real, int p> +void plot_condition_number() +{ + using std::abs; + using std::log; + static_assert(p >= 3, "p = 2 is not differentiable, so condition numbers cannot be effectively evaluated."); + auto phi = boost::math::daubechies_wavelet<Real, p>(); + Real a = phi.support().first + 1000*std::sqrt(std::numeric_limits<Real>::epsilon()); + Real b = phi.support().second - 1000*std::sqrt(std::numeric_limits<Real>::epsilon()); + std::string title = "log10 of condition number of function evaluation for Daubechies " + std::to_string(p) + " wavelet function."; + title = ""; + std::string filename = "daubechies_" + std::to_string(p) + "_wavelet_condition_number.svg"; + + + quicksvg::graph_fn daub(a, b, title, filename, 2048, GRAPH_WIDTH); + daub.set_stroke_width(1); + daub.set_gridlines(8, 2*p-1); + + auto cond = [&phi](Real x) + { + Real y = phi(x); + Real dydx = phi.prime(x); + Real z = abs(x*dydx/y); + using std::isnan; + if (z==0) + { + return Real(-1); + } + if (isnan(z)) + { + // Graphing libraries don't like nan's: + return Real(1); + } + return log10(z); + }; + daub.add_fn(cond); + daub.write_all(); +} + +template<typename CoarseReal, typename PreciseReal, int p, class PsiPrecise> +void do_ulp(int coarse_refinements, PsiPrecise psi_precise) +{ + auto psi_coarse = boost::math::daubechies_wavelet<CoarseReal, p>(coarse_refinements); + + std::string title = std::to_string(p) + " vanishing moment ULP plot at " + std::to_string(coarse_refinements) + " refinements and " + boost::core::demangle(typeid(CoarseReal).name()) + " precision"; + title = ""; + + std::string filename = "daubechies_" + std::to_string(p) + "_wavelet_" + boost::core::demangle(typeid(CoarseReal).name()) + "_" + std::to_string(coarse_refinements) + "_refinements.svg"; + int samples = 20000; + int clip = 20; + int horizontal_lines = 8; + int vertical_lines = 2*p - 1; + quicksvg::ulp_plot<decltype(psi_coarse), CoarseReal, decltype(psi_precise), PreciseReal>(psi_coarse, psi_precise, CoarseReal(psi_coarse.support().first), psi_coarse.support().second, title, filename, samples, GRAPH_WIDTH, clip, horizontal_lines, vertical_lines); +} + + +int main() +{ + boost::hana::for_each(std::make_index_sequence<18>(), [&](auto i){ plot_psi<double, i+2>(); }); + boost::hana::for_each(std::make_index_sequence<17>(), [&](auto i){ plot_dpsi<double, i+3>(); }); + boost::hana::for_each(std::make_index_sequence<17>(), [&](auto i){ plot_condition_number<double, i+3>(); }); + boost::hana::for_each(std::make_index_sequence<18>(), [&](auto i){ plot_convergence<double, i+2>(); }); + + using PreciseReal = float128; + using CoarseReal = double; + int precise_refinements = 22; + constexpr const int p = 9; + std::cout << "Computing precise wavelet function in " << boost::core::demangle(typeid(PreciseReal).name()) << " precision.\n"; + auto phi_precise = boost::math::daubechies_wavelet<PreciseReal, p>(precise_refinements); + std::cout << "Beginning comparison with functions computed in " << boost::core::demangle(typeid(CoarseReal).name()) << " precision.\n"; + for (int i = 7; i <= precise_refinements-1; ++i) + { + std::cout << "\tCoarse refinement " << i << "\n"; + do_ulp<CoarseReal, PreciseReal, p>(i, phi_precise); + } +} diff --git a/src/boost/libs/math/example/daubechies_wavelets/find_best_daubechies_interpolator.cpp b/src/boost/libs/math/example/daubechies_wavelets/find_best_daubechies_interpolator.cpp new file mode 100644 index 000000000..56c5ed3cb --- /dev/null +++ b/src/boost/libs/math/example/daubechies_wavelets/find_best_daubechies_interpolator.cpp @@ -0,0 +1,535 @@ +// Copyright Nick Thompson, 2020 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <iostream> +#include <unordered_map> +#include <string> +#include <future> +#include <thread> +#include <fstream> +#include <boost/hana/for_each.hpp> +#include <boost/hana/ext/std/integer_sequence.hpp> +#include <boost/math/special_functions/daubechies_scaling.hpp> +#include <boost/math/special_functions/detail/daubechies_scaling_integer_grid.hpp> +#include <boost/math/interpolators/cubic_hermite.hpp> +#include <boost/math/interpolators/quintic_hermite.hpp> +#include <boost/math/interpolators/quintic_hermite.hpp> +#include <boost/math/interpolators/septic_hermite.hpp> +#include <boost/math/interpolators/cardinal_quadratic_b_spline.hpp> +#include <boost/math/interpolators/cardinal_cubic_b_spline.hpp> +#include <boost/math/interpolators/cardinal_quintic_b_spline.hpp> +#include <boost/math/interpolators/whittaker_shannon.hpp> +#include <boost/math/interpolators/cardinal_trigonometric.hpp> +#include <boost/math/special_functions/next.hpp> +#include <boost/math/interpolators/makima.hpp> +#include <boost/math/interpolators/pchip.hpp> +#include <boost/multiprecision/float128.hpp> +#include <boost/core/demangle.hpp> + +using boost::multiprecision::float128; + + +template<typename Real, typename PreciseReal, int p> +void choose_refinement() +{ + std::cout << "Choosing refinement for " << boost::core::demangle(typeid(Real).name()) << " precision Daubechies scaling function with " << p << " vanishing moments.\n"; + using std::abs; + int rmax = 22; + auto phi_dense = boost::math::daubechies_scaling_dyadic_grid<PreciseReal, p, 0>(rmax); + Real dx_dense = (2*p-1)/static_cast<Real>(phi_dense.size()-1); + + for (int r = 2; r <= 18; ++r) + { + Real dx = Real(1)/ (1 << r); + std::cout << "\tdx = 1/" << (1/dx) << " = 1/2^" << r << " = " << dx << "\n"; + auto phi = boost::math::daubechies_scaling<Real, p>(r); + Real max_flt_distance = 0; + Real sup = 0; + Real rel_sup = 0; + Real worst_flt_abscissa = 0; + Real worst_flt_value = 0; + Real worst_flt_computed = 0; + + Real worst_rel_abscissa = 0; + Real worst_rel_value = 0; + Real worst_rel_computed = 0; + + Real worst_abs_abscissa = 0; + Real worst_abs_computed = 0; + Real worst_abs_expected = 0; + for (size_t i = 0; i < phi_dense.size(); ++i) + { + Real t = i*dx_dense; + Real computed = phi(t); + Real expected = Real(phi_dense[i]); + Real abs_diff = abs(computed - expected); + Real rel_diff = abs_diff/abs(expected); + Real flt_distance = abs(boost::math::float_distance(computed, expected)); + if (flt_distance > max_flt_distance) + { + max_flt_distance = flt_distance; + worst_flt_abscissa = t; + worst_flt_value = expected; + worst_flt_computed = computed; + } + if (expected != 0 && rel_diff > rel_sup) + { + rel_sup = rel_diff; + worst_rel_abscissa = t; + worst_rel_value = expected; + worst_rel_computed = computed; + + } + if (abs_diff > sup) + { + sup = abs_diff; + worst_abs_abscissa = t; + worst_abs_computed = computed; + worst_abs_expected = expected; + } + } + std::cout << "\t\tFloat distance at r = " << r << " is " << max_flt_distance << ", sup distance = " << sup << ", max relative error = " << rel_sup << "\n"; + std::cout << "\t\tWorst flt abscissa = " << worst_flt_abscissa << ", worst expected value = " << worst_flt_value << ", computed = " << worst_flt_computed << "\n"; + std::cout << "\t\tWorst rel abscissa = " << worst_rel_abscissa << ", worst expected value = " << worst_rel_value << ", computed = " << worst_rel_computed << "\n"; + std::cout << "\t\tWorst abs abscissa = " << worst_abs_abscissa << ", worst expected value = " << worst_abs_computed << ", worst abs value (expected) = " << worst_abs_expected << "\n"; + } + std::cout << "\n\n\n"; +} + +template<typename Real, typename PreciseReal, int p> +void find_best_interpolator() +{ + std::string filename = "daubechies_" + std::to_string(p) + "_scaling_convergence.csv"; + std::ofstream fs{filename}; + static_assert(sizeof(PreciseReal) >= sizeof(Real), "sizeof(PreciseReal) >= sizeof(Real) is required."); + using std::abs; + int rmax = 18; + std::cout << "Computing phi_dense_precise\n"; + auto phi_dense_precise = boost::math::daubechies_scaling_dyadic_grid<PreciseReal, p, 0>(rmax); + std::vector<Real> phi_dense(phi_dense_precise.size()); + for (size_t i = 0; i < phi_dense.size(); ++i) + { + phi_dense[i] = static_cast<Real>(phi_dense_precise[i]); + } + phi_dense_precise.resize(0); + std::cout << "Done\n"; + + Real dx_dense = (2*p-1)/static_cast<Real>(phi_dense.size()-1); + fs << std::setprecision(std::numeric_limits<Real>::digits10 + 3); + fs << std::fixed; + fs << "r, matched_holder, linear, quadratic_b_spline, cubic_b_spline, quintic_b_spline, cubic_hermite, pchip, makima, fo_taylor"; + if (p==2) + { + fs << "\n"; + } + else + { + fs << ", quintic_hermite, second_order_taylor"; + if (p > 3) + { + fs << ", third_order_taylor, septic_hermite\n"; + } + else + { + fs << "\n"; + } + } + for (int r = 2; r < 13; ++r) + { + fs << r << ", "; + std::map<Real, std::string> m; + auto phi = boost::math::daubechies_scaling_dyadic_grid<Real, p, 0>(r); + auto phi_prime = boost::math::daubechies_scaling_dyadic_grid<Real, p, 1>(r); + + std::vector<Real> x(phi.size()); + Real dx = (2*p-1)/static_cast<Real>(x.size()-1); + std::cout << "dx = 1/" << (1 << r) << " = " << dx << "\n"; + for (size_t i = 0; i < x.size(); ++i) + { + x[i] = i*dx; + } + + { + auto phi_copy = phi; + auto phi_prime_copy = phi_prime; + auto mh = boost::math::detail::matched_holder(std::move(phi_copy), std::move(phi_prime_copy), r, Real(0)); + Real sup = 0; + // call to matched_holder is unchecked, so only go to phi_dense.size() -1. + for (size_t i = 0; i < phi_dense.size() - 1; ++i) + { + Real x = i*dx_dense; + Real diff = abs(phi_dense[i] - mh(x)); + if (diff > sup) + { + sup = diff; + } + } + m.insert({sup, "matched_holder"}); + fs << sup << ", "; + } + + + { + auto linear = [&phi, &dx, &r](Real x)->Real { + if (x <= 0 || x >= 2*p-1) + { + return Real(0); + } + using std::floor; + + Real y = (1<<r)*x; + Real k = floor(y); + + size_t kk = static_cast<size_t>(k); + + Real t = y - k; + return (1-t)*phi[kk] + t*phi[kk+1]; + }; + + Real linear_sup = 0; + for (size_t i = 0; i < phi_dense.size(); ++i) + { + Real x = i*dx_dense; + Real diff = abs(phi_dense[i] - linear(x)); + if (diff > linear_sup) + { + linear_sup = diff; + } + } + m.insert({linear_sup, "linear interpolation"}); + fs << linear_sup << ", "; + } + + + { + auto qbs = boost::math::interpolators::cardinal_quadratic_b_spline(phi.data(), phi.size(), Real(0), dx, phi_prime.front(), phi_prime.back()); + Real qbs_sup = 0; + for (size_t i = 0; i < phi_dense.size(); ++i) + { + Real x = i*dx_dense; + Real diff = abs(phi_dense[i] - qbs(x)); + if (diff > qbs_sup) { + qbs_sup = diff; + } + } + m.insert({qbs_sup, "quadratic_b_spline"}); + fs << qbs_sup << ", "; + } + + { + auto cbs = boost::math::interpolators::cardinal_cubic_b_spline(phi.data(), phi.size(), Real(0), dx, phi_prime.front(), phi_prime.back()); + Real cbs_sup = 0; + for (size_t i = 0; i < phi_dense.size(); ++i) + { + Real x = i*dx_dense; + Real diff = abs(phi_dense[i] - cbs(x)); + if (diff > cbs_sup) + { + cbs_sup = diff; + } + } + m.insert({cbs_sup, "cubic_b_spline"}); + fs << cbs_sup << ", "; + } + + { + auto qbs = boost::math::interpolators::cardinal_quintic_b_spline(phi.data(), phi.size(), Real(0), dx, {0,0}, {0,0}); + Real qbs_sup = 0; + for (size_t i = 0; i < phi_dense.size(); ++i) + { + Real x = i*dx_dense; + Real diff = abs(phi_dense[i] - qbs(x)); + if (diff > qbs_sup) + { + qbs_sup = diff; + } + } + m.insert({qbs_sup, "quintic_b_spline"}); + fs << qbs_sup << ", "; + } + + { + auto phi_copy = phi; + auto phi_prime_copy = phi_prime; + auto ch = boost::math::interpolators::cardinal_cubic_hermite(std::move(phi_copy), std::move(phi_prime_copy), Real(0), dx); + Real chs_sup = 0; + for (size_t i = 0; i < phi_dense.size(); ++i) + { + Real x = i*dx_dense; + Real diff = abs(phi_dense[i] - ch(x)); + if (diff > chs_sup) + { + chs_sup = diff; + } + } + m.insert({chs_sup, "cubic_hermite_spline"}); + fs << chs_sup << ", "; + } + + { + auto phi_copy = phi; + auto x_copy = x; + auto phi_prime_copy = phi_prime; + auto pc = boost::math::interpolators::pchip(std::move(x_copy), std::move(phi_copy)); + Real pchip_sup = 0; + for (size_t i = 0; i < phi_dense.size(); ++i) + { + Real x = i*dx_dense; + Real diff = abs(phi_dense[i] - pc(x)); + if (diff > pchip_sup) + { + pchip_sup = diff; + } + } + m.insert({pchip_sup, "pchip"}); + fs << pchip_sup << ", "; + } + + { + auto phi_copy = phi; + auto x_copy = x; + auto pc = boost::math::interpolators::makima(std::move(x_copy), std::move(phi_copy)); + Real makima_sup = 0; + for (size_t i = 0; i < phi_dense.size(); ++i) { + Real x = i*dx_dense; + Real diff = abs(phi_dense[i] - pc(x)); + if (diff > makima_sup) + { + makima_sup = diff; + } + } + m.insert({makima_sup, "makima"}); + fs << makima_sup << ", "; + } + + // Whittaker-Shannon interpolation has linear complexity; test over all points and it's quadratic. + // I ran this a couple times and found it's not competitive; so comment out for now. + /*{ + auto phi_copy = phi; + auto ws = boost::math::interpolators::whittaker_shannon(std::move(phi_copy), Real(0), dx); + Real sup = 0; + for (size_t i = 0; i < phi_dense.size(); ++i) { + Real x = i*dx_dense; + using std::abs; + Real diff = abs(phi_dense[i] - ws(x)); + if (diff > sup) { + sup = diff; + } + } + + m.insert({sup, "whittaker_shannon"}); + } + + // Again, linear complexity of evaluation => quadratic complexity of exhaustive checking. + { + auto trig = boost::math::interpolators::cardinal_trigonometric(phi, Real(0), dx); + Real sup = 0; + for (size_t i = 0; i < phi_dense.size(); ++i) { + Real x = i*dx_dense; + using std::abs; + Real diff = abs(phi_dense[i] - trig(x)); + if (diff > sup) { + sup = diff; + } + } + m.insert({sup, "trig"}); + }*/ + + { + auto fotaylor = [&phi, &phi_prime, &r](Real x)->Real + { + if (x <= 0 || x >= 2*p-1) + { + return 0; + } + using std::floor; + + Real y = (1<<r)*x; + Real k = floor(y); + + size_t kk = static_cast<size_t>(k); + if (y - k < k + 1 - y) + { + Real eps = (y-k)/(1<<r); + return phi[kk] + eps*phi_prime[kk]; + } + else { + Real eps = (y-k-1)/(1<<r); + return phi[kk+1] + eps*phi_prime[kk+1]; + } + }; + Real fo_sup = 0; + for (size_t i = 0; i < phi_dense.size(); ++i) + { + Real x = i*dx_dense; + Real diff = abs(phi_dense[i] - fotaylor(x)); + if (diff > fo_sup) + { + fo_sup = diff; + } + } + m.insert({fo_sup, "First-order Taylor"}); + if (p==2) + { + fs << fo_sup << "\n"; + } + else + { + fs << fo_sup << ", "; + } + } + + if constexpr (p > 2) { + auto phi_dbl_prime = boost::math::daubechies_scaling_dyadic_grid<Real, p, 2>(r); + + { + auto phi_copy = phi; + auto phi_prime_copy = phi_prime; + auto phi_dbl_prime_copy = phi_dbl_prime; + auto qh = boost::math::interpolators::cardinal_quintic_hermite(std::move(phi_copy), std::move(phi_prime_copy), std::move(phi_dbl_prime_copy), Real(0), dx); + Real qh_sup = 0; + for (size_t i = 0; i < phi_dense.size(); ++i) + { + Real x = i*dx_dense; + Real diff = abs(phi_dense[i] - qh(x)); + if (diff > qh_sup) + { + qh_sup = diff; + } + } + m.insert({qh_sup, "quintic_hermite_spline"}); + fs << qh_sup << ", "; + } + + { + auto sotaylor = [&phi, &phi_prime, &phi_dbl_prime, &r](Real x)->Real { + if (x <= 0 || x >= 2*p-1) + { + return 0; + } + using std::floor; + + Real y = (1<<r)*x; + Real k = floor(y); + + size_t kk = static_cast<size_t>(k); + if (y - k < k + 1 - y) + { + Real eps = (y-k)/(1<<r); + return phi[kk] + eps*phi_prime[kk] + eps*eps*phi_dbl_prime[kk]/2; + } + else { + Real eps = (y-k-1)/(1<<r); + return phi[kk+1] + eps*phi_prime[kk+1] + eps*eps*phi_dbl_prime[kk+1]/2; + } + }; + Real so_sup = 0; + for (size_t i = 0; i < phi_dense.size(); ++i) + { + Real x = i*dx_dense; + Real diff = abs(phi_dense[i] - sotaylor(x)); + if (diff > so_sup) + { + so_sup = diff; + } + } + m.insert({so_sup, "Second-order Taylor"}); + if (p > 3) + { + fs << so_sup << ", "; + } + else + { + fs << so_sup << "\n"; + } + + } + } + + if constexpr (p > 3) + { + auto phi_dbl_prime = boost::math::daubechies_scaling_dyadic_grid<Real, p, 2>(r); + auto phi_triple_prime = boost::math::daubechies_scaling_dyadic_grid<Real, p, 3>(r); + + { + auto totaylor = [&phi, &phi_prime, &phi_dbl_prime, &phi_triple_prime, &r](Real x)->Real { + if (x <= 0 || x >= 2*p-1) { + return 0; + } + using std::floor; + + Real y = (1<<r)*x; + Real k = floor(y); + + size_t kk = static_cast<size_t>(k); + if (y - k < k + 1 - y) + { + Real eps = (y-k)/(1<<r); + return phi[kk] + eps*phi_prime[kk] + eps*eps*phi_dbl_prime[kk]/2 + eps*eps*eps*phi_triple_prime[kk]/6; + } + else { + Real eps = (y-k-1)/(1<<r); + return phi[kk+1] + eps*phi_prime[kk+1] + eps*eps*phi_dbl_prime[kk+1]/2 + eps*eps*eps*phi_triple_prime[kk]/6; + } + }; + Real to_sup = 0; + for (size_t i = 0; i < phi_dense.size(); ++i) + { + Real x = i*dx_dense; + Real diff = abs(phi_dense[i] - totaylor(x)); + if (diff > to_sup) + { + to_sup = diff; + } + } + + m.insert({to_sup, "Third-order Taylor"}); + fs << to_sup << ", "; + } + + { + auto phi_copy = phi; + auto phi_prime_copy = phi_prime; + auto phi_dbl_prime_copy = phi_dbl_prime; + auto phi_triple_prime_copy = phi_triple_prime; + auto sh = boost::math::interpolators::cardinal_septic_hermite(std::move(phi_copy), std::move(phi_prime_copy), std::move(phi_dbl_prime_copy), std::move(phi_triple_prime_copy), Real(0), dx); + Real septic_sup = 0; + for (size_t i = 0; i < phi_dense.size(); ++i) + { + Real x = i*dx_dense; + Real diff = abs(phi_dense[i] - sh(x)); + if (diff > septic_sup) + { + septic_sup = diff; + } + } + m.insert({septic_sup, "septic_hermite_spline"}); + fs << septic_sup << "\n"; + } + + + } + std::string best = "none"; + Real best_sup = 1000000000; + std::cout << std::setprecision(std::numeric_limits<Real>::digits10 + 3) << std::fixed; + for (auto & e : m) + { + std::cout << "\t" << e.first << " is error of " << e.second << "\n"; + if (e.first < best_sup) + { + best = e.second; + best_sup = e.first; + } + } + std::cout << "\tThe best method for p = " << p << " is the " << best << "\n"; + } +} + +int main() +{ + //boost::hana::for_each(std::make_index_sequence<4>(), [&](auto i){ choose_refinement<double, float128, i+16>(); }); + boost::hana::for_each(std::make_index_sequence<12>(), [&](auto i){ find_best_interpolator<double, float128, i+2>(); }); +} diff --git a/src/boost/libs/math/example/daubechies_wavelets/regress_daubechies_accuracy.cpp b/src/boost/libs/math/example/daubechies_wavelets/regress_daubechies_accuracy.cpp new file mode 100644 index 000000000..d7b0f3297 --- /dev/null +++ b/src/boost/libs/math/example/daubechies_wavelets/regress_daubechies_accuracy.cpp @@ -0,0 +1,146 @@ +#include <iostream> +#include <string> +#include <fstream> +#include <map> +#include <cmath> +#include <vector> +#include <iomanip> +#include <boost/algorithm/string.hpp> +#include <boost/math/statistics/linear_regression.hpp> + + +int main(int argc, char** argv) +{ + if (argc != 2) + { + std::cout << "Usage: ./regress_accuracy.x foo.csv\n"; + return 1; + } + std::string filename = std::string(argv[1]); + std::ifstream ifs(filename.c_str()); + if (!ifs.good()) + { + std::cerr << "Couldn't find file " << filename << "\n"; + return 1; + } + std::map<std::string, std::vector<double>> m; + + std::string header_line; + std::getline(ifs, header_line); + std::cout << "Header line = " << header_line << "\n"; + std::vector<std::string> header_strs; + boost::split(header_strs, header_line, boost::is_any_of(",")); + for (auto & s : header_strs) { + boost::algorithm::trim(s); + } + + std::string line; + std::vector<double> r; + std::vector<double> matched_holder; + std::vector<double> linear; + std::vector<double> quadratic_b_spline; + std::vector<double> cubic_b_spline; + std::vector<double> quintic_b_spline; + std::vector<double> cubic_hermite; + std::vector<double> pchip; + std::vector<double> makima; + std::vector<double> fotaylor; + std::vector<double> quintic_hermite; + std::vector<double> sotaylor; + std::vector<double> totaylor; + std::vector<double> septic_hermite; + while(std::getline(ifs, line)) + { + std::vector<std::string> strs; + boost::split(strs, line, boost::is_any_of(",")); + for (auto & s : strs) + { + boost::algorithm::trim(s); + } + std::vector<double> v(strs.size(), std::numeric_limits<double>::quiet_NaN()); + for (size_t i = 0; i < v.size(); ++i) + { + v[i] = std::stod(strs[i]); + } + r.push_back(v[0]); + matched_holder.push_back(std::log2(v[1])); + linear.push_back(std::log2(v[2])); + quadratic_b_spline.push_back(std::log2(v[3])); + cubic_b_spline.push_back(std::log2(v[4])); + quintic_b_spline.push_back(std::log2(v[5])); + cubic_hermite.push_back(std::log2(v[6])); + pchip.push_back(std::log2(v[7])); + makima.push_back(std::log2(v[8])); + fotaylor.push_back(std::log2(v[9])); + if (v.size() > 10) { + quintic_hermite.push_back(std::log2(v[10])); + sotaylor.push_back(std::log2(v[11])); + } + if (v.size() > 12) { + totaylor.push_back(std::log2(v[12])); + septic_hermite.push_back(std::log2(v[13])); + } + } + + std::cout << std::fixed << std::setprecision(16); + auto q = boost::math::statistics::simple_ordinary_least_squares_with_R_squared(r, matched_holder); + assert(std::get<1>(q) < 0); + std::cout << "Matched Holder : " << std::get<0>(q) << " - " << std::abs(std::get<1>(q)) << "r, R^2 = " << std::get<2>(q) << "\n"; + + q = boost::math::statistics::simple_ordinary_least_squares_with_R_squared(r, linear); + assert(std::get<1>(q) < 0); + std::cout << "Linear : " << std::get<0>(q) << " - " << std::abs(std::get<1>(q)) << "r, R^2 = " << std::get<2>(q) << "\n"; + + q = boost::math::statistics::simple_ordinary_least_squares_with_R_squared(r, quadratic_b_spline); + assert(std::get<1>(q) < 0); + std::cout << "Quadratic B-spline: " << std::get<0>(q) << " - " << std::abs(std::get<1>(q)) << "r, R^2 = " << std::get<2>(q) << "\n"; + + q = boost::math::statistics::simple_ordinary_least_squares_with_R_squared(r, cubic_b_spline); + assert(std::get<1>(q) < 0); + std::cout << "Cubic B-spline : " << std::get<0>(q) << " - " << std::abs(std::get<1>(q)) << "r, R^2 = " << std::get<2>(q) << "\n"; + + q = boost::math::statistics::simple_ordinary_least_squares_with_R_squared(r, quintic_b_spline); + assert(std::get<1>(q) < 0); + std::cout << "Quintic B-spline : " << std::get<0>(q) << " - " << std::abs(std::get<1>(q)) << "r, R^2 = " << std::get<2>(q) << "\n"; + + q = boost::math::statistics::simple_ordinary_least_squares_with_R_squared(r, cubic_hermite); + assert(std::get<1>(q) < 0); + std::cout << "Cubic Hermite : " << std::get<0>(q) << " - " << std::abs(std::get<1>(q)) << "r, R^2 = " << std::get<2>(q) << "\n"; + + q = boost::math::statistics::simple_ordinary_least_squares_with_R_squared(r, pchip); + assert(std::get<1>(q) < 0); + std::cout << "PCHIP : " << std::get<0>(q) << " - " << std::abs(std::get<1>(q)) << "r, R^2 = " << std::get<2>(q) << "\n"; + + q = boost::math::statistics::simple_ordinary_least_squares_with_R_squared(r, makima); + assert(std::get<1>(q) < 0); + std::cout << "Makima : " << std::get<0>(q) << " - " << std::abs(std::get<1>(q)) << "r, R^2 = " << std::get<2>(q) << "\n"; + + q = boost::math::statistics::simple_ordinary_least_squares_with_R_squared(r, fotaylor); + assert(std::get<1>(q) < 0); + std::cout << "First-order Taylor: " << std::get<0>(q) << " - " << std::abs(std::get<1>(q)) << "r, R^2 = " << std::get<2>(q) << "\n"; + + if (sotaylor.size() > 0) + { + q = boost::math::statistics::simple_ordinary_least_squares_with_R_squared(r, quintic_hermite); + assert(std::get<1>(q) < 0); + std::cout << "Quintic Hermite : " << std::get<0>(q) << " - " << std::abs(std::get<1>(q)) << "r, R^2 = " << std::get<2>(q) << "\n"; + + q = boost::math::statistics::simple_ordinary_least_squares_with_R_squared(r, sotaylor); + assert(std::get<1>(q) < 0); + std::cout << "2nd order Taylor : " << std::get<0>(q) << " - " << std::abs(std::get<1>(q)) << "r, R^2 = " << std::get<2>(q) << "\n"; + + } + + if (totaylor.size() > 0) + { + q = boost::math::statistics::simple_ordinary_least_squares_with_R_squared(r, totaylor); + assert(std::get<1>(q) < 0); + std::cout << "3rd order Taylor : " << std::get<0>(q) << " - " << std::abs(std::get<1>(q)) << "r, R^2 = " << std::get<2>(q) << "\n"; + + q = boost::math::statistics::simple_ordinary_least_squares_with_R_squared(r, septic_hermite); + assert(std::get<1>(q) < 0); + std::cout << "Septic Hermite : " << std::get<0>(q) << " - " << std::abs(std::get<1>(q)) << "r, R^2 = " << std::get<2>(q) << "\n"; + + } + +}
\ No newline at end of file diff --git a/src/boost/libs/math/example/daubechies_wavelets/wavelet_transform.cpp b/src/boost/libs/math/example/daubechies_wavelets/wavelet_transform.cpp new file mode 100644 index 000000000..67cdde803 --- /dev/null +++ b/src/boost/libs/math/example/daubechies_wavelets/wavelet_transform.cpp @@ -0,0 +1,46 @@ +/* + * Copyright Nick Thompson, 2020 + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#include <cstdint> +#include <cmath> +#include <boost/math/quadrature/wavelet_transforms.hpp> +#include <Eigen/Dense> + + +int main() +{ + using boost::math::quadrature::daubechies_wavelet_transform; + double a = 1.3; + auto f = [&a](double t) { + if(t==0) { + return double(0); + } + return std::sin(a/t); + }; + + auto Wf = daubechies_wavelet_transform<decltype(f), double, 8>(f); + + Eigen::MatrixXd grid(512, 512); + double s = 7; + double t = 0; + grid(0,0) = Wf(s, t); + + auto g = [&a](double t)->std::complex<double> { + if (t==0) { + return {0.0, 0.0}; + } + return std::exp(std::complex<double>(0.0, a/t)); + }; + + auto Wg = daubechies_wavelet_transform<decltype(g), double, 8>(g); + std::cout << "W[f](s,t) = " << Wf(s,t) << "\n"; + std::cout << "W[g](s,t) = " << Wg(s, t) << "\n"; + std::cout << Wg(0.0, 3.5) << "\n"; + std::cout << Wf(0.0, 4.8) << "\n"; + std::cout << "W[f](-s,t) = " << Wf(-s, t) << "\n"; + std::cout << "W[g](-s,t) = " << Wg(-s, t) << "\n"; + +} diff --git a/src/boost/libs/math/example/distribution_construction.cpp b/src/boost/libs/math/example/distribution_construction.cpp new file mode 100644 index 000000000..a3d1a635d --- /dev/null +++ b/src/boost/libs/math/example/distribution_construction.cpp @@ -0,0 +1,295 @@ +// distribution_construction.cpp + +// Copyright Paul A. Bristow 2007, 2010, 2012. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Caution: this file contains Quickbook markup as well as code +// and comments, don't change any of the special comment markups! + +#ifdef _MSC_VER +# pragma warning (disable : 4996) // disable -D_SCL_SECURE_NO_WARNINGS C++ 'Checked Iterators' +#endif + +#include <iostream> +#include <exception> + +//[distribution_construction_1 + +/*` +The structure of distributions is rather different from some other statistical libraries, +for example, those written in less object-oriented language like FORTRAN and C that +provide a few arguments to each free function. + +Boost.Math library instead provides each distribution as a template C++ class. +A distribution is constructed with a few arguments, and then +member and non-member functions are used to find values of the +distribution, often a function of a random variate. + +For this demonstration, first we need some includes to access the +negative binomial distribution (and the binomial, beta and gamma distributions too). + +To demonstrate the use with a high precision User-defined floating-point type +`cpp_bin_float`, we also need an include from Boost.Multiprecision. +(We could equally well have used a `cpp_dec_float` multiprecision type). + +We choose a typedef `cpp_bin_float_50` to provide a 50 decimal digit type, +but we could equally have chosen at 128-bit type `cpp_bin_float_quad`, +or on some platforms `__float128`, providing about 35 decimal digits. +*/ + +#include <boost/math/distributions/negative_binomial.hpp> // for negative_binomial_distribution + using boost::math::negative_binomial_distribution; // default type is double. + using boost::math::negative_binomial; // typedef provides default type is double. +#include <boost/math/distributions/binomial.hpp> // for binomial_distribution. +#include <boost/math/distributions/beta.hpp> // for beta_distribution. +#include <boost/math/distributions/gamma.hpp> // for gamma_distribution. +#include <boost/math/distributions/normal.hpp> // for normal_distribution. + +#include <boost/multiprecision/cpp_bin_float.hpp> // for cpp_bin_float_50 +/*` +Several examples of constructing distributions follow: +*/ +//] [/distribution_construction_1 end of Quickbook in C++ markup] + +int main() +{ + try + { +//[distribution_construction_2 +/*` +First, a negative binomial distribution with 8 successes +and a success fraction 0.25, 25% or 1 in 4, is constructed like this: +*/ + boost::math::negative_binomial_distribution<double> mydist0(8., 0.25); + /*` + But this is inconveniently long, so we might be tempted to write + */ + using namespace boost::math; + /*` + but this might risk ambiguity with names in `std random` so + [*much] better is explicit `using boost::math::` statements, for example: + */ + using boost::math::negative_binomial_distribution; + /*` + and we can still reduce typing. + + Since the vast majority of applications use will be using `double` precision, + the template argument to the distribution (`RealType`) defaults + to type `double`, so we can also write: + */ + + negative_binomial_distribution<> mydist9(8., 0.25); // Uses default `RealType = double`. + + /*` + But the name `negative_binomial_distribution` is still inconveniently long, + so, for most distributions, a convenience `typedef` is provided, for example: + + typedef negative_binomial_distribution<double> negative_binomial; // Reserved name of type double. + + [caution + This convenience typedef is [*not provided] if a clash would occur + with the name of a function; currently only `beta` and `gamma` + fall into this category. + ] + + So, after a using statement, + */ + + using boost::math::negative_binomial; + + /*` + we have a convenient typedef to `negative_binomial_distribution<double>`: + */ + negative_binomial mydist(8., 0.25); + + /*` + Some more examples using the convenience typedef: + */ + negative_binomial mydist10(5., 0.4); // Both arguments double. + /*` + And automatic conversion of arguments takes place, so you can use integers and floats: + */ + negative_binomial mydist11(5, 0.4); // Using provided typedef of type double, and int and double arguments. + /*` + This is probably the most common usage. + Other combination are possible too: + */ + negative_binomial mydist12(5., 0.4F); // Double and float arguments. + negative_binomial mydist13(5, 1); // Both arguments integer. + + /*` + Similarly for most other distributions like the binomial. + */ + binomial mybinomial(1, 0.5); // is more concise than + binomial_distribution<> mybinomd1(1, 0.5); + + /*` + For cases when the typdef distribution name would clash with a math special function + (currently only beta and gamma) + the typedef is deliberately not provided, and the longer version of the name + must be used, so for example, do not use: + + using boost::math::beta; + beta mybetad0(1, 0.5); // Error beta is a math FUNCTION! + + Which produces the error messages: + + [pre + error C2146: syntax error : missing ';' before identifier 'mybetad0' + warning C4551: function call missing argument list + error C3861: 'mybetad0': identifier not found + ] + + Instead you should use: + */ + using boost::math::beta_distribution; + beta_distribution<> mybetad1(1, 0.5); + /*` + or for the gamma distribution: + */ + gamma_distribution<> mygammad1(1, 0.5); + + /*` + We can, of course, still provide the type explicitly thus: + */ + + // Explicit double precision: both arguments are double: + negative_binomial_distribution<double> mydist1(8., 0.25); + + // Explicit float precision, double arguments are truncated to float: + negative_binomial_distribution<float> mydist2(8., 0.25); + + // Explicit float precision, integer & double arguments converted to float: + negative_binomial_distribution<float> mydist3(8, 0.25); + + // Explicit float precision, float arguments, so no conversion: + negative_binomial_distribution<float> mydist4(8.F, 0.25F); + + // Explicit float precision, integer arguments promoted to float. + negative_binomial_distribution<float> mydist5(8, 1); + + // Explicit double precision: + negative_binomial_distribution<double> mydist6(5., 0.4); + + // Explicit long double precision: + negative_binomial_distribution<long double> mydist7(8., 0.25); + + /*` + And you can use your own template RealType, + for example, `boost::math::cpp_bin_float_50` (an arbitrary 50 decimal digits precision type), + then we can write: + */ + using namespace boost::multiprecision; + negative_binomial_distribution<cpp_bin_float_50> mydist8(8, 0.25); + + // `integer` arguments are promoted to your RealType exactly, but + // `double` argument are converted to RealType, + // most likely losing precision! + + // So DON'T be tempted to write the 'obvious': + negative_binomial_distribution<cpp_bin_float_50> mydist20(8, 0.23456789012345678901234567890); + // to avoid truncation of second parameter to `0.2345678901234567` and loss of precision. + + // Instead pass a quoted decimal digit string: + negative_binomial_distribution<cpp_bin_float_50> mydist21(8, cpp_bin_float_50("0.23456789012345678901234567890") ); + + // Ensure that all potentially significant digits are shown. + std::cout.precision(std::numeric_limits<cpp_bin_float_50>::digits10); + // + cpp_bin_float_50 x("1.23456789012345678901234567890"); + std::cout << pdf(mydist8, x) << std::endl; +/*` showing 0.00012630010495970320103876754721976419438231705359935 + 0.00012630010495970320103876754721976419438231528547467 + +[warning When using multiprecision, it is all too easy to get accidental truncation!] + +For example, if you write +*/ + std::cout << pdf(mydist8, 1.23456789012345678901234567890) << std::endl; +/*` +showing 0.00012630010495970318465064569310967179576805651692929, +which is wrong at about the 17th decimal digit! + +This is because the value provided is truncated to a `double`, effectively + `double x = 1.23456789012345678901234567890;` + +Then the now `double x` is passed to function `pdf`, +and this truncated `double` value is finally promoted to `cpp_bin_float_50`. + +Another way of quietly getting the wrong answer is to write: +*/ + std::cout << pdf(mydist8, cpp_bin_float_50(1.23456789012345678901234567890)) << std::endl; +/*` +A correct way from a multi-digit string value is +*/ + std::cout << pdf(mydist8, cpp_bin_float_50("1.23456789012345678901234567890")) << std::endl; +/*` + +[tip Getting about 17 decimal digits followed by many zeros is often a sign of accidental truncation.] +*/ + +/*` +[h4 Default arguments to distribution constructors.] + +Note that default constructor arguments are only provided for some distributions. +So if you wrongly assume a default argument, you will get an error message, for example: + + negative_binomial_distribution<> mydist8; + +[pre error C2512 no appropriate default constructor available.] + +No default constructors are provided for the `negative binomial` distribution, +because it is difficult to chose any sensible default values for this distribution. + +For other distributions, like the normal distribution, +it is obviously very useful to provide 'standard' +defaults for the mean (zero) and standard deviation (unity) thus: + + normal_distribution(RealType mean = 0, RealType sd = 1); + +So in this case we can more tersely write: +*/ + using boost::math::normal; + + normal norm1; // Standard normal distribution N[0,1]. + normal norm2(2); // Mean = 2, std deviation = 1. + normal norm3(2, 3); // Mean = 2, std deviation = 3. + + } + catch(std::exception &ex) + { + std::cout << ex.what() << std::endl; + } + + return 0; +} // int main() + +/*`There is no useful output from this demonstration program, of course. */ + +//] [/end of distribution_construction_2] + +/* +//[distribution_construction_output + + 0.00012630010495970320103876754721976419438231705359935 + 0.00012630010495970318465064569310967179576805651692929 + 0.00012630010495970318465064569310967179576805651692929 + 0.00012630010495970320103876754721976419438231705359935 + +//] [/distribution_construction_output] + + + 0.00012630010495970320103876754721976419438231528547467 + 0.0001263001049597031846506456931096717957680547488046 + 0.0001263001049597031846506456931096717957680547488046 + 0.00012630010495970320103876754721976419438231528547467 + + +*/ + + + diff --git a/src/boost/libs/math/example/double_exponential.cpp b/src/boost/libs/math/example/double_exponential.cpp new file mode 100644 index 000000000..87e21b187 --- /dev/null +++ b/src/boost/libs/math/example/double_exponential.cpp @@ -0,0 +1,59 @@ +// Copyright Nick Thompson, 2017 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <iostream> +#include <cmath> +#include <boost/math/quadrature/tanh_sinh.hpp> +#include <boost/math/quadrature/sinh_sinh.hpp> +#include <boost/math/quadrature/exp_sinh.hpp> + +using boost::math::quadrature::tanh_sinh; +using boost::math::quadrature::sinh_sinh; +using boost::math::quadrature::exp_sinh; +using boost::math::constants::pi; +using boost::math::constants::half_pi; +using boost::math::constants::half; +using boost::math::constants::third; +using boost::math::constants::root_pi; +using std::log; +using std::cos; +using std::cosh; +using std::exp; +using std::sqrt; + +int main() +{ + std::cout << std::setprecision(std::numeric_limits<double>::digits10); + double tol = sqrt(std::numeric_limits<double>::epsilon()); + // For an integral over a finite domain, use tanh_sinh: + tanh_sinh<double> tanh_integrator(tol, 10); + auto f1 = [](double x) { return log(x)*log(1-x); }; + double Q = tanh_integrator.integrate(f1, (double) 0, (double) 1); + double Q_expected = 2 - pi<double>()*pi<double>()*half<double>()*third<double>(); + + std::cout << "tanh_sinh quadrature of log(x)log(1-x) gives " << Q << std::endl; + std::cout << "The exact integral is " << Q_expected << std::endl; + + // For an integral over the entire real line, use sinh-sinh quadrature: + sinh_sinh<double> sinh_integrator(tol, 10); + auto f2 = [](double t) { return cos(t)/cosh(t);}; + Q = sinh_integrator.integrate(f2); + Q_expected = pi<double>()/cosh(half_pi<double>()); + std::cout << "sinh_sinh quadrature of cos(x)/cosh(x) gives " << Q << std::endl; + std::cout << "The exact integral is " << Q_expected << std::endl; + + // For half-infinite intervals, use exp-sinh. + // Endpoint singularities are handled well: + exp_sinh<double> exp_integrator(tol, 10); + auto f3 = [](double t) { return exp(-t)/sqrt(t); }; + Q = exp_integrator.integrate(f3, 0, std::numeric_limits<double>::infinity()); + Q_expected = root_pi<double>(); + std::cout << "exp_sinh quadrature of exp(-t)/sqrt(t) gives " << Q << std::endl; + std::cout << "The exact integral is " << Q_expected << std::endl; + + + +} diff --git a/src/boost/libs/math/example/error_handling_example.cpp b/src/boost/libs/math/example/error_handling_example.cpp new file mode 100644 index 000000000..24543cdfa --- /dev/null +++ b/src/boost/libs/math/example/error_handling_example.cpp @@ -0,0 +1,153 @@ +// example_error_handling.cpp + +// Copyright Paul A. Bristow 2007, 2010. +// Copyright John Maddock 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook markup as well as code +// and comments, don't change any of the special comment markups! + +// Optional macro definitions described in text below: +// #define BOOST_MATH_DOMAIN_ERROR_POLICY ignore_error +// #define BOOST_MATH_DOMAIN_ERROR_POLICY errno_on_error +// #define BOOST_MATH_DOMAIN_ERROR_POLICY is set to: throw_on_error + +//[error_handling_example +/*` +The following example demonstrates the effect of +setting the macro BOOST_MATH_DOMAIN_ERROR_POLICY +when an invalid argument is encountered. For the +purposes of this example, we'll pass a negative +degrees of freedom parameter to the student's t +distribution. + +Since we know that this is a single file program we could +just add: + + #define BOOST_MATH_DOMAIN_ERROR_POLICY ignore_error + +to the top of the source file to change the default policy +to one that simply returns a NaN when a domain error occurs. +Alternatively we could use: + + #define BOOST_MATH_DOMAIN_ERROR_POLICY errno_on_error + +To ensure the `::errno` is set when a domain error occurs +as well as returning a NaN. + +This is safe provided the program consists of a single +translation unit /and/ we place the define /before/ any +#includes. Note that should we add the define after the includes +then it will have no effect! A warning such as: + +[pre warning C4005: 'BOOST_MATH_OVERFLOW_ERROR_POLICY' : macro redefinition] + +is a certain sign that it will /not/ have the desired effect. + +We'll begin our sample program with the needed includes: +*/ + + + #define BOOST_MATH_DOMAIN_ERROR_POLICY ignore_error + +// Boost +#include <boost/math/distributions/students_t.hpp> + using boost::math::students_t; // Probability of students_t(df, t). + +// std +#include <iostream> + using std::cout; + using std::endl; + +#include <stdexcept> + + +#include <cstddef> + // using ::errno + +/*` +Next we'll define the program's main() to call the student's t +distribution with an invalid degrees of freedom parameter, +the program is set up to handle either an exception or a NaN: +*/ + +int main() +{ + cout << "Example error handling using Student's t function. " << endl; + cout << "BOOST_MATH_DOMAIN_ERROR_POLICY is set to: " + << BOOST_STRINGIZE(BOOST_MATH_DOMAIN_ERROR_POLICY) << endl; + + double degrees_of_freedom = -1; // A bad argument! + double t = 10; + + try + { + errno = 0; // Clear/reset. + students_t dist(degrees_of_freedom); // exception is thrown here if enabled. + double p = cdf(dist, t); + // Test for error reported by other means: + if((boost::math::isnan)(p)) + { + cout << "cdf returned a NaN!" << endl; + if (errno != 0) + { // So errno has been set. + cout << "errno is set to: " << errno << endl; + } + } + else + cout << "Probability of Student's t is " << p << endl; + } + catch(const std::exception& e) + { + std::cout << + "\n""Message from thrown exception was:\n " << e.what() << std::endl; + } + return 0; +} // int main() + +/*` + +Here's what the program output looks like with a default build +(one that *does throw exceptions*): + +[pre +Example error handling using Student's t function. +BOOST_MATH_DOMAIN_ERROR_POLICY is set to: throw_on_error + +Message from thrown exception was: + Error in function boost::math::students_t_distribution<double>::students_t_distribution: + Degrees of freedom argument is -1, but must be > 0 ! +] + +Alternatively let's build with: + + #define BOOST_MATH_DOMAIN_ERROR_POLICY ignore_error + +Now the program output is: + +[pre +Example error handling using Student's t function. +BOOST_MATH_DOMAIN_ERROR_POLICY is set to: ignore_error +cdf returned a NaN! +] + +And finally let's build with: + + #define BOOST_MATH_DOMAIN_ERROR_POLICY errno_on_error + +Which gives the output show errno: + +[pre +Example error handling using Student's t function. +BOOST_MATH_DOMAIN_ERROR_POLICY is set to: errno_on_error +cdf returned a NaN! +errno is set to: 33 +] + +*/ + +//] [error_handling_eg end quickbook markup] diff --git a/src/boost/libs/math/example/error_policies_example.cpp b/src/boost/libs/math/example/error_policies_example.cpp new file mode 100644 index 000000000..289d1016b --- /dev/null +++ b/src/boost/libs/math/example/error_policies_example.cpp @@ -0,0 +1,105 @@ +// error_policies_example.cpp + +// Copyright Paul A. Bristow 2007, 2010. +// Copyright John Maddock 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/math/distributions/normal.hpp> + using boost::math::normal_distribution; + +#include <boost/math/distributions/students_t.hpp> + using boost::math::students_t; // Probability of students_t(df, t). + using boost::math::students_t_distribution; + +// using namespace boost::math; causes: +//.\error_policy_normal.cpp(30) : error C2872: 'policy' : ambiguous symbol +// could be '\boost/math/policies/policy.hpp(392) : boost::math::policies::policy' +// or 'boost::math::policies' + +// So should not use this 'using namespace boost::math;' command. + +// Suppose we want a statistical distribution to return infinities, +// rather than throw exceptions (the default policy), then we can use: + +// std +#include <iostream> + using std::cout; + using std::endl; + +// using namespace boost::math::policies; or + +using boost::math::policies::policy; +// Possible errors +using boost::math::policies::overflow_error; +using boost::math::policies::underflow_error; +using boost::math::policies::domain_error; +using boost::math::policies::pole_error; +using boost::math::policies::denorm_error; +using boost::math::policies::evaluation_error; +using boost::math::policies::ignore_error; + +// Define a custom policy to ignore just overflow: +typedef policy< +overflow_error<ignore_error> + > my_policy; + +// Define another custom policy (perhaps ill-advised?) +// to ignore all errors: domain, pole, overflow, underflow, denorm & evaluation: +typedef policy< +domain_error<ignore_error>, +pole_error<ignore_error>, +overflow_error<ignore_error>, +underflow_error<ignore_error>, +denorm_error<ignore_error>, +evaluation_error<ignore_error> + > my_ignoreall_policy; + +// Define a new distribution with a custom policy to ignore_error +// (& thus perhaps return infinity for some arguments): +typedef boost::math::normal_distribution<double, my_policy> my_normal; +// Note: uses default parameters zero mean and unit standard deviation. + +// We could also do the same for another distribution, for example: +using boost::math::students_t_distribution; +typedef students_t_distribution<double, my_ignoreall_policy> my_students_t; + +int main() +{ + cout << "quantile(my_normal(), 0.05); = " << quantile(my_normal(), 0.05) << endl; // 0.05 is argument within normal range. + cout << "quantile(my_normal(), 0.); = " << quantile(my_normal(), 0.) << endl; // argument zero, so expect infinity. + cout << "quantile(my_normal(), 0.); = " << quantile(my_normal(), 0.F) << endl; // argument zero, so expect infinity. + + cout << "quantile(my_students_t(), 0.); = " << quantile(my_students_t(-1), 0.F) << endl; // 'bad' argument negative, so expect NaN. + +#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS + // Construct a (0, 1) normal distribution that ignores all errors, + // returning NaN, infinity, zero, or best guess, + // and NOT setting errno. + normal_distribution<long double, my_ignoreall_policy> my_normal2(0.L, 1.L); // explicit parameters for distribution. + cout << "quantile(my_normal2(), 0.); = " << quantile(my_normal2, 0.01) << endl; // argument 0.01, so result finite. + cout << "quantile(my_normal2(), 0.); = " << quantile(my_normal2, 0.) << endl; // argument zero, so expect infinity. +#endif + + return 0; +} + +/* + +Output: + +error_policies_example.cpp + Generating code + Finished generating code + error_policy_normal_example.vcxproj -> J:\Cpp\MathToolkit\test\Math_test\Release\error_policies_example.exe + quantile(my_normal(), 0.05); = -1.64485 + quantile(my_normal(), 0.); = -1.#INF + quantile(my_normal(), 0.); = -1.#INF + quantile(my_students_t(), 0.); = 1.#QNAN + quantile(my_normal2(), 0.); = -2.32635 + quantile(my_normal2(), 0.); = -1.#INF + +*/ diff --git a/src/boost/libs/math/example/error_policy_example.cpp b/src/boost/libs/math/example/error_policy_example.cpp new file mode 100644 index 000000000..37cb51633 --- /dev/null +++ b/src/boost/libs/math/example/error_policy_example.cpp @@ -0,0 +1,93 @@ +// example_policy_handling.cpp + +// Copyright Paul A. Bristow 2007, 2010. +// Copyright John Maddock 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See error_handling_example.cpp for use of +// macro definition to change policy for +// domain_error - negative degrees of freedom argument +// for student's t distribution CDF, +// and catching the exception. + +// See error_handling_policies.cpp for more examples. + +// Boost +#include <boost/math/distributions/students_t.hpp> +using boost::math::students_t_distribution; // Probability of students_t(df, t). +using boost::math::students_t; // Probability of students_t(df, t) convenience typedef for double. + +using boost::math::policies::policy; +using boost::math::policies::domain_error; +using boost::math::policies::ignore_error; + +// std +#include <iostream> + using std::cout; + using std::endl; + +#include <stdexcept> + + +// Define a (bad?) policy to ignore domain errors ('bad' arguments): +typedef policy< + domain_error<ignore_error> + > my_policy; + +// Define my_students_t distribution with this different domain error policy: +typedef students_t_distribution<double, my_policy> my_students_t; + +int main() +{ // Example of error handling of bad argument(s) to a distribution. + cout << "Example error handling using Student's t function. " << endl; + + double degrees_of_freedom = -1; double t = -1.; // Two 'bad' arguments! + + try + { + cout << "Probability of ignore_error Student's t is " + << cdf(my_students_t(degrees_of_freedom), t) << endl; + cout << "Probability of default error policy Student's t is " << endl; + // By contrast the students_t distribution default domain error policy is to throw, + cout << cdf(students_t(-1), -1) << endl; // so this will throw. +/*` + Message from thrown exception was: + Error in function boost::math::students_t_distribution<double>::students_t_distribution: + Degrees of freedom argument is -1, but must be > 0 ! +*/ + + // We could also define a 'custom' distribution + // with an "ignore overflow error policy" in a single statement: + using boost::math::policies::overflow_error; + students_t_distribution<double, policy<overflow_error<ignore_error> > > students_t_no_throw(-1); + + } + catch(const std::exception& e) + { + std::cout << + "\n""Message from thrown exception was:\n " << e.what() << std::endl; + } + + return 0; +} // int main() + +/* + +Output: + + error_policy_example.cpp + Generating code + Finished generating code + error_policy_example.vcxproj -> J:\Cpp\MathToolkit\test\Math_test\Release\error_policy_example.exe + Example error handling using Student's t function. + Probability of ignore_error Student's t is 1.#QNAN + Probability of default error policy Student's t is + + Message from thrown exception was: + Error in function boost::math::students_t_distribution<double>::students_t_distribution: Degrees of freedom argument is -1, but must be > 0 ! + +*/ diff --git a/src/boost/libs/math/example/f_test.cpp b/src/boost/libs/math/example/f_test.cpp new file mode 100644 index 000000000..f7fabdee3 --- /dev/null +++ b/src/boost/libs/math/example/f_test.cpp @@ -0,0 +1,250 @@ +// Copyright John Maddock 2006 +// Copyright Paul A. Bristow 2007, 2008, 2010 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifdef _MSC_VER +# pragma warning(disable: 4512) // assignment operator could not be generated. +# pragma warning(disable: 4510) // default constructor could not be generated. +# pragma warning(disable: 4610) // can never be instantiated - user defined constructor required. +# pragma warning(disable: 4180) // qualifier has no effect (in Fusion). +#endif + +#include <iostream> +using std::cout; using std::endl; +using std::left; using std::fixed; using std::right; using std::scientific; +#include <iomanip> +using std::setw; +using std::setprecision; + +#include <boost/math/distributions/fisher_f.hpp> + +void f_test( + double sd1, // Sample 1 std deviation + double sd2, // Sample 2 std deviation + double N1, // Sample 1 size + double N2, // Sample 2 size + double alpha) // Significance level +{ + // + // An F test applied to two sets of data. + // We are testing the null hypothesis that the + // standard deviation of the samples is equal, and + // that any variation is down to chance. We can + // also test the alternative hypothesis that any + // difference is not down to chance. + // See http://www.itl.nist.gov/div898/handbook/eda/section3/eda359.htm + // + // Avoid "using namespace boost::math;" because of potential name ambiguity. + using boost::math::fisher_f; + + // Print header: + cout << + "____________________________________\n" + "F test for equal standard deviations\n" + "____________________________________\n\n"; + cout << setprecision(5); + cout << "Sample 1:\n"; + cout << setw(55) << left << "Number of Observations" << "= " << N1 << "\n"; + cout << setw(55) << left << "Sample Standard Deviation" << "= " << sd1 << "\n\n"; + cout << "Sample 2:\n"; + cout << setw(55) << left << "Number of Observations" << "= " << N2 << "\n"; + cout << setw(55) << left << "Sample Standard Deviation" << "= " << sd2 << "\n\n"; + // + // Now we can calculate and output some stats: + // + // F-statistic: + double F = (sd1 / sd2); + F *= F; + cout << setw(55) << left << "Test Statistic" << "= " << F << "\n\n"; + // + // Finally define our distribution, and get the probability: + // + fisher_f dist(N1 - 1, N2 - 1); + double p = cdf(dist, F); + cout << setw(55) << left << "CDF of test statistic: " << "= " + << setprecision(3) << scientific << p << "\n"; + double ucv = quantile(complement(dist, alpha)); + double ucv2 = quantile(complement(dist, alpha / 2)); + double lcv = quantile(dist, alpha); + double lcv2 = quantile(dist, alpha / 2); + cout << setw(55) << left << "Upper Critical Value at alpha: " << "= " + << setprecision(3) << scientific << ucv << "\n"; + cout << setw(55) << left << "Upper Critical Value at alpha/2: " << "= " + << setprecision(3) << scientific << ucv2 << "\n"; + cout << setw(55) << left << "Lower Critical Value at alpha: " << "= " + << setprecision(3) << scientific << lcv << "\n"; + cout << setw(55) << left << "Lower Critical Value at alpha/2: " << "= " + << setprecision(3) << scientific << lcv2 << "\n\n"; + // + // Finally print out results of null and alternative hypothesis: + // + cout << setw(55) << left << + "Results for Alternative Hypothesis and alpha" << "= " + << setprecision(4) << fixed << alpha << "\n\n"; + cout << "Alternative Hypothesis Conclusion\n"; + cout << "Standard deviations are unequal (two sided test) "; + if((ucv2 < F) || (lcv2 > F)) + cout << "NOT REJECTED\n"; + else + cout << "REJECTED\n"; + cout << "Standard deviation 1 is less than standard deviation 2 "; + if(lcv > F) + cout << "NOT REJECTED\n"; + else + cout << "REJECTED\n"; + cout << "Standard deviation 1 is greater than standard deviation 2 "; + if(ucv < F) + cout << "NOT REJECTED\n"; + else + cout << "REJECTED\n"; + cout << endl << endl; +} + +int main() +{ + // + // Run tests for ceramic strength data: + // see http://www.itl.nist.gov/div898/handbook/eda/section4/eda42a1.htm + // The data for this case study were collected by Said Jahanmir of the + // NIST Ceramics Division in 1996 in connection with a NIST/industry + // ceramics consortium for strength optimization of ceramic strength. + // + f_test(65.54909, 61.85425, 240, 240, 0.05); + // + // And again for the process change comparison: + // see http://www.itl.nist.gov/div898/handbook/prc/section3/prc32.htm + // A new procedure to assemble a device is introduced and tested for + // possible improvement in time of assembly. The question being addressed + // is whether the standard deviation of the new assembly process (sample 2) is + // better (i.e., smaller) than the standard deviation for the old assembly + // process (sample 1). + // + f_test(4.9082, 2.5874, 11, 9, 0.05); + return 0; +} + +/* + +Output: + + f_test.cpp + F-test_example1.vcxproj -> J:\Cpp\MathToolkit\test\Math_test\Debug\F_test_example1.exe + ____________________________________ + F test for equal standard deviations + ____________________________________ + + Sample 1: + Number of Observations = 240 + Sample Standard Deviation = 65.549 + + Sample 2: + Number of Observations = 240 + Sample Standard Deviation = 61.854 + + Test Statistic = 1.123 + + CDF of test statistic: = 8.148e-001 + Upper Critical Value at alpha: = 1.238e+000 + Upper Critical Value at alpha/2: = 1.289e+000 + Lower Critical Value at alpha: = 8.080e-001 + Lower Critical Value at alpha/2: = 7.756e-001 + + Results for Alternative Hypothesis and alpha = 0.0500 + + Alternative Hypothesis Conclusion + Standard deviations are unequal (two sided test) REJECTED + Standard deviation 1 is less than standard deviation 2 REJECTED + Standard deviation 1 is greater than standard deviation 2 REJECTED + + + ____________________________________ + F test for equal standard deviations + ____________________________________ + + Sample 1: + Number of Observations = 11.00000 + Sample Standard Deviation = 4.90820 + + Sample 2: + Number of Observations = 9.00000 + Sample Standard Deviation = 2.58740 + + Test Statistic = 3.59847 + + CDF of test statistic: = 9.589e-001 + Upper Critical Value at alpha: = 3.347e+000 + Upper Critical Value at alpha/2: = 4.295e+000 + Lower Critical Value at alpha: = 3.256e-001 + Lower Critical Value at alpha/2: = 2.594e-001 + + Results for Alternative Hypothesis and alpha = 0.0500 + + Alternative Hypothesis Conclusion + Standard deviations are unequal (two sided test) REJECTED + Standard deviation 1 is less than standard deviation 2 REJECTED + Standard deviation 1 is greater than standard deviation 2 NOT REJECTED + + + ____________________________________ + F test for equal standard deviations + ____________________________________ + + Sample 1: + Number of Observations = 240 + Sample Standard Deviation = 65.549 + + Sample 2: + Number of Observations = 240 + Sample Standard Deviation = 61.854 + + Test Statistic = 1.123 + + CDF of test statistic: = 8.148e-001 + Upper Critical Value at alpha: = 1.238e+000 + Upper Critical Value at alpha/2: = 1.289e+000 + Lower Critical Value at alpha: = 8.080e-001 + Lower Critical Value at alpha/2: = 7.756e-001 + + Results for Alternative Hypothesis and alpha = 0.0500 + + Alternative Hypothesis Conclusion + Standard deviations are unequal (two sided test) REJECTED + Standard deviation 1 is less than standard deviation 2 REJECTED + Standard deviation 1 is greater than standard deviation 2 REJECTED + + + ____________________________________ + F test for equal standard deviations + ____________________________________ + + Sample 1: + Number of Observations = 11.00000 + Sample Standard Deviation = 4.90820 + + Sample 2: + Number of Observations = 9.00000 + Sample Standard Deviation = 2.58740 + + Test Statistic = 3.59847 + + CDF of test statistic: = 9.589e-001 + Upper Critical Value at alpha: = 3.347e+000 + Upper Critical Value at alpha/2: = 4.295e+000 + Lower Critical Value at alpha: = 3.256e-001 + Lower Critical Value at alpha/2: = 2.594e-001 + + Results for Alternative Hypothesis and alpha = 0.0500 + + Alternative Hypothesis Conclusion + Standard deviations are unequal (two sided test) REJECTED + Standard deviation 1 is less than standard deviation 2 REJECTED + Standard deviation 1 is greater than standard deviation 2 NOT REJECTED + + + +*/ + diff --git a/src/boost/libs/math/example/factorial_example.cpp b/src/boost/libs/math/example/factorial_example.cpp new file mode 100644 index 000000000..7a51e0746 --- /dev/null +++ b/src/boost/libs/math/example/factorial_example.cpp @@ -0,0 +1,97 @@ +// TestFactorial.cpp +// +// Factorials and Binomial Coefficients. +// +// Copyright Datasim Education BV 2009-2010 +// Copyright John Maddock and Paul A. Bristow 2010 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/math/special_functions/factorials.hpp> +#include <boost/math/special_functions.hpp> + +#include <iostream> +using namespace std; + +int main() +{ + using namespace boost::math; + + // Factorials + unsigned int n = 3; + + try + { + cout << "Factorial: " << factorial<double>(n) << endl; + + // Caution: You must provide a return type template value, so this will not compile + // unsigned int nfac = factorial(n); // could not deduce template argument for 'T' + // You must provide an explicit floating-point (not integer) return type. + // If you do provide an integer type, like this: + // unsigned int uintfac = factorial<unsigned int>(n); + // you will also get a compile error, for MSVC C2338. + // If you really want an integer type, you can convert from double: + unsigned int intfac = static_cast<unsigned int>(factorial<double>(n)); + // this will be exact, until the result of the factorial overflows the integer type. + + cout << "Unchecked factorial: " << boost::math::unchecked_factorial<float>(n) << endl; + // Note: + // unsigned int unfac = boost::math::unchecked_factorial<unsigned int>(n); + // also fails to compile for the same reasons. + } + catch(exception& e) + { + cout << e.what() << endl; + } + + // Double factorial n!! + try + { + //cout << "Double factorial: " << boost::math::double_factorial<unsigned>(n); + } + catch(exception& e) + { + cout << e.what() << endl; + } + + // Rising and falling factorials + try + { + int i = 2; double x = 8; + cout << "Rising factorial: " << rising_factorial(x,i) << endl; + cout << "Falling factorial: " << falling_factorial(x,i) << endl; + } + catch(exception& e) + { + cout << e.what() << endl; + } + + // Binomial coefficients + try + { + unsigned n = 10; unsigned k = 2; + // cout << "Binomial coefficient: " << boost::math::binomial_coefficient<unsigned>(n,k) << endl; + } + catch(exception& e) + { + cout << e.what() << endl; + } + return 0; +} + +/* + +Output: + + factorial_example.vcxproj -> J:\Cpp\MathToolkit\test\Math_test\Release\factorial_example.exe + Factorial: 6 + Unchecked factorial: 6 + Rising factorial: 72 + Falling factorial: 56 + +*/ + + diff --git a/src/boost/libs/math/example/fft_sines_table.cpp b/src/boost/libs/math/example/fft_sines_table.cpp new file mode 100644 index 000000000..82345f0d8 --- /dev/null +++ b/src/boost/libs/math/example/fft_sines_table.cpp @@ -0,0 +1,270 @@ +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Copyright Paul A. Bristow 2013. +// Copyright Christopher Kormanyos 2012, 2013. +// Copyright John Maddock 2013. + +// This file is written to be included from a Quickbook .qbk document. +// It can be compiled by the C++ compiler, and run. Any output can +// also be added here as comment or included or pasted in elsewhere. +// Caution: this file contains Quickbook markup as well as code +// and comments: don't change any of the special comment markups! + +#ifdef _MSC_VER +# pragma warning (disable : 4996) // -D_SCL_SECURE_NO_WARNINGS. +#endif + +//[fft_sines_table_example_1 + +/*`[h5 Using Boost.Multiprecision to generate a high-precision array of sine coefficients for use with FFT.] + +The Boost.Multiprecision library can be used for computations requiring precision +exceeding that of standard built-in types such as `float`, `double` +and `long double`. For extended-precision calculations, Boost.Multiprecision +supplies a template data type called `cpp_bin_float`. The number of decimal +digits of precision is fixed at compile-time via a template parameter. + +One often needs to compute tables of numbers in mathematical software. +To avoid the +[@https://en.wikipedia.org/wiki/Rounding#Table-maker's_dilemma Table-maker's dilemma] +it is necessary to use a higher precision type to compute the table values so that they have +the nearest representable bit-pattern for the type, say `double`, of the table value. + +This example is a program `fft_since_table.cpp` that writes a header file `sines.hpp` +containing an array of sine coefficients for use with a Fast Fourier Transform (FFT), +that can be included by the FFT program. + +To use Boost.Multiprecision's high-precision floating-point types and constants, we need some includes: +*/ +#include <boost/math/constants/constants.hpp> +// using boost::math::constants::pi; + +#include <boost/multiprecision/cpp_bin_float.hpp> // for +// using boost::multiprecision::cpp_bin_float and +// using boost::multiprecision::cpp_bin_float_50; +// using boost::multiprecision::cpp_bin_float_quad; + +#include <boost/array.hpp> // or <array> for std::array + +#include <iostream> +#include <limits> +#include <vector> +#include <algorithm> +#include <iomanip> +#include <iterator> +#include <fstream> + +/*`First, this example defines a prolog text string which is a C++ comment with the program licence, copyright etc. +(You would of course, tailor this to your needs, including *your* copyright claim). +This will appear at the top of the written header file `sines.hpp`. +*/ + +//] [fft_sines_table_example_1] + +static const char* prolog = +{ + "// Use, modification and distribution are subject to the\n" + "// Boost Software License, Version 1.0.\n" + "// (See accompanying file LICENSE_1_0.txt\n" + "// or copy at ""http://www.boost.org/LICENSE_1_0.txt)\n\n" + + "// Copyright A N Other, 2019.\n\n" +}; + +//[fft_sines_table_example_2 + +using boost::multiprecision::cpp_bin_float_50; +using boost::math::constants::pi; + +//] [fft_sines_table_example_2] + +// VS 2010 (wrongly) requires these at file scope, not local scope in `main`. +// This program also requires `-std=c++11` option to compile using Clang and GCC. + +int main() +{ +//[fft_sines_table_example_3 +/*`A fast Fourier transform (FFT), for example, may use a table of the values of +sin(([pi]/2[super n]) in its implementation details. In order to maximize the precision in +the FFT implementation, the precision of the tabulated trigonometric values +should exceed that of the built-in floating-point type used in the FFT. + +The sample below computes a table of the values of sin([pi]/2[super n]) +in the range 1 <= n <= 31. + +This program makes use of, among other program elements, the data type +`boost::multiprecision::cpp_bin_float_50` +for a precision of 50 decimal digits from Boost.Multiprecision, +the value of constant [pi] retrieved from Boost.Math, +guaranteed to be initialized with the very last bit of precision for the type, +here `cpp_bin_float_50`, +and a C++11 lambda function combined with `std::for_each()`. +*/ + +/*`define the number of values (32) in the array of sines. +*/ + + std::size_t size = 32U; + //cpp_bin_float_50 p = pi<cpp_bin_float_50>(); + cpp_bin_float_50 p = boost::math::constants::pi<cpp_bin_float_50>(); + + std::vector <cpp_bin_float_50> sin_values (size); + unsigned n = 1U; + // Generate the sine values. + std::for_each + ( + sin_values.begin (), + sin_values.end (), + [&n](cpp_bin_float_50& y) + { + y = sin( pi<cpp_bin_float_50>() / pow(cpp_bin_float_50 (2), n)); + ++n; + } + ); + +/*`Define the floating-point type for the generated file, either built-in +`double, `float, or `long double`, or a user defined type like `cpp_bin_float_50`. +*/ + +std::string fp_type = "double"; + +std::cout << "Generating an `std::array` or `boost::array` for floating-point type: " + << fp_type << ". " << std::endl; + +/*`By default, output would only show the standard 6 decimal digits, +so set precision to show enough significant digits for the chosen floating-point type. +For `cpp_bin_float_50` is 50. (50 decimal digits should be ample for most applications). + +*/ + std::streamsize precision = std::numeric_limits<cpp_bin_float_50>::digits10; + + std::cout << "Sines table precision is " << precision << " decimal digits. " << std::endl; + +/*`Of course, one could also choose a lower precision for the table values, for example, + +`std::streamsize precision = std::numeric_limits<cpp_bin_float_quad>::max_digits10;` + +128-bit 'quad' precision of 36 decimal digits would be sufficient +for the most precise current `long double` implementations using 128-bit. +In general, it should be a couple of decimal digits more (guard digits) than +`std::numeric_limits<RealType>::max_digits10` for the target system floating-point type. +(If the implementation does not provide `max_digits10`, the the Kahan formula +`std::numeric_limits<RealType>::digits * 3010/10000 + 2` can be used instead). + +The compiler will read these values as decimal digits strings and +use the nearest representation for the floating-point type. + +Now output all the sine table, to a file of your chosen name. +*/ + const char sines_name[] = "sines.hpp"; // Assuming in same directory as .exe + + std::ofstream fout(sines_name, std::ios_base::out); // Creates if no file exists, + // & uses default overwrite/ ios::replace. + if (fout.is_open() == false) + { // failed to open OK! + std::cout << "Open file " << sines_name << " failed!" << std::endl; + return EXIT_FAILURE; + } + else + { // Write prolog etc as a C++ comment. + std::cout << "Open file " << sines_name << " for output OK." << std::endl; + fout << prolog + << "// Table of " << sin_values.size() << " values with " + << precision << " decimal digits precision,\n" + "// generated by program fft_sines_table.cpp.\n" << std::endl; + + fout << "#include <array> // std::array" << std::endl; + + // Write the table of sines as a C++ array. + fout << "\nstatic const std::array<double, " << size << "> sines =\n" + "{{\n"; // 2nd { needed for some old GCC compiler versions. + fout.precision(precision); + + for (unsigned int i = 0U; ;) + { + fout << " " << sin_values[i]; + if (i == sin_values.size()-1) + { // next is last value. + fout << "\n}}; // array sines\n"; // 2nd } needed for some old GCC compiler versions. + break; + } + else + { + fout << ",\n"; + i++; + } + } // for + + fout.close(); + std::cout << "Closed file " << sines_name << " for output." << std::endl; + } +//`The output file generated can be seen at [@../../example/sines.hpp] + +//] [/fft_sines_table_example_3] + + return EXIT_SUCCESS; + +} // int main() + +/* +//[fft_sines_table_example_output + +The printed table is: + + 1 + 0.70710678118654752440084436210484903928483593768847 + 0.38268343236508977172845998403039886676134456248563 + 0.19509032201612826784828486847702224092769161775195 + 0.098017140329560601994195563888641845861136673167501 + 0.049067674327418014254954976942682658314745363025753 + 0.024541228522912288031734529459282925065466119239451 + 0.012271538285719926079408261951003212140372319591769 + 0.0061358846491544753596402345903725809170578863173913 + 0.003067956762965976270145365490919842518944610213452 + 0.0015339801862847656123036971502640790799548645752374 + 0.00076699031874270452693856835794857664314091945206328 + 0.00038349518757139558907246168118138126339502603496474 + 0.00019174759731070330743990956198900093346887403385916 + 9.5873799095977345870517210976476351187065612851145e-05 + 4.7936899603066884549003990494658872746866687685767e-05 + 2.3968449808418218729186577165021820094761474895673e-05 + 1.1984224905069706421521561596988984804731977538387e-05 + 5.9921124526424278428797118088908617299871778780951e-06 + 2.9960562263346607504548128083570598118251878683408e-06 + 1.4980281131690112288542788461553611206917585861527e-06 + 7.4901405658471572113049856673065563715595930217207e-07 + 3.7450702829238412390316917908463317739740476297248e-07 + 1.8725351414619534486882457659356361712045272098287e-07 + 9.3626757073098082799067286680885620193236507169473e-08 + 4.681337853654909269511551813854009695950362701667e-08 + 2.3406689268274552759505493419034844037886207223779e-08 + 1.1703344634137277181246213503238103798093456639976e-08 + 5.8516723170686386908097901008341396943900085051757e-09 + 2.9258361585343193579282304690689559020175857150074e-09 + 1.4629180792671596805295321618659637103742615227834e-09 +*/ + +//] [/fft_sines_table_example_output] + +//[fft_sines_table_example_check + +/*` +The output can be copied as text and readily integrated into a given source +code. Alternatively, the output can be written to a text or even be used +within a self-written automatic code generator as this example. + +A computer algebra system can be used to verify the results obtained from +Boost.Math and Boost.Multiprecision. For example, the __Mathematica +computer algebra system can obtain a similar table with the command: + + Table[N[Sin[Pi / (2^n)], 50], {n, 1, 31, 1}] + +The __WolframAlpha computational knowledge engine can also be used to generate +this table. The same command can be pasted into the compute box. + +*/ + +//] [/fft_sines_table_example_check] diff --git a/src/boost/libs/math/example/find_location_example.cpp b/src/boost/libs/math/example/find_location_example.cpp new file mode 100644 index 000000000..c9ce58d62 --- /dev/null +++ b/src/boost/libs/math/example/find_location_example.cpp @@ -0,0 +1,174 @@ +// find_location.cpp + +// Copyright Paul A. Bristow 2008, 2010. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Example of finding location (mean) +// for normal (Gaussian) & Cauchy distribution. + +// Note that this file contains Quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +//#ifdef _MSC_VER +//# pragma warning(disable: 4180) // qualifier has no effect (in Fusion). +//#endif + +//[find_location1 +/*` +First we need some includes to access the normal distribution, +the algorithms to find location (and some std output of course). +*/ + +#include <boost/math/distributions/normal.hpp> // for normal_distribution + using boost::math::normal; // typedef provides default type is double. +#include <boost/math/distributions/cauchy.hpp> // for cauchy_distribution + using boost::math::cauchy; // typedef provides default type is double. +#include <boost/math/distributions/find_location.hpp> + using boost::math::find_location; // for mean +#include <boost/math/distributions/find_scale.hpp> + using boost::math::find_scale; // for standard deviation + using boost::math::complement; // Needed if you want to use the complement version. + using boost::math::policies::policy; + +#include <iostream> + using std::cout; using std::endl; +#include <iomanip> + using std::setw; using std::setprecision; +#include <limits> + using std::numeric_limits; + +//] [/find_location1] + +int main() +{ + cout << "Example: Find location (or mean)." << endl; + try + { +//[find_location2 +/*` +For this example, we will use the standard normal distribution, +with mean (location) zero and standard deviation (scale) unity. +This is also the default for this implementation. +*/ + normal N01; // Default 'standard' normal distribution with zero mean and + double sd = 1.; // normal default standard deviation is 1. +/*`Suppose we want to find a different normal distribution whose mean is shifted +so that only fraction p (here 0.001 or 0.1%) are below a certain chosen limit +(here -2, two standard deviations). +*/ + double z = -2.; // z to give prob p + double p = 0.001; // only 0.1% below z + + cout << "Normal distribution with mean = " << N01.location() + << ", standard deviation " << N01.scale() + << ", has " << "fraction <= " << z + << ", p = " << cdf(N01, z) << endl; + cout << "Normal distribution with mean = " << N01.location() + << ", standard deviation " << N01.scale() + << ", has " << "fraction > " << z + << ", p = " << cdf(complement(N01, z)) << endl; // Note: uses complement. +/*` +[pre +Normal distribution with mean = 0, standard deviation 1, has fraction <= -2, p = 0.0227501 +Normal distribution with mean = 0, standard deviation 1, has fraction > -2, p = 0.97725 +] +We can now use ''find_location'' to give a new offset mean. +*/ + double l = find_location<normal>(z, p, sd); + cout << "offset location (mean) = " << l << endl; +/*` +that outputs: +[pre +offset location (mean) = 1.09023 +] +showing that we need to shift the mean just over one standard deviation from its previous value of zero. + +Then we can check that we have achieved our objective +by constructing a new distribution +with the offset mean (but same standard deviation): +*/ + normal np001pc(l, sd); // Same standard_deviation (scale) but with mean (location) shifted. +/*` +And re-calculating the fraction below our chosen limit. +*/ +cout << "Normal distribution with mean = " << l + << " has " << "fraction <= " << z + << ", p = " << cdf(np001pc, z) << endl; + cout << "Normal distribution with mean = " << l + << " has " << "fraction > " << z + << ", p = " << cdf(complement(np001pc, z)) << endl; +/*` +[pre +Normal distribution with mean = 1.09023 has fraction <= -2, p = 0.001 +Normal distribution with mean = 1.09023 has fraction > -2, p = 0.999 +] + +[h4 Controlling Error Handling from find_location] +We can also control the policy for handling various errors. +For example, we can define a new (possibly unwise) +policy to ignore domain errors ('bad' arguments). + +Unless we are using the boost::math namespace, we will need: +*/ + using boost::math::policies::policy; + using boost::math::policies::domain_error; + using boost::math::policies::ignore_error; + +/*` +Using a typedef is often convenient, especially if it is re-used, +although it is not required, as the various examples below show. +*/ + typedef policy<domain_error<ignore_error> > ignore_domain_policy; + // find_location with new policy, using typedef. + l = find_location<normal>(z, p, sd, ignore_domain_policy()); + // Default policy policy<>, needs "using boost::math::policies::policy;" + l = find_location<normal>(z, p, sd, policy<>()); + // Default policy, fully specified. + l = find_location<normal>(z, p, sd, boost::math::policies::policy<>()); + // A new policy, ignoring domain errors, without using a typedef. + l = find_location<normal>(z, p, sd, policy<domain_error<ignore_error> >()); +/*` +If we want to use a probability that is the __complements of our probability, +we should not even think of writing `find_location<normal>(z, 1 - p, sd)`, +but use the complement version, see __why_complements. +*/ + z = 2.; + double q = 0.95; // = 1 - p; // complement. + l = find_location<normal>(complement(z, q, sd)); + + normal np95pc(l, sd); // Same standard_deviation (scale) but with mean(location) shifted + cout << "Normal distribution with mean = " << l << " has " + << "fraction <= " << z << " = " << cdf(np95pc, z) << endl; + cout << "Normal distribution with mean = " << l << " has " + << "fraction > " << z << " = " << cdf(complement(np95pc, z)) << endl; + //] [/find_location2] + } + catch(const std::exception& e) + { // Always useful to include try & catch blocks because default policies + // are to throw exceptions on arguments that cause errors like underflow, overflow. + // Lacking try & catch blocks, the program will abort without a message below, + // which may give some helpful clues as to the cause of the exception. + std::cout << + "\n""Message from thrown exception was:\n " << e.what() << std::endl; + } + return 0; +} // int main() + +//[find_location_example_output +/*` +[pre +Example: Find location (mean). +Normal distribution with mean = 0, standard deviation 1, has fraction <= -2, p = 0.0227501 +Normal distribution with mean = 0, standard deviation 1, has fraction > -2, p = 0.97725 +offset location (mean) = 1.09023 +Normal distribution with mean = 1.09023 has fraction <= -2, p = 0.001 +Normal distribution with mean = 1.09023 has fraction > -2, p = 0.999 +Normal distribution with mean = 0.355146 has fraction <= 2 = 0.95 +Normal distribution with mean = 0.355146 has fraction > 2 = 0.05 +] +*/ +//] [/find_location_example_output] diff --git a/src/boost/libs/math/example/find_mean_and_sd_normal.cpp b/src/boost/libs/math/example/find_mean_and_sd_normal.cpp new file mode 100644 index 000000000..752c06a7f --- /dev/null +++ b/src/boost/libs/math/example/find_mean_and_sd_normal.cpp @@ -0,0 +1,413 @@ +// find_mean_and_sd_normal.cpp + +// Copyright Paul A. Bristow 2007, 2010. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Example of finding mean or sd for normal distribution. + +// Note that this file contains Quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +//[normal_std +/*` +First we need some includes to access the normal distribution, +the algorithms to find location and scale +(and some std output of course). +*/ + +#include <boost/math/distributions/normal.hpp> // for normal_distribution + using boost::math::normal; // typedef provides default type is double. +#include <boost/math/distributions/cauchy.hpp> // for cauchy_distribution + using boost::math::cauchy; // typedef provides default type is double. +#include <boost/math/distributions/find_location.hpp> + using boost::math::find_location; +#include <boost/math/distributions/find_scale.hpp> + using boost::math::find_scale; + using boost::math::complement; + using boost::math::policies::policy; + +#include <iostream> + using std::cout; using std::endl; using std::left; using std::showpoint; using std::noshowpoint; +#include <iomanip> + using std::setw; using std::setprecision; +#include <limits> + using std::numeric_limits; +#include <stdexcept> + +//] [/normal_std Quickbook] + +int main() +{ + cout << "Find_location (mean) and find_scale (standard deviation) examples." << endl; + try + { + +//[normal_find_location_and_scale_eg + +/*` +[h4 Using find_location and find_scale to meet dispensing and measurement specifications] + +Consider an example from K Krishnamoorthy, +Handbook of Statistical Distributions with Applications, +ISBN 1-58488-635-8, (2006) p 126, example 10.3.7. + +"A machine is set to pack 3 kg of ground beef per pack. +Over a long period of time it is found that the average packed was 3 kg +with a standard deviation of 0.1 kg. +Assume the packing is normally distributed." + +We start by constructing a normal distribution with the given parameters: +*/ + +double mean = 3.; // kg +double standard_deviation = 0.1; // kg +normal packs(mean, standard_deviation); +/*`We can then find the fraction (or %) of packages that weigh more than 3.1 kg. +*/ + +double max_weight = 3.1; // kg +cout << "Percentage of packs > " << max_weight << " is " +<< cdf(complement(packs, max_weight)) * 100. << endl; // P(X > 3.1) + +/*`We might want to ensure that 95% of packs are over a minimum weight specification, +then we want the value of the mean such that P(X < 2.9) = 0.05. + +Using the mean of 3 kg, we can estimate +the fraction of packs that fail to meet the specification of 2.9 kg. +*/ + +double minimum_weight = 2.9; +cout <<"Fraction of packs <= " << minimum_weight << " with a mean of " << mean + << " is " << cdf(complement(packs, minimum_weight)) << endl; +// fraction of packs <= 2.9 with a mean of 3 is 0.841345 + +/*`This is 0.84 - more than the target fraction of 0.95. +If we want 95% to be over the minimum weight, +what should we set the mean weight to be? + +Using the KK StatCalc program supplied with the book and the method given on page 126 gives 3.06449. + +We can confirm this by constructing a new distribution which we call 'xpacks' +with a safety margin mean of 3.06449 thus: +*/ +double over_mean = 3.06449; +normal xpacks(over_mean, standard_deviation); +cout << "Fraction of packs >= " << minimum_weight +<< " with a mean of " << xpacks.mean() + << " is " << cdf(complement(xpacks, minimum_weight)) << endl; +// fraction of packs >= 2.9 with a mean of 3.06449 is 0.950005 + +/*`Using this Math Toolkit, we can calculate the required mean directly thus: +*/ +double under_fraction = 0.05; // so 95% are above the minimum weight mean - sd = 2.9 +double low_limit = standard_deviation; +double offset = mean - low_limit - quantile(packs, under_fraction); +double nominal_mean = mean + offset; +// mean + (mean - low_limit - quantile(packs, under_fraction)); + +normal nominal_packs(nominal_mean, standard_deviation); +cout << "Setting the packer to " << nominal_mean << " will mean that " + << "fraction of packs >= " << minimum_weight + << " is " << cdf(complement(nominal_packs, minimum_weight)) << endl; +// Setting the packer to 3.06449 will mean that fraction of packs >= 2.9 is 0.95 + +/*` +This calculation is generalized as the free function called `find_location`, +see __algorithms. + +To use this we will need to +*/ + +#include <boost/math/distributions/find_location.hpp> + using boost::math::find_location; +/*`and then use find_location function to find safe_mean, +& construct a new normal distribution called 'goodpacks'. +*/ +double safe_mean = find_location<normal>(minimum_weight, under_fraction, standard_deviation); +normal good_packs(safe_mean, standard_deviation); +/*`with the same confirmation as before: +*/ +cout << "Setting the packer to " << nominal_mean << " will mean that " + << "fraction of packs >= " << minimum_weight + << " is " << cdf(complement(good_packs, minimum_weight)) << endl; +// Setting the packer to 3.06449 will mean that fraction of packs >= 2.9 is 0.95 + +/*` +[h4 Using Cauchy-Lorentz instead of normal distribution] + +After examining the weight distribution of a large number of packs, we might decide that, +after all, the assumption of a normal distribution is not really justified. +We might find that the fit is better to a __cauchy_distrib. +This distribution has wider 'wings', so that whereas most of the values +are closer to the mean than the normal, there are also more values than 'normal' +that lie further from the mean than the normal. + +This might happen because a larger than normal lump of meat is either included or excluded. + +We first create a __cauchy_distrib with the original mean and standard deviation, +and estimate the fraction that lie below our minimum weight specification. +*/ + +cauchy cpacks(mean, standard_deviation); +cout << "Cauchy Setting the packer to " << mean << " will mean that " + << "fraction of packs >= " << minimum_weight + << " is " << cdf(complement(cpacks, minimum_weight)) << endl; +// Cauchy Setting the packer to 3 will mean that fraction of packs >= 2.9 is 0.75 + +/*`Note that far fewer of the packs meet the specification, only 75% instead of 95%. +Now we can repeat the find_location, using the cauchy distribution as template parameter, +in place of the normal used above. +*/ + +double lc = find_location<cauchy>(minimum_weight, under_fraction, standard_deviation); +cout << "find_location<cauchy>(minimum_weight, over fraction, standard_deviation); " << lc << endl; +// find_location<cauchy>(minimum_weight, over fraction, packs.standard_deviation()); 3.53138 +/*`Note that the safe_mean setting needs to be much higher, 3.53138 instead of 3.06449, +so we will make rather less profit. + +And again confirm that the fraction meeting specification is as expected. +*/ +cauchy goodcpacks(lc, standard_deviation); +cout << "Cauchy Setting the packer to " << lc << " will mean that " + << "fraction of packs >= " << minimum_weight + << " is " << cdf(complement(goodcpacks, minimum_weight)) << endl; +// Cauchy Setting the packer to 3.53138 will mean that fraction of packs >= 2.9 is 0.95 + +/*`Finally we could estimate the effect of a much tighter specification, +that 99% of packs met the specification. +*/ + +cout << "Cauchy Setting the packer to " + << find_location<cauchy>(minimum_weight, 0.99, standard_deviation) + << " will mean that " + << "fraction of packs >= " << minimum_weight + << " is " << cdf(complement(goodcpacks, minimum_weight)) << endl; + +/*`Setting the packer to 3.13263 will mean that fraction of packs >= 2.9 is 0.99, +but will more than double the mean loss from 0.0644 to 0.133 kg per pack. + +Of course, this calculation is not limited to packs of meat, it applies to dispensing anything, +and it also applies to a 'virtual' material like any measurement. + +The only caveat is that the calculation assumes that the standard deviation (scale) is known with +a reasonably low uncertainty, something that is not so easy to ensure in practice. +And that the distribution is well defined, __normal_distrib or __cauchy_distrib, or some other. + +If one is simply dispensing a very large number of packs, +then it may be feasible to measure the weight of hundreds or thousands of packs. +With a healthy 'degrees of freedom', the confidence intervals for the standard deviation +are not too wide, typically about + and - 10% for hundreds of observations. + +For other applications, where it is more difficult or expensive to make many observations, +the confidence intervals are depressingly wide. + +See [link math_toolkit.stat_tut.weg.cs_eg.chi_sq_intervals Confidence Intervals on the standard deviation] +for a worked example +[@../../example/chi_square_std_dev_test.cpp chi_square_std_dev_test.cpp] +of estimating these intervals. + + +[h4 Changing the scale or standard deviation] + +Alternatively, we could invest in a better (more precise) packer +(or measuring device) with a lower standard deviation, or scale. + +This might cost more, but would reduce the amount we have to 'give away' +in order to meet the specification. + +To estimate how much better (how much smaller standard deviation) it would have to be, +we need to get the 5% quantile to be located at the under_weight limit, 2.9 +*/ +double p = 0.05; // wanted p th quantile. +cout << "Quantile of " << p << " = " << quantile(packs, p) + << ", mean = " << packs.mean() << ", sd = " << packs.standard_deviation() << endl; +/*` +Quantile of 0.05 = 2.83551, mean = 3, sd = 0.1 + +With the current packer (mean = 3, sd = 0.1), the 5% quantile is at 2.8551 kg, +a little below our target of 2.9 kg. +So we know that the standard deviation is going to have to be smaller. + +Let's start by guessing that it (now 0.1) needs to be halved, to a standard deviation of 0.05 kg. +*/ +normal pack05(mean, 0.05); +cout << "Quantile of " << p << " = " << quantile(pack05, p) + << ", mean = " << pack05.mean() << ", sd = " << pack05.standard_deviation() << endl; +// Quantile of 0.05 = 2.91776, mean = 3, sd = 0.05 + +cout <<"Fraction of packs >= " << minimum_weight << " with a mean of " << mean + << " and standard deviation of " << pack05.standard_deviation() + << " is " << cdf(complement(pack05, minimum_weight)) << endl; +// Fraction of packs >= 2.9 with a mean of 3 and standard deviation of 0.05 is 0.97725 +/*` +So 0.05 was quite a good guess, but we are a little over the 2.9 target, +so the standard deviation could be a tiny bit more. So we could do some +more guessing to get closer, say by increasing standard deviation to 0.06 kg, +constructing another new distribution called pack06. +*/ +normal pack06(mean, 0.06); +cout << "Quantile of " << p << " = " << quantile(pack06, p) + << ", mean = " << pack06.mean() << ", sd = " << pack06.standard_deviation() << endl; +// Quantile of 0.05 = 2.90131, mean = 3, sd = 0.06 + +cout <<"Fraction of packs >= " << minimum_weight << " with a mean of " << mean + << " and standard deviation of " << pack06.standard_deviation() + << " is " << cdf(complement(pack06, minimum_weight)) << endl; +// Fraction of packs >= 2.9 with a mean of 3 and standard deviation of 0.06 is 0.95221 +/*` +Now we are getting really close, but to do the job properly, +we might need to use root finding method, for example the tools provided, +and used elsewhere, in the Math Toolkit, see __root_finding_without_derivatives + +But in this (normal) distribution case, we can and should be even smarter +and make a direct calculation. +*/ + +/*`Our required limit is minimum_weight = 2.9 kg, often called the random variate z. +For a standard normal distribution, then probability p = N((minimum_weight - mean) / sd). + +We want to find the standard deviation that would be required to meet this limit, +so that the p th quantile is located at z (minimum_weight). +In this case, the 0.05 (5%) quantile is at 2.9 kg pack weight, when the mean is 3 kg, +ensuring that 0.95 (95%) of packs are above the minimum weight. + +Rearranging, we can directly calculate the required standard deviation: +*/ +normal N01; // standard normal distribution with mean zero and unit standard deviation. +p = 0.05; +double qp = quantile(N01, p); +double sd95 = (minimum_weight - mean) / qp; + +cout << "For the "<< p << "th quantile to be located at " + << minimum_weight << ", would need a standard deviation of " << sd95 << endl; +// For the 0.05th quantile to be located at 2.9, would need a standard deviation of 0.0607957 + +/*`We can now construct a new (normal) distribution pack95 for the 'better' packer, +and check that our distribution will meet the specification. +*/ + +normal pack95(mean, sd95); +cout <<"Fraction of packs >= " << minimum_weight << " with a mean of " << mean + << " and standard deviation of " << pack95.standard_deviation() + << " is " << cdf(complement(pack95, minimum_weight)) << endl; +// Fraction of packs >= 2.9 with a mean of 3 and standard deviation of 0.0607957 is 0.95 + +/*`This calculation is generalized in the free function find_scale, +as shown below, giving the same standard deviation. +*/ +double ss = find_scale<normal>(minimum_weight, under_fraction, packs.mean()); +cout << "find_scale<normal>(minimum_weight, under_fraction, packs.mean()); " << ss << endl; +// find_scale<normal>(minimum_weight, under_fraction, packs.mean()); 0.0607957 + +/*`If we had defined an over_fraction, or percentage that must pass specification +*/ +double over_fraction = 0.95; +/*`And (wrongly) written + + double sso = find_scale<normal>(minimum_weight, over_fraction, packs.mean()); + +With the default policy, we would get a message like + +[pre +Message from thrown exception was: + Error in function boost::math::find_scale<Dist, Policy>(double, double, double, Policy): + Computed scale (-0.060795683191176959) is <= 0! Was the complement intended? +] + +But this would return a *negative* standard deviation - obviously impossible. +The probability should be 1 - over_fraction, not over_fraction, thus: +*/ + +double ss1o = find_scale<normal>(minimum_weight, 1 - over_fraction, packs.mean()); +cout << "find_scale<normal>(minimum_weight, under_fraction, packs.mean()); " << ss1o << endl; +// find_scale<normal>(minimum_weight, under_fraction, packs.mean()); 0.0607957 + +/*`But notice that using '1 - over_fraction' - will lead to a +loss of accuracy, especially if over_fraction was close to unity. (See __why_complements). +In this (very common) case, we should instead use the __complements, +giving the most accurate result. +*/ + +double ssc = find_scale<normal>(complement(minimum_weight, over_fraction, packs.mean())); +cout << "find_scale<normal>(complement(minimum_weight, over_fraction, packs.mean())); " << ssc << endl; +// find_scale<normal>(complement(minimum_weight, over_fraction, packs.mean())); 0.0607957 + +/*`Note that our guess of 0.06 was close to the accurate value of 0.060795683191176959. + +We can again confirm our prediction thus: +*/ + +normal pack95c(mean, ssc); +cout <<"Fraction of packs >= " << minimum_weight << " with a mean of " << mean + << " and standard deviation of " << pack95c.standard_deviation() + << " is " << cdf(complement(pack95c, minimum_weight)) << endl; +// Fraction of packs >= 2.9 with a mean of 3 and standard deviation of 0.0607957 is 0.95 + +/*`Notice that these two deceptively simple questions: + +* Do we over-fill to make sure we meet a minimum specification (or under-fill to avoid an overdose)? + +and/or + +* Do we measure better? + +are actually extremely common. + +The weight of beef might be replaced by a measurement of more or less anything, +from drug tablet content, Apollo landing rocket firing, X-ray treatment doses... + +The scale can be variation in dispensing or uncertainty in measurement. +*/ +//] [/normal_find_location_and_scale_eg Quickbook end] + + } + catch(const std::exception& e) + { // Always useful to include try & catch blocks because default policies + // are to throw exceptions on arguments that cause errors like underflow, overflow. + // Lacking try & catch blocks, the program will abort without a message below, + // which may give some helpful clues as to the cause of the exception. + cout << + "\n""Message from thrown exception was:\n " << e.what() << endl; + } + return 0; +} // int main() + + +/* + +Output is: + +//[normal_find_location_and_scale_output + +Find_location (mean) and find_scale (standard deviation) examples. +Percentage of packs > 3.1 is 15.8655 +Fraction of packs <= 2.9 with a mean of 3 is 0.841345 +Fraction of packs >= 2.9 with a mean of 3.06449 is 0.950005 +Setting the packer to 3.06449 will mean that fraction of packs >= 2.9 is 0.95 +Setting the packer to 3.06449 will mean that fraction of packs >= 2.9 is 0.95 +Cauchy Setting the packer to 3 will mean that fraction of packs >= 2.9 is 0.75 +find_location<cauchy>(minimum_weight, over fraction, standard_deviation); 3.53138 +Cauchy Setting the packer to 3.53138 will mean that fraction of packs >= 2.9 is 0.95 +Cauchy Setting the packer to -0.282052 will mean that fraction of packs >= 2.9 is 0.95 +Quantile of 0.05 = 2.83551, mean = 3, sd = 0.1 +Quantile of 0.05 = 2.91776, mean = 3, sd = 0.05 +Fraction of packs >= 2.9 with a mean of 3 and standard deviation of 0.05 is 0.97725 +Quantile of 0.05 = 2.90131, mean = 3, sd = 0.06 +Fraction of packs >= 2.9 with a mean of 3 and standard deviation of 0.06 is 0.95221 +For the 0.05th quantile to be located at 2.9, would need a standard deviation of 0.0607957 +Fraction of packs >= 2.9 with a mean of 3 and standard deviation of 0.0607957 is 0.95 +find_scale<normal>(minimum_weight, under_fraction, packs.mean()); 0.0607957 +find_scale<normal>(minimum_weight, under_fraction, packs.mean()); 0.0607957 +find_scale<normal>(complement(minimum_weight, over_fraction, packs.mean())); 0.0607957 +Fraction of packs >= 2.9 with a mean of 3 and standard deviation of 0.0607957 is 0.95 + +//] [/normal_find_location_and_scale_eg_output] + +*/ + + + diff --git a/src/boost/libs/math/example/find_root_example.cpp b/src/boost/libs/math/example/find_root_example.cpp new file mode 100644 index 000000000..e944e09e8 --- /dev/null +++ b/src/boost/libs/math/example/find_root_example.cpp @@ -0,0 +1,169 @@ +// find_root_example.cpp + +// Copyright Paul A. Bristow 2007, 2010. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Example of using root finding. + +// Note that this file contains Quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +//[root_find1 +/*` +First we need some includes to access the normal distribution +(and some std output of course). +*/ + +#include <boost/math/tools/roots.hpp> // root finding. + +#include <boost/math/distributions/normal.hpp> // for normal_distribution + using boost::math::normal; // typedef provides default type is double. + +#include <iostream> + using std::cout; using std::endl; using std::left; using std::showpoint; using std::noshowpoint; +#include <iomanip> + using std::setw; using std::setprecision; +#include <limits> + using std::numeric_limits; +#include <stdexcept> + + +//] //[/root_find1] + +int main() +{ + cout << "Example: Normal distribution, root finding."; + try + { + +//[root_find2 + +/*`A machine is set to pack 3 kg of ground beef per pack. +Over a long period of time it is found that the average packed was 3 kg +with a standard deviation of 0.1 kg. +Assuming the packing is normally distributed, +we can find the fraction (or %) of packages that weigh more than 3.1 kg. +*/ + +double mean = 3.; // kg +double standard_deviation = 0.1; // kg +normal packs(mean, standard_deviation); + +double max_weight = 3.1; // kg +cout << "Percentage of packs > " << max_weight << " is " +<< cdf(complement(packs, max_weight)) << endl; // P(X > 3.1) + +double under_weight = 2.9; +cout <<"fraction of packs <= " << under_weight << " with a mean of " << mean + << " is " << cdf(complement(packs, under_weight)) << endl; +// fraction of packs <= 2.9 with a mean of 3 is 0.841345 +// This is 0.84 - more than the target 0.95 +// Want 95% to be over this weight, so what should we set the mean weight to be? +// KK StatCalc says: +double over_mean = 3.0664; +normal xpacks(over_mean, standard_deviation); +cout << "fraction of packs >= " << under_weight +<< " with a mean of " << xpacks.mean() + << " is " << cdf(complement(xpacks, under_weight)) << endl; +// fraction of packs >= 2.9 with a mean of 3.06449 is 0.950005 +double under_fraction = 0.05; // so 95% are above the minimum weight mean - sd = 2.9 +double low_limit = standard_deviation; +double offset = mean - low_limit - quantile(packs, under_fraction); +double nominal_mean = mean + offset; + +normal nominal_packs(nominal_mean, standard_deviation); +cout << "Setting the packer to " << nominal_mean << " will mean that " + << "fraction of packs >= " << under_weight + << " is " << cdf(complement(nominal_packs, under_weight)) << endl; + +/*` +Setting the packer to 3.06449 will mean that fraction of packs >= 2.9 is 0.95. + +Setting the packer to 3.13263 will mean that fraction of packs >= 2.9 is 0.99, +but will more than double the mean loss from 0.0644 to 0.133. + +Alternatively, we could invest in a better (more precise) packer with a lower standard deviation. + +To estimate how much better (how much smaller standard deviation) it would have to be, +we need to get the 5% quantile to be located at the under_weight limit, 2.9 +*/ +double p = 0.05; // wanted p th quantile. +cout << "Quantile of " << p << " = " << quantile(packs, p) + << ", mean = " << packs.mean() << ", sd = " << packs.standard_deviation() << endl; // +/*` +Quantile of 0.05 = 2.83551, mean = 3, sd = 0.1 + +With the current packer (mean = 3, sd = 0.1), the 5% quantile is at 2.8551 kg, +a little below our target of 2.9 kg. +So we know that the standard deviation is going to have to be smaller. + +Let's start by guessing that it (now 0.1) needs to be halved, to a standard deviation of 0.05 +*/ +normal pack05(mean, 0.05); +cout << "Quantile of " << p << " = " << quantile(pack05, p) + << ", mean = " << pack05.mean() << ", sd = " << pack05.standard_deviation() << endl; + +cout <<"Fraction of packs >= " << under_weight << " with a mean of " << mean + << " and standard deviation of " << pack05.standard_deviation() + << " is " << cdf(complement(pack05, under_weight)) << endl; +// +/*` +Fraction of packs >= 2.9 with a mean of 3 and standard deviation of 0.05 is 0.9772 + +So 0.05 was quite a good guess, but we are a little over the 2.9 target, +so the standard deviation could be a tiny bit more. So we could do some +more guessing to get closer, say by increasing to 0.06 +*/ + +normal pack06(mean, 0.06); +cout << "Quantile of " << p << " = " << quantile(pack06, p) + << ", mean = " << pack06.mean() << ", sd = " << pack06.standard_deviation() << endl; + +cout <<"Fraction of packs >= " << under_weight << " with a mean of " << mean + << " and standard deviation of " << pack06.standard_deviation() + << " is " << cdf(complement(pack06, under_weight)) << endl; +/*` +Fraction of packs >= 2.9 with a mean of 3 and standard deviation of 0.06 is 0.9522 + +Now we are getting really close, but to do the job properly, +we could use root finding method, for example the tools provided, and used elsewhere, +in the Math Toolkit, see __root_finding_without_derivatives. + +But in this normal distribution case, we could be even smarter and make a direct calculation. +*/ +//] [/root_find2] + + } + catch(const std::exception& e) + { // Always useful to include try & catch blocks because default policies + // are to throw exceptions on arguments that cause errors like underflow, overflow. + // Lacking try & catch blocks, the program will abort without a message below, + // which may give some helpful clues as to the cause of the exception. + std::cout << + "\n""Message from thrown exception was:\n " << e.what() << std::endl; + } + return 0; +} // int main() + +/* +Output is: + +//[root_find_output + +Autorun "i:\boost-06-05-03-1300\libs\math\test\Math_test\debug\find_root_example.exe" +Example: Normal distribution, root finding.Percentage of packs > 3.1 is 0.158655 +fraction of packs <= 2.9 with a mean of 3 is 0.841345 +fraction of packs >= 2.9 with a mean of 3.0664 is 0.951944 +Setting the packer to 3.06449 will mean that fraction of packs >= 2.9 is 0.95 +Quantile of 0.05 = 2.83551, mean = 3, sd = 0.1 +Quantile of 0.05 = 2.91776, mean = 3, sd = 0.05 +Fraction of packs >= 2.9 with a mean of 3 and standard deviation of 0.05 is 0.97725 +Quantile of 0.05 = 2.90131, mean = 3, sd = 0.06 +Fraction of packs >= 2.9 with a mean of 3 and standard deviation of 0.06 is 0.95221 + +//] [/root_find_output] +*/ diff --git a/src/boost/libs/math/example/find_scale_example.cpp b/src/boost/libs/math/example/find_scale_example.cpp new file mode 100644 index 000000000..29e474f0f --- /dev/null +++ b/src/boost/libs/math/example/find_scale_example.cpp @@ -0,0 +1,180 @@ +// find_scale.cpp + +// Copyright Paul A. Bristow 2007, 2010. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Example of finding scale (standard deviation) for normal (Gaussian). + +// Note that this file contains Quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +//[find_scale1 +/*` +First we need some includes to access the __normal_distrib, +the algorithms to find scale (and some std output of course). +*/ + +#include <boost/math/distributions/normal.hpp> // for normal_distribution + using boost::math::normal; // typedef provides default type is double. +#include <boost/math/distributions/find_scale.hpp> + using boost::math::find_scale; + using boost::math::complement; // Needed if you want to use the complement version. + using boost::math::policies::policy; // Needed to specify the error handling policy. + +#include <iostream> + using std::cout; using std::endl; +#include <iomanip> + using std::setw; using std::setprecision; +#include <limits> + using std::numeric_limits; +//] [/find_scale1] + +int main() +{ + cout << "Example: Find scale (standard deviation)." << endl; + try + { +//[find_scale2 +/*` +For this example, we will use the standard __normal_distrib, +with location (mean) zero and standard deviation (scale) unity. +Conveniently, this is also the default for this implementation's constructor. +*/ + normal N01; // Default 'standard' normal distribution with zero mean + double sd = 1.; // and standard deviation is 1. +/*`Suppose we want to find a different normal distribution with standard deviation +so that only fraction p (here 0.001 or 0.1%) are below a certain chosen limit +(here -2. standard deviations). +*/ + double z = -2.; // z to give prob p + double p = 0.001; // only 0.1% below z = -2 + + cout << "Normal distribution with mean = " << N01.location() // aka N01.mean() + << ", standard deviation " << N01.scale() // aka N01.standard_deviation() + << ", has " << "fraction <= " << z + << ", p = " << cdf(N01, z) << endl; + cout << "Normal distribution with mean = " << N01.location() + << ", standard deviation " << N01.scale() + << ", has " << "fraction > " << z + << ", p = " << cdf(complement(N01, z)) << endl; // Note: uses complement. +/*` +[pre +Normal distribution with mean = 0 has fraction <= -2, p = 0.0227501 +Normal distribution with mean = 0 has fraction > -2, p = 0.97725 +] +Noting that p = 0.02 instead of our target of 0.001, +we can now use `find_scale` to give a new standard deviation. +*/ + double l = N01.location(); + double s = find_scale<normal>(z, p, l); + cout << "scale (standard deviation) = " << s << endl; +/*` +that outputs: +[pre +scale (standard deviation) = 0.647201 +] +showing that we need to reduce the standard deviation from 1. to 0.65. + +Then we can check that we have achieved our objective +by constructing a new distribution +with the new standard deviation (but same zero mean): +*/ + normal np001pc(N01.location(), s); +/*` +And re-calculating the fraction below (and above) our chosen limit. +*/ + cout << "Normal distribution with mean = " << l + << " has " << "fraction <= " << z + << ", p = " << cdf(np001pc, z) << endl; + cout << "Normal distribution with mean = " << l + << " has " << "fraction > " << z + << ", p = " << cdf(complement(np001pc, z)) << endl; +/*` +[pre +Normal distribution with mean = 0 has fraction <= -2, p = 0.001 +Normal distribution with mean = 0 has fraction > -2, p = 0.999 +] + +[h4 Controlling how Errors from find_scale are handled] +We can also control the policy for handling various errors. +For example, we can define a new (possibly unwise) +policy to ignore domain errors ('bad' arguments). + +Unless we are using the boost::math namespace, we will need: +*/ + using boost::math::policies::policy; + using boost::math::policies::domain_error; + using boost::math::policies::ignore_error; + +/*` +Using a typedef is convenient, especially if it is re-used, +although it is not required, as the various examples below show. +*/ + typedef policy<domain_error<ignore_error> > ignore_domain_policy; + // find_scale with new policy, using typedef. + l = find_scale<normal>(z, p, l, ignore_domain_policy()); + // Default policy policy<>, needs using boost::math::policies::policy; + + l = find_scale<normal>(z, p, l, policy<>()); + // Default policy, fully specified. + l = find_scale<normal>(z, p, l, boost::math::policies::policy<>()); + // New policy, without typedef. + l = find_scale<normal>(z, p, l, policy<domain_error<ignore_error> >()); +/*` +If we want to express a probability, say 0.999, that is a complement, `1 - p` +we should not even think of writing `find_scale<normal>(z, 1 - p, l)`, +but use the __complements version (see __why_complements). +*/ + z = -2.; + double q = 0.999; // = 1 - p; // complement of 0.001. + sd = find_scale<normal>(complement(z, q, l)); + + normal np95pc(l, sd); // Same standard_deviation (scale) but with mean(scale) shifted + cout << "Normal distribution with mean = " << l << " has " + << "fraction <= " << z << " = " << cdf(np95pc, z) << endl; + cout << "Normal distribution with mean = " << l << " has " + << "fraction > " << z << " = " << cdf(complement(np95pc, z)) << endl; + +/*` +Sadly, it is all too easy to get probabilities the wrong way round, +when you may get a warning like this: +[pre +Message from thrown exception was: + Error in function boost::math::find_scale<Dist, Policy>(complement(double, double, double, Policy)): + Computed scale (-0.48043523852179076) is <= 0! Was the complement intended? +] +The default error handling policy is to throw an exception with this message, +but if you chose a policy to ignore the error, +the (impossible) negative scale is quietly returned. +*/ +//] [/find_scale2] + } + catch(const std::exception& e) + { // Always useful to include try & catch blocks because default policies + // are to throw exceptions on arguments that cause errors like underflow, overflow. + // Lacking try & catch blocks, the program will abort without a message below, + // which may give some helpful clues as to the cause of the exception. + std::cout << + "\n""Message from thrown exception was:\n " << e.what() << std::endl; + } + return 0; +} // int main() + +//[find_scale_example_output +/*` +[pre +Example: Find scale (standard deviation). +Normal distribution with mean = 0, standard deviation 1, has fraction <= -2, p = 0.0227501 +Normal distribution with mean = 0, standard deviation 1, has fraction > -2, p = 0.97725 +scale (standard deviation) = 0.647201 +Normal distribution with mean = 0 has fraction <= -2, p = 0.001 +Normal distribution with mean = 0 has fraction > -2, p = 0.999 +Normal distribution with mean = 0.946339 has fraction <= -2 = 0.001 +Normal distribution with mean = 0.946339 has fraction > -2 = 0.999 +] +*/ +//] [/find_scale_example_output] diff --git a/src/boost/libs/math/example/float128_example.cpp b/src/boost/libs/math/example/float128_example.cpp new file mode 100644 index 000000000..23e01666a --- /dev/null +++ b/src/boost/libs/math/example/float128_example.cpp @@ -0,0 +1,289 @@ +// Copyright John Maddock 2016 +// Copyright Christopher Kormanyos 2016. +// Copyright Paul A. Bristow 2016. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Contains Quickbook snippets as C++ comments - do not remove. + +// http://gcc.gnu.org/onlinedocs/libquadmath/ GCC Quad-Precision Math Library +// https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format + +// https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Dialect-Options.html#C_002b_002b-Dialect-Options GNU 3.5 Options Controlling C++ Dialect +// https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html#C-Dialect-Options 3.4 Options Controlling C Dialect + +//[float128_includes_1 + +#include <boost/cstdfloat.hpp> // For float_64_t, float128_t. Must be first include! +//#include <boost/config.hpp> +#include <boost/multiprecision/float128.hpp> +#include <boost/math/special_functions.hpp> // For gamma function. +#include <boost/math/constants/constants.hpp> // For constants pi, e ... +#include <typeinfo> // + +#include <cmath> // for pow function. + +// #include <quadmath.h> +// C:\program files\gcc-6-win64\lib\gcc\x86_64-w64-mingw32\6.1.1\include\quadmath.h + +// i:\modular-boost\boost\multiprecision\float128.hpp|210| undefined reference to `quadmath_snprintf'. + +//] [/float128_includes_1] + +//[float128_dialect_1 +/*`To make float128 available it is vital to get the dialect and options on the command line correct. + +Quad type is forbidden by all the strict C++ standards, so using or adding -std=c++11 and later standards will prevent its use. +so explicitly use -std=gnu++11, 1y, 14, 17, or 1z or ... + +For GCC 6.1.1, for example, the default is if no C++ language dialect options are given, is -std=gnu++14. + +See https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html#C-Dialect-Options +https://gcc.gnu.org/onlinedocs/gcc/Standards.html#Standards 2 Language Standards Supported by GCC + + g++.exe -Wall -fexceptions -std=gnu++17 -g -fext-numeric-literals -fpermissive -lquadmath + -II:\modular-boost\libs\math\include -Ii:\modular-boost -c J:\Cpp\float128\float128\float128_example.cpp -o obj\Debug\float128_example.o + +Requires GCC linker option -lquadmath + +If this is missing, then get errors like: + + \modular-boost\boost\multiprecision\float128.hpp|210|undefined reference to `quadmath_snprintf'| + \modular-boost\boost\multiprecision\float128.hpp|351|undefined reference to `sqrtq'| + +Requires compile option + + -fext-numeric-literals + +If missing, then get errors like: + +\modular-boost\libs\math\include/boost/math/cstdfloat/cstdfloat_types.hpp:229:43: error: unable to find numeric literal operator 'operator""Q' + +A successful build log was: + + g++.exe -Wall -std=c++11 -fexceptions -std=gnu++17 -g -fext-numeric-literals -II:\modular-boost\libs\math\include -Ii:\modular-boost -c J:\Cpp\float128\float128\float128_example.cpp -o obj\Debug\float128_example.o + g++.exe -o bin\Debug\float128.exe obj\Debug\float128_example.o -lquadmath +*/ + +//] [/float128_dialect_1] + +void show_versions(std::string title) +{ + std::cout << title << std::endl; + + std::cout << "Platform: " << BOOST_PLATFORM << '\n' + << "Compiler: " << BOOST_COMPILER << '\n' + << "STL : " << BOOST_STDLIB << '\n' + << "Boost : " << BOOST_VERSION / 100000 << "." + << BOOST_VERSION / 100 % 1000 << "." + << BOOST_VERSION % 100 + << std::endl; +#ifdef _MSC_VER + std::cout << "_MSC_FULL_VER = " << _MSC_FULL_VER << std::endl; // VS 2015 190023026 +#if defined _M_IX86 + std::cout << "(x86)" << std::endl; +#endif +#if defined _M_X64 + std::cout << " (x64)" << std::endl; +#endif +#if defined _M_IA64 + std::cout << " (Itanium)" << std::endl; +#endif + // Something very wrong if more than one is defined (so show them in all just in case)! +#endif // _MSC_VER +#ifdef __GNUC__ +//PRINT_MACRO(__GNUC__); +//PRINT_MACRO(__GNUC_MINOR__); +//PRINT_MACRO(__GNUC_PATCH__); +std::cout << "GCC " << __VERSION__ << std::endl; +//PRINT_MACRO(LONG_MAX); +#endif // __GNUC__ + return; +} // void show_version(std::string title) + +int main() +{ + try + { + +//[float128_example_3 +// Always use try'n'catch blocks to ensure any error messages are displayed. +//`Ensure that all possibly significant digits (17) including trailing zeros are shown. + + std::cout.precision(std::numeric_limits<boost::float64_t>::max_digits10); + std::cout.setf(std::ios::showpoint); // Show all significant trailing zeros. + //] [/ float128_example_3] + +#ifdef BOOST_FLOAT128_C + std::cout << "Floating-point type boost::float128_t is available." << std::endl; + std::cout << " std::numeric_limits<boost::float128_t>::digits10 == " + << std::numeric_limits<boost::float128_t>::digits10 << std::endl; + std::cout << " std::numeric_limits<boost::float128_t>::max_digits10 == " + << std::numeric_limits<boost::float128_t>::max_digits10 << std::endl; +#else + std::cout << "Floating-point type boost::float128_t is NOT available." << std::endl; +#endif + + show_versions(""); + + using boost::multiprecision::float128; // Wraps, for example, __float128 or _Quad. + // or + //using namespace boost::multiprecision; + + std::cout.precision(std::numeric_limits<float128>::max_digits10); // Show all potentially meaningful digits. + std::cout.setf(std::ios::showpoint); // Show all significant trailing zeros. + + // float128 pi0 = boost::math::constants::pi(); // Compile fails - need to specify a type for the constant! + + float128 pi1 = boost::math::constants::pi<float128>(); // Returns a constant of type float128. + std::cout << sqrt(pi1) << std::endl; // 1.77245385090551602729816748334114514 + + float128 pi2 = boost::math::constants::pi<__float128>(); // Constant of type __float128 gets converted to float128 on the assignment. + std::cout << sqrt(pi2) << std::endl; // 1.77245385090551602729816748334114514 + + // DIY decimal digit literal constant, with suffix Q. + float128 pi3 = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348Q; + std::cout << sqrt(pi3) << std::endl; // 1.77245385090551602729816748334114514 + + // Compare to ready-rolled sqrt(pi) constant from Boost.Math: + std::cout << boost::math::constants::root_pi<float128>() << std::endl; // 1.77245385090551602729816748334114514 + + // DIY decimal digit literal constant, without suffix Q, suffering seventeen silent digits loss of precision! + float128 pi4 = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348; + std::cout << sqrt(pi4) << std::endl; // 1.77245385090551599275151910313924857 + + // float128 variables constructed from a quad-type literal can be declared constexpr if required: + +#ifndef BOOST_NO_CXX11_CONSTEXPR + constexpr float128 pi_constexpr = 3.1415926535897932384626433832795028841971693993751058Q; +#endif + std::cout << pi_constexpr << std::endl; // 3.14159265358979323846264338327950280 + + // But sadly functions like sqrt are not yet available constexpr for float128. + + // constexpr float128 root_pi_constexpr = sqrt(pi_constexpr); // Fails - not constexpr (yet). + // constexpr float128 root_pi_constexpr = std::sqrt(pi_constexpr); // Fails - no known conversion for argument 1 from 'const float128'. + // constexpr float128 root_pi_constexpr = sqrt(pi_constexpr); // Call to non-constexpr + // constexpr float128 root_pi_constexpr = boost::math::constants::root_pi(); // Missing type for constant. + + // Best current way to get a constexpr is to use a Boost.Math constant if one is available. + constexpr float128 root_pi_constexpr = boost::math::constants::root_pi<float128>(); + std::cout << root_pi_constexpr << std::endl; // 1.77245385090551602729816748334114514 + + // Note that casts within the sqrt call are NOT NEEDED (nor allowed), + // since all the variables are the correct type to begin with. + // std::cout << sqrt<float128>(pi3) << std::endl; + // But note examples of catastrophic (but hard to see) loss of precision below. + + // Note also that the library functions, here sqrt, is NOT defined using std::sqrt, + // so that the correct overload is found using Argument Dependent LookUp (ADL). + + float128 ee = boost::math::constants::e<float128>(); + std::cout << ee << std::endl; // 2.71828182845904523536028747135266231 + + float128 e1 = exp(1.Q); // Note argument to exp is type float128. + std::cout << e1 << std::endl; // 2.71828182845904523536028747135266231 + + // Beware - it is all too easy to silently get a much lower precision by mistake. + + float128 e1d = exp(1.); // Caution - only double 17 decimal digits precision! + std::cout << e1d << std::endl; // 2.71828182845904509079559829842764884 + + float128 e1i = exp(1); // Caution int promoted to double so only 17 decimal digits precision! + std::cout << e1i << std::endl; // 2.71828182845904509079559829842764884 + + float f1 = 1.F; + float128 e1f = exp(f1); // Caution float so only 6 decimal digits precision out of 36! + std::cout << e1f << std::endl; // 2.71828174591064453125000000000000000 + + // In all these cases you get what you asked for and not what you expected or wanted. + + // Casting is essential if you start with a lower precision type. + + float128 e1q = exp(static_cast<float128>(f1)); // Full 36 decimal digits precision! + std::cout << e1q << std::endl; // 2.71828182845904523536028747135266231 + + float128 e1qc = exp((float128)f1); // Full 36 decimal digits precision! + std::cout << e1qc << std::endl; // 2.71828182845904523536028747135266231 + + float128 e1qcc = exp(float128(f1)); // Full 36 decimal digits precision! + std::cout << e1qcc << std::endl; // 2.71828182845904523536028747135266231 + + //float128 e1q = exp<float128>(1.); // Compile fails. + // std::cout << e1q << std::endl; // + +// http://en.cppreference.com/w/cpp/language/typeid +// The name()is implementation-dependent mangled, and may not be able to be output. +// The example showing output using one of the implementations where type_info::name prints full type names; +// filter through c++filt -t if using gcc or similar. + +//[float128_type_info +const std::type_info& tifu128 = typeid(__float128); // OK. +//std::cout << tifu128.name() << std::endl; // On GCC, aborts (because not printable string). +//std::cout << typeid(__float128).name() << std::endl; // Aborts - +// string name cannot be output. + +const std::type_info& tif128 = typeid(float128); // OK. +std::cout << tif128.name() << std::endl; // OK. +std::cout << typeid(float128).name() << std::endl; // OK. + +const std::type_info& tpi = typeid(pi1); // OK using GCC 6.1.1. +// (from GCC 5 according to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43622) +std::cout << tpi.name() << std::endl; // OK, Output implementation-dependent mangled name: + +// N5boost14multiprecision6numberINS0_8backends16float128_backendELNS0_26expression_template_optionE0EEE + +//] [/float128_type_info] + + } + catch (std::exception ex) + { // Display details about why any exceptions are thrown. + std::cout << "Thrown exception " << ex.what() << std::endl; + } +} // int main() + +/* +[float128_output + +-std=c++11 or -std=c++17 don't work + +Floating-point type boost::float128_t is NOT available. + +Platform: Win32 +Compiler: GNU C++ version 6.1.1 20160609 +STL : GNU libstdc++ version 20160609 +Boost : 1.62.0 +GCC 6.1.1 20160609 + + +Added -fext-numeric-literals to + +-std=gnu++11 -fext-numeric-literals -lquadmath + +Floating-point type boost::float128_t is available. + std::numeric_limits<boost::float128_t>::digits10 == 33 + std::numeric_limits<boost::float128_t>::max_digits10 == 36 + +Platform: Win32 +Compiler: GNU C++ version 6.1.1 20160609 +STL : GNU libstdc++ version 20160609 +Boost : 1.62.0 +GCC 6.1.1 20160609 +1.77245385090551602729816748334114514 +1.77245385090551602729816748334114514 +1.77245385090551602729816748334114514 +1.77245385090551602729816748334114514 +N5boost14multiprecision6numberINS0_8backends16float128_backendELNS0_26expression_template_optionE0EEE +N5boost14multiprecision6numberINS0_8backends16float128_backendELNS0_26expression_template_optionE0EEE +N5boost14multiprecision6numberINS0_8backends16float128_backendELNS0_26expression_template_optionE0EEE + +Process returned 0 (0x0) execution time : 0.033 s +Press any key to continue. + + + +//] [/float128_output] + +*/ diff --git a/src/boost/libs/math/example/float_comparison_example.cpp b/src/boost/libs/math/example/float_comparison_example.cpp new file mode 100644 index 000000000..6c892fa21 --- /dev/null +++ b/src/boost/libs/math/example/float_comparison_example.cpp @@ -0,0 +1,444 @@ +//!file +//! \brief floating-point comparison from Boost.Test +// Copyright Paul A. Bristow 2015. +// Copyright John Maddock 2015. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains Quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +#include <boost/math/special_functions/relative_difference.hpp> +#include <boost/math/special_functions/next.hpp> + +#include <iostream> +#include <limits> // for std::numeric_limits<T>::epsilon(). + +int main() +{ + std::cout << "Compare floats using Boost.Math functions/classes" << std::endl; + + +//[compare_floats_using +/*`Some using statements will ensure that the functions we need are accessible. +*/ + + using namespace boost::math; + +//`or + + using boost::math::relative_difference; + using boost::math::epsilon_difference; + using boost::math::float_next; + using boost::math::float_prior; + +//] [/compare_floats_using] + + +//[compare_floats_example_1 +/*`The following examples display values with all possibly significant digits. +Newer compilers should provide `std::numeric_limits<FPT>::max_digits10` +for this purpose, and here we use `float` precision where `max_digits10` = 9 +to avoid displaying a distracting number of decimal digits. + +[note Older compilers can use this formula to calculate `max_digits10` +from `std::numeric_limits<FPT>::digits10`: +__spaces `int max_digits10 = 2 + std::numeric_limits<FPT>::digits10 * 3010/10000;` +] [/note] + +One can set the display including all trailing zeros +(helpful for this example to show all potentially significant digits), +and also to display `bool` values as words rather than integers: +*/ + std::cout.precision(std::numeric_limits<float>::max_digits10); + std::cout << std::boolalpha << std::showpoint << std::endl; + +//] [/compare_floats_example_1] + +//[compare_floats_example_2] +/*` +When comparing values that are ['quite close] or ['approximately equal], +we could use either `float_distance` or `relative_difference`/`epsilon_difference`, for example +with type `float`, these two values are adjacent to each other: +*/ + + float a = 1; + float b = 1 + std::numeric_limits<float>::epsilon(); + std::cout << "a = " << a << std::endl; + std::cout << "b = " << b << std::endl; + std::cout << "float_distance = " << float_distance(a, b) << std::endl; + std::cout << "relative_difference = " << relative_difference(a, b) << std::endl; + std::cout << "epsilon_difference = " << epsilon_difference(a, b) << std::endl; + +/*` +Which produces the output: + +[pre +a = 1.00000000 +b = 1.00000012 +float_distance = 1.00000000 +relative_difference = 1.19209290e-007 +epsilon_difference = 1.00000000 +] +*/ + //] [/compare_floats_example_2] + +//[compare_floats_example_3] +/*` +In the example above, it just so happens that the edit distance as measured by `float_distance`, and the +difference measured in units of epsilon were equal. However, due to the way floating point +values are represented, that is not always the case:*/ + + a = 2.0f / 3.0f; // 2/3 inexactly represented as a float + b = float_next(float_next(float_next(a))); // 3 floating point values above a + std::cout << "a = " << a << std::endl; + std::cout << "b = " << b << std::endl; + std::cout << "float_distance = " << float_distance(a, b) << std::endl; + std::cout << "relative_difference = " << relative_difference(a, b) << std::endl; + std::cout << "epsilon_difference = " << epsilon_difference(a, b) << std::endl; + +/*` +Which produces the output: + +[pre +a = 0.666666687 +b = 0.666666865 +float_distance = 3.00000000 +relative_difference = 2.68220901e-007 +epsilon_difference = 2.25000000 +] + +There is another important difference between `float_distance` and the +`relative_difference/epsilon_difference` functions in that `float_distance` +returns a signed result that reflects which argument is larger in magnitude, +where as `relative_difference/epsilon_difference` simply return an unsigned +value that represents how far apart the values are. For example if we swap +the order of the arguments: +*/ + + std::cout << "float_distance = " << float_distance(b, a) << std::endl; + std::cout << "relative_difference = " << relative_difference(b, a) << std::endl; + std::cout << "epsilon_difference = " << epsilon_difference(b, a) << std::endl; + + /*` + The output is now: + + [pre + float_distance = -3.00000000 + relative_difference = 2.68220901e-007 + epsilon_difference = 2.25000000 + ] +*/ + //] [/compare_floats_example_3] + +//[compare_floats_example_4] +/*` +Zeros are always treated as equal, as are infinities as long as they have the same sign:*/ + + a = 0; + b = -0; // signed zero + std::cout << "relative_difference = " << relative_difference(a, b) << std::endl; + a = b = std::numeric_limits<float>::infinity(); + std::cout << "relative_difference = " << relative_difference(a, b) << std::endl; + std::cout << "relative_difference = " << relative_difference(a, -b) << std::endl; + +/*` +Which produces the output: + +[pre +relative_difference = 0.000000000 +relative_difference = 0.000000000 +relative_difference = 3.40282347e+038 +] +*/ +//] [/compare_floats_example_4] + +//[compare_floats_example_5] +/*` +Note that finite values are always infinitely far away from infinities even if those finite values are very large:*/ + + a = (std::numeric_limits<float>::max)(); + b = std::numeric_limits<float>::infinity(); + std::cout << "a = " << a << std::endl; + std::cout << "b = " << b << std::endl; + std::cout << "relative_difference = " << relative_difference(a, b) << std::endl; + std::cout << "epsilon_difference = " << epsilon_difference(a, b) << std::endl; + +/*` +Which produces the output: + +[pre +a = 3.40282347e+038 +b = 1.#INF0000 +relative_difference = 3.40282347e+038 +epsilon_difference = 3.40282347e+038 +] +*/ +//] [/compare_floats_example_5] + +//[compare_floats_example_6] +/*` +Finally, all denormalized values and zeros are treated as being effectively equal:*/ + + a = std::numeric_limits<float>::denorm_min(); + b = a * 2; + std::cout << "a = " << a << std::endl; + std::cout << "b = " << b << std::endl; + std::cout << "float_distance = " << float_distance(a, b) << std::endl; + std::cout << "relative_difference = " << relative_difference(a, b) << std::endl; + std::cout << "epsilon_difference = " << epsilon_difference(a, b) << std::endl; + a = 0; + std::cout << "a = " << a << std::endl; + std::cout << "b = " << b << std::endl; + std::cout << "float_distance = " << float_distance(a, b) << std::endl; + std::cout << "relative_difference = " << relative_difference(a, b) << std::endl; + std::cout << "epsilon_difference = " << epsilon_difference(a, b) << std::endl; + +/*` +Which produces the output: + +[pre +a = 1.40129846e-045 +b = 2.80259693e-045 +float_distance = 1.00000000 +relative_difference = 0.000000000 +epsilon_difference = 0.000000000 +a = 0.000000000 +b = 2.80259693e-045 +float_distance = 2.00000000 +relative_difference = 0.000000000 +epsilon_difference = 0.000000000] + +Notice how, in the above example, two denormalized values that are a factor of 2 apart are +none the less only one representation apart! + +*/ +//] [/compare_floats_example_6] + + +#if 0 +//[old_compare_floats_example_3 +//`The simplest use is to compare two values with a tolerance thus: + + bool is_close = is_close_to(1.F, 1.F + epsilon, epsilon); // One epsilon apart is close enough. + std::cout << "is_close_to(1.F, 1.F + epsilon, epsilon); is " << is_close << std::endl; // true + + is_close = is_close_to(1.F, 1.F + 2 * epsilon, epsilon); // Two epsilon apart isn't close enough. + std::cout << "is_close_to(1.F, 1.F + epsilon, epsilon); is " << is_close << std::endl; // false + +/*` +[note The type FPT of the tolerance and the type of the values [*must match]. + +So `is_close(0.1F, 1., 1.)` will fail to compile because "template parameter 'FPT' is ambiguous". +Always provide the same type, using `static_cast<FPT>` if necessary.] +*/ + + +/*`An instance of class `close_at_tolerance` is more convenient +when multiple tests with the same conditions are planned. +A class that stores a tolerance of three epsilon (and the default ['strong] test) is: +*/ + + close_at_tolerance<float> three_rounds(3 * epsilon); // 'strong' by default. + +//`and we can confirm these settings: + + std::cout << "fraction_tolerance = " + << three_rounds.fraction_tolerance() + << std::endl; // +3.57627869e-007 + std::cout << "strength = " + << (three_rounds.strength() == FPC_STRONG ? "strong" : "weak") + << std::endl; // strong + +//`To start, let us use two values that are truly equal (having identical bit patterns) + + float a = 1.23456789F; + float b = 1.23456789F; + +//`and make a comparison using our 3*epsilon `three_rounds` functor: + + bool close = three_rounds(a, b); + std::cout << "three_rounds(a, b) = " << close << std::endl; // true + +//`Unsurprisingly, the result is true, and the failed fraction is zero. + + std::cout << "failed_fraction = " << three_rounds.failed_fraction() << std::endl; + +/*`To get some nearby values, it is convenient to use the Boost.Math __next_float functions, +for which we need an include + + #include <boost/math/special_functions/next.hpp> + +and some using declarations: +*/ + + using boost::math::float_next; + using boost::math::float_prior; + using boost::math::nextafter; + using boost::math::float_distance; + +//`To add a few __ulp to one value: + b = float_next(a); // Add just one ULP to a. + b = float_next(b); // Add another one ULP. + b = float_next(b); // Add another one ULP. + // 3 epsilon would pass. + b = float_next(b); // Add another one ULP. + +//`and repeat our comparison: + + close = three_rounds(a, b); + std::cout << "three_rounds(a, b) = " << close << std::endl; // false + std::cout << "failed_fraction = " << three_rounds.failed_fraction() + << std::endl; // abs(u-v) / abs(v) = 3.86237957e-007 + +//`We can also 'measure' the number of bits different using the `float_distance` function: + + std::cout << "float_distance = " << float_distance(a, b) << std::endl; // 4 + +/*`Now consider two values that are much further apart +than one might expect from ['computational noise], +perhaps the result of two measurements of some physical property like length +where an uncertainty of a percent or so might be expected. +*/ + float fp1 = 0.01000F; + float fp2 = 0.01001F; // Slightly different. + + float tolerance = 0.0001F; + + close_at_tolerance<float> strong(epsilon); // Default is strong. + bool rs = strong(fp1, fp2); + std::cout << "strong(fp1, fp2) is " << rs << std::endl; + +//`Or we could contrast using the ['weak] criterion: + close_at_tolerance<float> weak(epsilon, FPC_WEAK); // Explicitly weak. + bool rw = weak(fp1, fp2); // + std::cout << "weak(fp1, fp2) is " << rw << std::endl; + +//`We can also construct, setting tolerance and strength, and compare in one statement: + + std::cout << a << " #= " << b << " is " + << close_at_tolerance<float>(epsilon, FPC_STRONG)(a, b) << std::endl; + std::cout << a << " ~= " << b << " is " + << close_at_tolerance<float>(epsilon, FPC_WEAK)(a, b) << std::endl; + +//`but this has little advantage over using function `is_close_to` directly. + +//] [/old_compare_floats_example_3] + + +/*When the floating-point values become very small and near zero, using +//a relative test becomes unhelpful because one is dividing by zero or tiny, + +//Instead, an absolute test is needed, comparing one (or usually both) values with zero, +//using a tolerance. +//This is provided by the `small_with_tolerance` class and `is_small` function. + + namespace boost { + namespace math { + namespace fpc { + + + template<typename FPT> + class small_with_tolerance + { + public: + // Public typedefs. + typedef bool result_type; + + // Constructor. + explicit small_with_tolerance(FPT tolerance); // tolerance >= 0 + + // Functor + bool operator()(FPT value) const; // return true if <= absolute tolerance (near zero). + }; + + template<typename FPT> + bool + is_small(FPT value, FPT tolerance); // return true if value <= absolute tolerance (near zero). + + }}} // namespaces. + +/*` +[note The type FPT of the tolerance and the type of the value [*must match]. + +So `is_small(0.1F, 0.000001)` will fail to compile because "template parameter 'FPT' is ambiguous". +Always provide the same type, using `static_cast<FPT>` if necessary.] + +A few values near zero are tested with varying tolerance below. +*/ +//[compare_floats_small_1 + + float c = 0; + std::cout << "0 is_small " << is_small(c, epsilon) << std::endl; // true + + c = std::numeric_limits<float>::denorm_min(); // 1.40129846e-045 + std::cout << "denorm_ min =" << c << ", is_small is " << is_small(c, epsilon) << std::endl; // true + + c = (std::numeric_limits<float>::min)(); // 1.17549435e-038 + std::cout << "min = " << c << ", is_small is " << is_small(c, epsilon) << std::endl; // true + + c = 1 * epsilon; // 1.19209290e-007 + std::cout << "epsilon = " << c << ", is_small is " << is_small(c, epsilon) << std::endl; // false + + c = 1 * epsilon; // 1.19209290e-007 + std::cout << "2 epsilon = " << c << ", is_small is " << is_small(c, 2 * epsilon) << std::endl; // true + + c = 2 * epsilon; //2.38418579e-007 + std::cout << "4 epsilon = " << c << ", is_small is " << is_small(c, 2 * epsilon) << std::endl; // false + + c = 0.00001F; + std::cout << "0.00001 = " << c << ", is_small is " << is_small(c, 0.0001F) << std::endl; // true + + c = -0.00001F; + std::cout << "0.00001 = " << c << ", is_small is " << is_small(c, 0.0001F) << std::endl; // true + +/*`Using the class `small_with_tolerance` allows storage of the tolerance, +convenient if you make repeated tests with the same tolerance. +*/ + + small_with_tolerance<float>my_test(0.01F); + + std::cout << "my_test(0.001F) is " << my_test(0.001F) << std::endl; // true + std::cout << "my_test(0.001F) is " << my_test(0.01F) << std::endl; // false + + //] [/compare_floats_small_1] +#endif + return 0; +} // int main() + +/* + +Example output is: + +//[compare_floats_output +Compare floats using Boost.Test functions/classes + +float epsilon = 1.19209290e-007 +is_close_to(1.F, 1.F + epsilon, epsilon); is true +is_close_to(1.F, 1.F + epsilon, epsilon); is false +fraction_tolerance = 3.57627869e-007 +strength = strong +three_rounds(a, b) = true +failed_fraction = 0.000000000 +three_rounds(a, b) = false +failed_fraction = 3.86237957e-007 +float_distance = 4.00000000 +strong(fp1, fp2) is false +weak(fp1, fp2) is false +1.23456788 #= 1.23456836 is false +1.23456788 ~= 1.23456836 is false +0 is_small true +denorm_ min =1.40129846e-045, is_small is true +min = 1.17549435e-038, is_small is true +epsilon = 1.19209290e-007, is_small is false +2 epsilon = 1.19209290e-007, is_small is true +4 epsilon = 2.38418579e-007, is_small is false +0.00001 = 9.99999975e-006, is_small is true +0.00001 = -9.99999975e-006, is_small is true +my_test(0.001F) is true + +my_test(0.001F) is false//] [/compare_floats_output] +*/ diff --git a/src/boost/libs/math/example/gauss_example.cpp b/src/boost/libs/math/example/gauss_example.cpp new file mode 100644 index 000000000..466d58b4c --- /dev/null +++ b/src/boost/libs/math/example/gauss_example.cpp @@ -0,0 +1,142 @@ +/* + * Copyright John Maddock, 2017 + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + * This example Illustrates numerical integration via Gauss and Gauss-Kronrod quadrature. + */ + +#include <iostream> +#include <cmath> +#include <limits> +#include <boost/math/quadrature/gauss.hpp> +#include <boost/math/quadrature/gauss_kronrod.hpp> +#include <boost/math/constants/constants.hpp> +#include <boost/math/special_functions/relative_difference.hpp> +#include <boost/multiprecision/cpp_bin_float.hpp> + +void gauss_examples() +{ + //[gauss_example + + /*` + We'll begin by integrating t[super 2] atan(t) over (0,1) using a 7 term Gauss-Legendre rule, + and begin by defining the function to integrate as a C++ lambda expression: + */ + using namespace boost::math::quadrature; + + auto f = [](const double& t) { return t * t * std::atan(t); }; + + /*` + Integration is simply a matter of calling the `gauss<double, 7>::integrate` method: + */ + + double Q = gauss<double, 7>::integrate(f, 0, 1); + + /*` + Which yields a value 0.2106572512 accurate to 1e-10. + + For more accurate evaluations, we'll move to a multiprecision type and use a 20-point integration scheme: + */ + + using boost::multiprecision::cpp_bin_float_quad; + + auto f2 = [](const cpp_bin_float_quad& t) { return t * t * atan(t); }; + + cpp_bin_float_quad Q2 = gauss<cpp_bin_float_quad, 20>::integrate(f2, 0, 1); + + /*` + Which yields 0.2106572512258069881080923020669, which is accurate to 5e-28. + */ + + //] + + std::cout << std::setprecision(18) << Q << std::endl; + std::cout << boost::math::relative_difference(Q, (boost::math::constants::pi<double>() - 2 + 2 * boost::math::constants::ln_two<double>()) / 12) << std::endl; + + std::cout << std::setprecision(34) << Q2 << std::endl; + std::cout << boost::math::relative_difference(Q2, (boost::math::constants::pi<cpp_bin_float_quad>() - 2 + 2 * boost::math::constants::ln_two<cpp_bin_float_quad>()) / 12) << std::endl; +} + +void gauss_kronrod_examples() +{ + //[gauss_kronrod_example + + /*` + We'll begin by integrating exp(-t[super 2]/2) over (0,+[infin]) using a 7 term Gauss rule + and 15 term Kronrod rule, + and begin by defining the function to integrate as a C++ lambda expression: + */ + using namespace boost::math::quadrature; + + auto f1 = [](double t) { return std::exp(-t*t / 2); }; + + //<- + double Q_expected = sqrt(boost::math::constants::half_pi<double>()); + //-> + + /*` + We'll start off with a one shot (ie non-adaptive) + integration, and keep track of the estimated error: + */ + double error; + double Q = gauss_kronrod<double, 15>::integrate(f1, 0, std::numeric_limits<double>::infinity(), 0, 0, &error); + + /*` + This yields Q = 1.25348207361, which has an absolute error of 1e-4 compared to the estimated error + of 5e-3: this is fairly typical, with the difference between Gauss and Gauss-Kronrod schemes being + much higher than the actual error. Before moving on to adaptive quadrature, lets try again + with more points, in fact with the largest Gauss-Kronrod scheme we have cached (30/61): + */ + //<- + std::cout << std::setprecision(16) << Q << std::endl; + std::cout << boost::math::relative_difference(Q, Q_expected) << std::endl; + std::cout << fabs(Q - Q_expected) << std::endl; + std::cout << error << std::endl; + //-> + Q = gauss_kronrod<double, 61>::integrate(f1, 0, std::numeric_limits<double>::infinity(), 0, 0, &error); + //<- + std::cout << std::setprecision(16) << Q << std::endl; + std::cout << boost::math::relative_difference(Q, Q_expected) << std::endl; + std::cout << fabs(Q - Q_expected) << std::endl; + std::cout << error << std::endl; + //-> + /*` + This yields an absolute error of 3e-15 against an estimate of 1e-8, which is about as good as we're going to get + at double precision + + However, instead of continuing with ever more points, lets switch to adaptive integration, and set the desired relative + error to 1e-14 against a maximum depth of 5: + */ + Q = gauss_kronrod<double, 15>::integrate(f1, 0, std::numeric_limits<double>::infinity(), 5, 1e-14, &error); + //<- + std::cout << std::setprecision(16) << Q << std::endl; + std::cout << boost::math::relative_difference(Q, Q_expected) << std::endl; + std::cout << fabs(Q - Q_expected) << std::endl; + std::cout << error << std::endl; + //-> + /*` + This yields an actual error of zero, against an estimate of 4e-15. In fact in this case the requested tolerance was almost + certainly set too low: as we've seen above, for smooth functions, the precision achieved is often double + that of the estimate, so if we integrate with a tolerance of 1e-9: + */ + Q = gauss_kronrod<double, 15>::integrate(f1, 0, std::numeric_limits<double>::infinity(), 5, 1e-9, &error); + //<- + std::cout << std::setprecision(16) << Q << std::endl; + std::cout << boost::math::relative_difference(Q, Q_expected) << std::endl; + std::cout << fabs(Q - Q_expected) << std::endl; + std::cout << error << std::endl; + //-> + /*` + We still achieve 1e-15 precision, with an error estimate of 1e-10. + */ + //] +} + +int main() +{ + gauss_examples(); + gauss_kronrod_examples(); + return 0; +} diff --git a/src/boost/libs/math/example/geometric_examples.cpp b/src/boost/libs/math/example/geometric_examples.cpp new file mode 100644 index 000000000..92ea28e56 --- /dev/null +++ b/src/boost/libs/math/example/geometric_examples.cpp @@ -0,0 +1,364 @@ +// geometric_examples.cpp + +// Copyright Paul A. Bristow 2010. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// This file is written to be included from a Quickbook .qbk document. +// It can still be compiled by the C++ compiler, and run. +// Any output can also be added here as comment or included or pasted in elsewhere. +// Caution: this file contains Quickbook markup as well as code +// and comments: don't change any of the special comment markups! + +// Examples of using the geometric distribution. + +//[geometric_eg1_1 +/*` +For this example, we will opt to #define two macros to control +the error and discrete handling policies. +For this simple example, we want to avoid throwing +an exception (the default policy) and just return infinity. +We want to treat the distribution as if it was continuous, +so we choose a discrete_quantile policy of real, +rather than the default policy integer_round_outwards. +*/ +#define BOOST_MATH_OVERFLOW_ERROR_POLICY ignore_error +#define BOOST_MATH_DISCRETE_QUANTILE_POLICY real +/*` +[caution It is vital to #include distributions etc *after* the above #defines] +After that we need some includes to provide easy access to the negative binomial distribution, +and we need some std library iostream, of course. +*/ +#include <boost/math/distributions/geometric.hpp> + // for geometric_distribution + using ::boost::math::geometric_distribution; // + using ::boost::math::geometric; // typedef provides default type is double. + using ::boost::math::pdf; // Probability mass function. + using ::boost::math::cdf; // Cumulative density function. + using ::boost::math::quantile; + +#include <boost/math/distributions/negative_binomial.hpp> + // for negative_binomial_distribution + using boost::math::negative_binomial; // typedef provides default type is double. + +#include <boost/math/distributions/normal.hpp> + // for negative_binomial_distribution + using boost::math::normal; // typedef provides default type is double. + +#include <iostream> + using std::cout; using std::endl; + using std::noshowpoint; using std::fixed; using std::right; using std::left; +#include <iomanip> + using std::setprecision; using std::setw; + +#include <limits> + using std::numeric_limits; +//] [geometric_eg1_1] + +int main() +{ + cout <<"Geometric distribution example" << endl; + cout << endl; + + cout.precision(4); // But only show a few for this example. + try + { +//[geometric_eg1_2 +/*` +It is always sensible to use try and catch blocks because defaults policies are to +throw an exception if anything goes wrong. + +Simple try'n'catch blocks (see below) will ensure that you get a +helpful error message instead of an abrupt (and silent) program abort. + +[h6 Throwing a dice] +The Geometric distribution describes the probability (/p/) of a number of failures +to get the first success in /k/ Bernoulli trials. +(A [@http://en.wikipedia.org/wiki/Bernoulli_distribution Bernoulli trial] +is one with only two possible outcomes, success of failure, +and /p/ is the probability of success). + +Suppose an 'fair' 6-face dice is thrown repeatedly: +*/ + double success_fraction = 1./6; // success_fraction (p) = 0.1666 + // (so failure_fraction is 1 - success_fraction = 5./6 = 1- 0.1666 = 0.8333) + +/*`If the dice is thrown repeatedly until the *first* time a /three/ appears. +The probability distribution of the number of times it is thrown *not* getting a /three/ + (/not-a-threes/ number of failures to get a /three/) +is a geometric distribution with the success_fraction = 1/6 = 0.1666[recur]. + +We therefore start by constructing a geometric distribution +with the one parameter success_fraction, the probability of success. +*/ + geometric g6(success_fraction); // type double by default. +/*` +To confirm, we can echo the success_fraction parameter of the distribution. +*/ + cout << "success fraction of a six-sided dice is " << g6.success_fraction() << endl; +/*`So the probability of getting a three at the first throw (zero failures) is +*/ + cout << pdf(g6, 0) << endl; // 0.1667 + cout << cdf(g6, 0) << endl; // 0.1667 +/*`Note that the cdf and pdf are identical because the is only one throw. +If we want the probability of getting the first /three/ on the 2nd throw: +*/ + cout << pdf(g6, 1) << endl; // 0.1389 + +/*`If we want the probability of getting the first /three/ on the 1st or 2nd throw +(allowing one failure): +*/ + cout << "pdf(g6, 0) + pdf(g6, 1) = " << pdf(g6, 0) + pdf(g6, 1) << endl; +/*`Or more conveniently, and more generally, +we can use the Cumulative Distribution Function CDF.*/ + + cout << "cdf(g6, 1) = " << cdf(g6, 1) << endl; // 0.3056 + +/*`If we allow many more (12) throws, the probability of getting our /three/ gets very high:*/ + cout << "cdf(g6, 12) = " << cdf(g6, 12) << endl; // 0.9065 or 90% probability. +/*`If we want to be much more confident, say 99%, +we can estimate the number of throws to be this sure +using the inverse or quantile. +*/ + cout << "quantile(g6, 0.99) = " << quantile(g6, 0.99) << endl; // 24.26 +/*`Note that the value returned is not an integer: +if you want an integer result you should use either floor, round or ceil functions, +or use the policies mechanism. + +See __understand_dis_quant. + +The geometric distribution is related to the negative binomial +__spaces `negative_binomial_distribution(RealType r, RealType p);` with parameter /r/ = 1. +So we could get the same result using the negative binomial, +but using the geometric the results will be faster, and may be more accurate. +*/ + negative_binomial nb(1, success_fraction); + cout << pdf(nb, 1) << endl; // 0.1389 + cout << cdf(nb, 1) << endl; // 0.3056 +/*`We could also the complement to express the required probability +as 1 - 0.99 = 0.01 (and get the same result): +*/ + cout << "quantile(complement(g6, 1 - p)) " << quantile(complement(g6, 0.01)) << endl; // 24.26 +/*` +Note too that Boost.Math geometric distribution is implemented as a continuous function. +Unlike other implementations (for example R) it *uses* the number of failures as a *real* parameter, +not as an integer. If you want this integer behaviour, you may need to enforce this by +rounding the parameter you pass, probably rounding down, to the nearest integer. +For example, R returns the success fraction probability for all values of failures +from 0 to 0.999999 thus: +[pre +__spaces R> formatC(pgeom(0.0001,0.5, FALSE), digits=17) " 0.5" +] [/pre] +So in Boost.Math the equivalent is +*/ + geometric g05(0.5); // Probability of success = 0.5 or 50% + // Output all potentially significant digits for the type, here double. + +#ifdef BOOST_NO_CXX11_NUMERIC_LIMITS + int max_digits10 = 2 + (boost::math::policies::digits<double, boost::math::policies::policy<> >() * 30103UL) / 100000UL; + cout << "BOOST_NO_CXX11_NUMERIC_LIMITS is defined" << endl; +#else + int max_digits10 = std::numeric_limits<double>::max_digits10; +#endif + cout << "Show all potentially significant decimal digits std::numeric_limits<double>::max_digits10 = " + << max_digits10 << endl; + cout.precision(max_digits10); // + + cout << cdf(g05, 0.0001) << endl; // returns 0.5000346561579232, not exact 0.5. +/*`To get the R discrete behaviour, you simply need to round with, +for example, the `floor` function. +*/ + cout << cdf(g05, floor(0.0001)) << endl; // returns exactly 0.5 +/*` +[pre +`> formatC(pgeom(0.9999999,0.5, FALSE), digits=17) [1] " 0.25"` +`> formatC(pgeom(1.999999,0.5, FALSE), digits=17)[1] " 0.25" k = 1` +`> formatC(pgeom(1.9999999,0.5, FALSE), digits=17)[1] "0.12500000000000003" k = 2` +] [/pre] +shows that R makes an arbitrary round-up decision at about 1e7 from the next integer above. +This may be convenient in practice, and could be replicated in C++ if desired. + +[h6 Surveying customers to find one with a faulty product] +A company knows from warranty claims that 2% of their products will be faulty, +so the 'success_fraction' of finding a fault is 0.02. +It wants to interview a purchaser of faulty products to assess their 'user experience'. + +To estimate how many customers they will probably need to contact +in order to find one who has suffered from the fault, +we first construct a geometric distribution with probability 0.02, +and then chose a confidence, say 80%, 95%, or 99% to finding a customer with a fault. +Finally, we probably want to round up the result to the integer above using the `ceil` function. +(We could also use a policy, but that is hardly worthwhile for this simple application.) + +(This also assumes that each customer only buys one product: +if customers bought more than one item, +the probability of finding a customer with a fault obviously improves.) +*/ + cout.precision(5); + geometric g(0.02); // On average, 2 in 100 products are faulty. + double c = 0.95; // 95% confidence. + cout << " quantile(g, " << c << ") = " << quantile(g, c) << endl; + + cout << "To be " << c * 100 + << "% confident of finding we customer with a fault, need to survey " + << ceil(quantile(g, c)) << " customers." << endl; // 148 + c = 0.99; // Very confident. + cout << "To be " << c * 100 + << "% confident of finding we customer with a fault, need to survey " + << ceil(quantile(g, c)) << " customers." << endl; // 227 + c = 0.80; // Only reasonably confident. + cout << "To be " << c * 100 + << "% confident of finding we customer with a fault, need to survey " + << ceil(quantile(g, c)) << " customers." << endl; // 79 + +/*`[h6 Basket Ball Shooters] +According to Wikipedia, average pro basket ball players get +[@http://en.wikipedia.org/wiki/Free_throw free throws] +in the baskets 70 to 80 % of the time, +but some get as high as 95%, and others as low as 50%. +Suppose we want to compare the probabilities +of failing to get a score only on the first or on the fifth shot? +To start we will consider the average shooter, say 75%. +So we construct a geometric distribution +with success_fraction parameter 75/100 = 0.75. +*/ + cout.precision(2); + geometric gav(0.75); // Shooter averages 7.5 out of 10 in the basket. +/*`What is probability of getting 1st try in the basket, that is with no failures? */ + cout << "Probability of score on 1st try = " << pdf(gav, 0) << endl; // 0.75 +/*`This is, of course, the success_fraction probability 75%. +What is the probability that the shooter only scores on the fifth shot? +So there are 5-1 = 4 failures before the first success.*/ + cout << "Probability of score on 5th try = " << pdf(gav, 4) << endl; // 0.0029 +/*`Now compare this with the poor and the best players success fraction. +We need to constructing new distributions with the different success fractions, +and then get the corresponding probability density functions values: +*/ + geometric gbest(0.95); + cout << "Probability of score on 5th try = " << pdf(gbest, 4) << endl; // 5.9e-6 + geometric gmediocre(0.50); + cout << "Probability of score on 5th try = " << pdf(gmediocre, 4) << endl; // 0.031 +/*`So we can see the very much smaller chance (0.000006) of 4 failures by the best shooters, +compared to the 0.03 of the mediocre.*/ + +/*`[h6 Estimating failures] +Of course one man's failure is an other man's success. +So a fault can be defined as a 'success'. + +If a fault occurs once after 100 flights, then one might naively say +that the risk of fault is obviously 1 in 100 = 1/100, a probability of 0.01. + +This is the best estimate we can make, but while it is the truth, +it is not the whole truth, +for it hides the big uncertainty when estimating from a single event. +"One swallow doesn't make a summer." +To show the magnitude of the uncertainty, the geometric +(or the negative binomial) distribution can be used. + +If we chose the popular 95% confidence in the limits, corresponding to an alpha of 0.05, +because we are calculating a two-sided interval, we must divide alpha by two. +*/ + double alpha = 0.05; + double k = 100; // So frequency of occurrence is 1/100. + cout << "Probability is failure is " << 1/k << endl; + double t = geometric::find_lower_bound_on_p(k, alpha/2); + cout << "geometric::find_lower_bound_on_p(" << int(k) << ", " << alpha/2 << ") = " + << t << endl; // 0.00025 + t = geometric::find_upper_bound_on_p(k, alpha/2); + cout << "geometric::find_upper_bound_on_p(" << int(k) << ", " << alpha/2 << ") = " + << t << endl; // 0.037 +/*`So while we estimate the probability is 0.01, it might lie between 0.0003 and 0.04. +Even if we relax our confidence to alpha = 90%, the bounds only contract to 0.0005 and 0.03. +And if we require a high confidence, they widen to 0.00005 to 0.05. +*/ + alpha = 0.1; // 90% confidence. + t = geometric::find_lower_bound_on_p(k, alpha/2); + cout << "geometric::find_lower_bound_on_p(" << int(k) << ", " << alpha/2 << ") = " + << t << endl; // 0.0005 + t = geometric::find_upper_bound_on_p(k, alpha/2); + cout << "geometric::find_upper_bound_on_p(" << int(k) << ", " << alpha/2 << ") = " + << t << endl; // 0.03 + + alpha = 0.01; // 99% confidence. + t = geometric::find_lower_bound_on_p(k, alpha/2); + cout << "geometric::find_lower_bound_on_p(" << int(k) << ", " << alpha/2 << ") = " + << t << endl; // 5e-005 + t = geometric::find_upper_bound_on_p(k, alpha/2); + cout << "geometric::find_upper_bound_on_p(" << int(k) << ", " << alpha/2 << ") = " + << t << endl; // 0.052 +/*`In real life, there will usually be more than one event (fault or success), +when the negative binomial, which has the necessary extra parameter, will be needed. +*/ + +/*`As noted above, using a catch block is always a good idea, +even if you hope not to use it! +*/ + } + catch(const std::exception& e) + { // Since we have set an overflow policy of ignore_error, + // an overflow exception should never be thrown. + std::cout << "\nMessage from thrown exception was:\n " << e.what() << std::endl; +/*` +For example, without a ignore domain error policy, +if we asked for ``pdf(g, -1)`` for example, +we would get an unhelpful abort, but with a catch: +[pre +Message from thrown exception was: + Error in function boost::math::pdf(const exponential_distribution<double>&, double): + Number of failures argument is -1, but must be >= 0 ! +] [/pre] +*/ +//] [/ geometric_eg1_2] + } + return 0; +} // int main() + + +/* +Output is: + + Geometric distribution example + + success fraction of a six-sided dice is 0.1667 + 0.1667 + 0.1667 + 0.1389 + pdf(g6, 0) + pdf(g6, 1) = 0.3056 + cdf(g6, 1) = 0.3056 + cdf(g6, 12) = 0.9065 + quantile(g6, 0.99) = 24.26 + 0.1389 + 0.3056 + quantile(complement(g6, 1 - p)) 24.26 + 0.5000346561579232 + 0.5 + quantile(g, 0.95) = 147.28 + To be 95% confident of finding we customer with a fault, need to survey 148 customers. + To be 99% confident of finding we customer with a fault, need to survey 227 customers. + To be 80% confident of finding we customer with a fault, need to survey 79 customers. + Probability of score on 1st try = 0.75 + Probability of score on 5th try = 0.0029 + Probability of score on 5th try = 5.9e-006 + Probability of score on 5th try = 0.031 + Probability is failure is 0.01 + geometric::find_lower_bound_on_p(100, 0.025) = 0.00025 + geometric::find_upper_bound_on_p(100, 0.025) = 0.037 + geometric::find_lower_bound_on_p(100, 0.05) = 0.00051 + geometric::find_upper_bound_on_p(100, 0.05) = 0.03 + geometric::find_lower_bound_on_p(100, 0.005) = 5e-005 + geometric::find_upper_bound_on_p(100, 0.005) = 0.052 + +*/ + + + + + + + + + + diff --git a/src/boost/libs/math/example/handle_test_result.hpp b/src/boost/libs/math/example/handle_test_result.hpp new file mode 100644 index 000000000..cb1432a58 --- /dev/null +++ b/src/boost/libs/math/example/handle_test_result.hpp @@ -0,0 +1,220 @@ +// (C) Copyright John Maddock 2006-7. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_HANDLE_TEST_RESULT +#define BOOST_MATH_HANDLE_TEST_RESULT + +#include <boost/math/tools/stats.hpp> +#include <boost/math/tools/test.hpp> +#include <boost/math/tools/precision.hpp> +#include <boost/regex.hpp> +#include <boost/test/test_tools.hpp> +#include <iostream> +#include <iomanip> + +#if defined(BOOST_INTEL) +# pragma warning(disable:239) +# pragma warning(disable:264) +#endif + +// +// Every client of this header has to define this function, +// and initialise the table of expected results: +// +void expected_results(); + +typedef std::pair<boost::regex, std::pair<boost::uintmax_t, boost::uintmax_t> > expected_data_type; +typedef std::list<expected_data_type> list_type; + +inline list_type& + get_expected_data() +{ + static list_type data; + return data; +} + +inline void add_expected_result( + const char* compiler, + const char* library, + const char* platform, + const char* type_name, + const char* test_name, + const char* group_name, + boost::uintmax_t max_peek_error, + boost::uintmax_t max_mean_error) +{ + std::string re("(?:"); + re += compiler; + re += ")"; + re += "\\|"; + re += "(?:"; + re += library; + re += ")"; + re += "\\|"; + re += "(?:"; + re += platform; + re += ")"; + re += "\\|"; + re += "(?:"; + re += type_name; + re += ")"; + re += "\\|"; + re += "(?:"; + re += test_name; + re += ")"; + re += "\\|"; + re += "(?:"; + re += group_name; + re += ")"; + get_expected_data().push_back( + std::make_pair(boost::regex(re, boost::regex::perl | boost::regex::icase), + std::make_pair(max_peek_error, max_mean_error))); +} + +inline std::string build_test_name(const char* type_name, const char* test_name, const char* group_name) +{ + std::string result(BOOST_COMPILER); + result += "|"; + result += BOOST_STDLIB; + result += "|"; + result += BOOST_PLATFORM; + result += "|"; + result += type_name; + result += "|"; + result += group_name; + result += "|"; + result += test_name; + return result; +} + +inline const std::pair<boost::uintmax_t, boost::uintmax_t>& + get_max_errors(const char* type_name, const char* test_name, const char* group_name) +{ + static const std::pair<boost::uintmax_t, boost::uintmax_t> defaults(1, 1); + std::string name = build_test_name(type_name, test_name, group_name); + list_type& l = get_expected_data(); + list_type::const_iterator a(l.begin()), b(l.end()); + while(a != b) + { + if(regex_match(name, a->first)) + { +#if 0 + std::cout << name << std::endl; + std::cout << a->first.str() << std::endl; +#endif + return a->second; + } + ++a; + } + return defaults; +} + +template <class T, class Seq> +void handle_test_result(const boost::math::tools::test_result<T>& result, + const Seq& worst, int row, + const char* type_name, + const char* test_name, + const char* group_name) +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif + using namespace std; // To aid selection of the right pow. + T eps = boost::math::tools::epsilon<T>(); + std::cout << std::setprecision(4); + + T max_error_found = (result.max)()/eps; + T mean_error_found = result.rms()/eps; + // + // Begin by printing the main tag line with the results: + // + std::cout << test_name << "<" << type_name << "> Max = " << max_error_found + << " RMS Mean=" << mean_error_found; + // + // If the max error is non-zero, give the row of the table that + // produced the worst error: + // + if((result.max)() != 0) + { + std::cout << "\n worst case at row: " + << row << "\n { "; + if(std::numeric_limits<T>::digits10) + { + std::cout << std::setprecision(std::numeric_limits<T>::digits10 + 2); + } + else + { + std::cout << std::setprecision(std::numeric_limits<long double>::digits10 + 2); + } + for(unsigned i = 0; i < worst.size(); ++i) + { + if(i) + std::cout << ", "; +#if defined(__SGI_STL_PORT) + std::cout << boost::math::tools::real_cast<double>(worst[i]); +#else + std::cout << worst[i]; +#endif + } + std::cout << " }"; + } + std::cout << std::endl; + // + // Now verify that the results are within our expected bounds: + // + std::pair<boost::uintmax_t, boost::uintmax_t> const& bounds = get_max_errors(type_name, test_name, group_name); + if(bounds.first < max_error_found) + { + std::cerr << "Peak error greater than expected value of " << bounds.first << std::endl; + BOOST_CHECK(bounds.first >= max_error_found); + } + if(bounds.second < mean_error_found) + { + std::cerr << "Mean error greater than expected value of " << bounds.second << std::endl; + BOOST_CHECK(bounds.second >= mean_error_found); + } + std::cout << std::endl; +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template <class T, class Seq> +void print_test_result(const boost::math::tools::test_result<T>& result, + const Seq& worst, int row, const char* name, const char* test) +{ + using namespace std; // To aid selection of the right pow. + T eps = boost::math::tools::epsilon<T>(); + std::cout << std::setprecision(4); + + T max_error_found = (result.max)()/eps; + T mean_error_found = result.rms()/eps; + // + // Begin by printing the main tag line with the results: + // + std::cout << test << "(" << name << ") Max = " << max_error_found + << " RMS Mean=" << mean_error_found; + // + // If the max error is non-zero, give the row of the table that + // produced the worst error: + // + if((result.max)() != 0) + { + std::cout << "\n worst case at row: " + << row << "\n { "; + for(unsigned i = 0; i < worst.size(); ++i) + { + if(i) + std::cout << ", "; + std::cout << worst[i]; + } + std::cout << " }"; + } + std::cout << std::endl; +} + +#endif // BOOST_MATH_HANDLE_TEST_RESULT + diff --git a/src/boost/libs/math/example/hyperexponential_more_snips.cpp b/src/boost/libs/math/example/hyperexponential_more_snips.cpp new file mode 100644 index 000000000..ba9d5010e --- /dev/null +++ b/src/boost/libs/math/example/hyperexponential_more_snips.cpp @@ -0,0 +1,155 @@ +// Copyright 2014 Marco Guazzone (marco.guazzone@gmail.com). + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Caution: this file contains Quickbook markup as well as code +// and comments, don't change any of the special comment markups! + + +//[hyperexponential_more_snip1 +#include <boost/math/distributions.hpp> +#include <iostream> +#include <string> + +struct ds_info +{ + std::string name; + double iat_sample_mean; + double iat_sample_sd; + boost::math::hyperexponential iat_he; + double multi_lt_sample_mean; + double multi_lt_sample_sd; + boost::math::hyperexponential multi_lt_he; + double single_lt_sample_mean; + double single_lt_sample_sd; + boost::math::hyperexponential single_lt_he; +}; + +// DS1 dataset +ds_info make_ds1() +{ + ds_info ds; + + ds.name = "DS1"; + + // VM interarrival time distribution + const double iat_fit_probs[] = { 0.34561,0.08648,0.56791 }; + const double iat_fit_rates[] = { 0.0008,0.00005,0.02894 }; + ds.iat_sample_mean = 2202.1; + ds.iat_sample_sd = 2.2e+4; + ds.iat_he = boost::math::hyperexponential(iat_fit_probs, iat_fit_rates); + + // Multi-core VM lifetime distribution + const double multi_lt_fit_probs[] = { 0.24667,0.37948,0.37385 }; + const double multi_lt_fit_rates[] = { 0.00004,0.000002,0.00059 }; + ds.multi_lt_sample_mean = 257173; + ds.multi_lt_sample_sd = 4.6e+5; + ds.multi_lt_he = boost::math::hyperexponential(multi_lt_fit_probs, multi_lt_fit_rates); + + // Single-core VM lifetime distribution + const double single_lt_fit_probs[] = { 0.09325,0.22251,0.68424 }; + const double single_lt_fit_rates[] = { 0.000003,0.00109,0.00109 }; + ds.single_lt_sample_mean = 28754.4; + ds.single_lt_sample_sd = 1.6e+5; + ds.single_lt_he = boost::math::hyperexponential(single_lt_fit_probs, single_lt_fit_rates); + + return ds; +} + +// DS2 dataset +ds_info make_ds2() +{ + ds_info ds; + + ds.name = "DS2"; + + // VM interarrival time distribution + const double iat_fit_probs[] = { 0.38881,0.18227,0.42892 }; + const double iat_fit_rates[] = { 0.000006,0.05228,0.00081 }; + ds.iat_sample_mean = 41285.7; + ds.iat_sample_sd = 1.1e+05; + ds.iat_he = boost::math::hyperexponential(iat_fit_probs, iat_fit_rates); + + // Multi-core VM lifetime distribution + const double multi_lt_fit_probs[] = { 0.42093,0.43960,0.13947 }; + const double multi_lt_fit_rates[] = { 0.00186,0.00008,0.0000008 }; + ds.multi_lt_sample_mean = 144669.0; + ds.multi_lt_sample_sd = 7.9e+05; + ds.multi_lt_he = boost::math::hyperexponential(multi_lt_fit_probs, multi_lt_fit_rates); + + // Single-core VM lifetime distribution + const double single_lt_fit_probs[] = { 0.44885,0.30675,0.2444 }; + const double single_lt_fit_rates[] = { 0.00143,0.00005,0.0000004 }; + ds.single_lt_sample_mean = 599815.0; + ds.single_lt_sample_sd = 1.7e+06; + ds.single_lt_he = boost::math::hyperexponential(single_lt_fit_probs, single_lt_fit_rates); + + return ds; +} + +// DS3 dataset +ds_info make_ds3() +{ + ds_info ds; + + ds.name = "DS3"; + + // VM interarrival time distribution + const double iat_fit_probs[] = { 0.39442,0.24644,0.35914 }; + const double iat_fit_rates[] = { 0.00030,0.00003,0.00257 }; + ds.iat_sample_mean = 11238.8; + ds.iat_sample_sd = 3.0e+04; + ds.iat_he = boost::math::hyperexponential(iat_fit_probs, iat_fit_rates); + + // Multi-core VM lifetime distribution + const double multi_lt_fit_probs[] = { 0.37621,0.14838,0.47541 }; + const double multi_lt_fit_rates[] = { 0.00498,0.000005,0.00022 }; + ds.multi_lt_sample_mean = 30739.2; + ds.multi_lt_sample_sd = 1.6e+05; + ds.multi_lt_he = boost::math::hyperexponential(multi_lt_fit_probs, multi_lt_fit_rates); + + // Single-core VM lifetime distribution + const double single_lt_fit_probs[] = { 0.34131,0.12544,0.53325 }; + const double single_lt_fit_rates[] = { 0.000297,0.000003,0.00410 }; + ds.single_lt_sample_mean = 44447.8; + ds.single_lt_sample_sd = 2.2e+05; + ds.single_lt_he = boost::math::hyperexponential(single_lt_fit_probs, single_lt_fit_rates); + + return ds; +} + +void print_fitted(ds_info const& ds) +{ + const double secs_in_a_hour = 3600; + const double secs_in_a_month = 30 * 24 * secs_in_a_hour; + + std::cout << "### " << ds.name << std::endl; + std::cout << "* Fitted Request Interarrival Time" << std::endl; + std::cout << " - Mean (SD): " << boost::math::mean(ds.iat_he) << " (" << boost::math::standard_deviation(ds.iat_he) << ") seconds." << std::endl; + std::cout << " - 99th Percentile: " << boost::math::quantile(ds.iat_he, 0.99) << " seconds." << std::endl; + std::cout << " - Probability that a VM will arrive within 30 minutes: " << boost::math::cdf(ds.iat_he, secs_in_a_hour / 2.0) << std::endl; + std::cout << " - Probability that a VM will arrive after 1 hour: " << boost::math::cdf(boost::math::complement(ds.iat_he, secs_in_a_hour)) << std::endl; + std::cout << "* Fitted Multi-core VM Lifetime" << std::endl; + std::cout << " - Mean (SD): " << boost::math::mean(ds.multi_lt_he) << " (" << boost::math::standard_deviation(ds.multi_lt_he) << ") seconds." << std::endl; + std::cout << " - 99th Percentile: " << boost::math::quantile(ds.multi_lt_he, 0.99) << " seconds." << std::endl; + std::cout << " - Probability that a VM will last for less than 1 month: " << boost::math::cdf(ds.multi_lt_he, secs_in_a_month) << std::endl; + std::cout << " - Probability that a VM will last for more than 3 months: " << boost::math::cdf(boost::math::complement(ds.multi_lt_he, 3.0*secs_in_a_month)) << std::endl; + std::cout << "* Fitted Single-core VM Lifetime" << std::endl; + std::cout << " - Mean (SD): " << boost::math::mean(ds.single_lt_he) << " (" << boost::math::standard_deviation(ds.single_lt_he) << ") seconds." << std::endl; + std::cout << " - 99th Percentile: " << boost::math::quantile(ds.single_lt_he, 0.99) << " seconds." << std::endl; + std::cout << " - Probability that a VM will last for less than 1 month: " << boost::math::cdf(ds.single_lt_he, secs_in_a_month) << std::endl; + std::cout << " - Probability that a VM will last for more than 3 months: " << boost::math::cdf(boost::math::complement(ds.single_lt_he, 3.0*secs_in_a_month)) << std::endl; +} + +int main() +{ + print_fitted(make_ds1()); + + print_fitted(make_ds2()); + + print_fitted(make_ds3()); +} +//] diff --git a/src/boost/libs/math/example/hyperexponential_snips.cpp b/src/boost/libs/math/example/hyperexponential_snips.cpp new file mode 100644 index 000000000..785e500d2 --- /dev/null +++ b/src/boost/libs/math/example/hyperexponential_snips.cpp @@ -0,0 +1,103 @@ +// Copyright John Maddock 2014. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Caution: this file contains Quickbook markup as well as code +// and comments, don't change any of the special comment markups! + +#ifdef _MSC_VER +# pragma warning (disable : 4996) // disable -D_SCL_SECURE_NO_WARNINGS C++ 'Checked Iterators' +#endif + +#include <boost/math/distributions/hyperexponential.hpp> +#include <iostream> + +#ifndef BOOST_NO_CXX11_HDR_ARRAY +#include <array> +#endif + +int main() +{ + { +//[hyperexponential_snip1 +//=#include <boost/math/distributions/hyperexponential.hpp> +//=#include <iostream> +//=int main() +//={ + const double rates[] = { 1.0 / 10.0, 1.0 / 12.0 }; + + boost::math::hyperexponential he(rates); + + std::cout << "Average lifetime: " + << boost::math::mean(he) + << " years" << std::endl; + std::cout << "Probability that the appliance will work for more than 15 years: " + << boost::math::cdf(boost::math::complement(he, 15.0)) + << std::endl; +//=} +//] + } + using namespace boost::math; +#ifndef BOOST_NO_CXX11_HDR_ARRAY + { + //[hyperexponential_snip2 + std::array<double, 2> phase_prob = { 0.5, 0.5 }; + std::array<double, 2> rates = { 1.0 / 10, 1.0 / 12 }; + + hyperexponential he(phase_prob.begin(), phase_prob.end(), rates.begin(), rates.end()); + //] + } + + { + //[hyperexponential_snip3 + // We could be using any standard library container here... vector, deque, array, list etc: + std::array<double, 2> phase_prob = { 0.5, 0.5 }; + std::array<double, 2> rates = { 1.0 / 10, 1.0 / 12 }; + + hyperexponential he1(phase_prob, rates); // Construct from standard library container. + + double phase_probs2[] = { 0.5, 0.5 }; + double rates2[] = { 1.0 / 10, 1.0 / 12 }; + + hyperexponential he2(phase_probs2, rates2); // Construct from native C++ array. + //] + } + { + //[hyperexponential_snip4 + // We could be using any standard library container here... vector, deque, array, list etc: + std::array<double, 2> rates = { 1.0 / 10, 1.0 / 12 }; + + hyperexponential he(rates.begin(), rates.end()); + + BOOST_ASSERT(he.probabilities()[0] == 0.5); // Phase probabilities will be equal and normalised to unity. + //] + } + { + //[hyperexponential_snip5 + std::array<double, 2> rates = { 1.0 / 10, 1.0 / 12 }; + + hyperexponential he(rates); + + BOOST_ASSERT(he.probabilities()[0] == 0.5); // Phase probabilities will be equal and normalised to unity. + //] + } +#endif +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) && !(defined(BOOST_GCC_VERSION) && (BOOST_GCC_VERSION < 40500)) + { + //[hyperexponential_snip6 + hyperexponential he = { { 0.5, 0.5 }, { 1.0 / 10, 1.0 / 12 } }; + //] + } + { + //[hyperexponential_snip7 + hyperexponential he = { 1.0 / 10, 1.0 / 12 }; + + BOOST_ASSERT(he.probabilities()[0] == 0.5); + //] + } +#endif + return 0; +} diff --git a/src/boost/libs/math/example/inspect_fp.cpp b/src/boost/libs/math/example/inspect_fp.cpp new file mode 100644 index 000000000..0838b8ddd --- /dev/null +++ b/src/boost/libs/math/example/inspect_fp.cpp @@ -0,0 +1,224 @@ +// inspect.cpp + +// Copyright (c) 2006 Johan Rade + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +//------------------------------------- + +#include <cstring> + +#include <iomanip> +#include <iostream> +#include <limits> +#include <boost/detail/endian.hpp> + +//------------------------------------------------------------------------------ + +bool is_big_endian() +{ + float x = 1.0f; + unsigned char first_byte; + memcpy(&first_byte, &x, 1); + return first_byte != 0; +} + +//------------------------------------------------------------------------------ + +void print_processor(); +void print_endianness(); +template<class T> void print_table(); +template<class T> void print_row(const char* name, T val, bool ok = true); + +//------------------------------------------------------------------------------ + +int main() +{ + std::cout << '\n'; + + print_processor(); + + print_endianness(); + + std::cout << "---------- float --------------------\n\n"; + print_table<float>(); + + std::cout << "---------- double -------------------\n\n"; + print_table<double>(); + + std::cout << "---------- long double --------------\n\n"; + print_table<long double>(); + + return 0; +} + +//------------------------------------------------------------------------------ + +void print_processor() +{ +#if defined(__i386) || defined(__i386__) || defined(_M_IX86) \ + || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) \ + || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) + + std::cout << "Processor: x86 or x64\n\n"; + +#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64) + + std::cout << "Processor: ia64\n\n"; + +#elif defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) \ + || defined(__ppc) || defined(__ppc__) || defined(__PPC__) + + std::cout << "Processor: PowerPC\n\n"; + +#elif defined(__m68k) || defined(__m68k__) \ + || defined(__mc68000) || defined(__mc68000__) \ + + std::cout << "Processor: Motorola 68K\n\n"; + +#else + + std::cout << "Processor: Unknown\n\n"; + +#endif +} + +void print_endianness() +{ + if(is_big_endian()) + std::cout << "This platform is big-endian.\n"; + else + std::cout << "This platform is little-endian.\n"; + +#ifdef BOOST_BIG_ENDIAN + std::cout << "BOOST_BIG_ENDIAN is defined.\n\n"; +#endif +#if defined BOOST_LITTLE_ENDIAN + std::cout << "BOOST_LITTTLE_ENDIAN is defined.\n\n"; +#endif +} + +//.............................................................................. + +template<class T> void print_table() +{ + print_row("0", (T)0); + print_row("sn.min", std::numeric_limits<T>::denorm_min(), + std::numeric_limits<T>::has_denorm); + print_row("-sn.min", -std::numeric_limits<T>::denorm_min(), + std::numeric_limits<T>::has_denorm); + print_row("n.min/256", (std::numeric_limits<T>::min)()/256); + print_row("n.min/2", (std::numeric_limits<T>::min)()/2); + print_row("-n.min/2", -(std::numeric_limits<T>::min)()/2); + print_row("n.min", (std::numeric_limits<T>::min)()); + print_row("1", (T)1); + print_row("3/4", (T)3/(T)4); + print_row("4/3", (T)4/(T)3); + print_row("max", (std::numeric_limits<T>::max)()); + print_row("inf", std::numeric_limits<T>::infinity(), + std::numeric_limits<T>::has_infinity); + print_row("q.nan", std::numeric_limits<T>::quiet_NaN(), + std::numeric_limits<T>::has_quiet_NaN); + print_row("s.nan", std::numeric_limits<T>::signaling_NaN(), + std::numeric_limits<T>::has_signaling_NaN); + + std::cout << "\n\n"; +} + +template<class T> +void print_row(const char* name, T val, bool ok) +{ + std::cout << std::left << std::setw(10) << name << std::right; + + std::cout << std::hex << std::setfill('0'); + + if(ok) { + if(is_big_endian()) { + for(size_t i = 0; i < sizeof(T); ++i) { + unsigned char c = *(reinterpret_cast<unsigned char*>(&val) + i); + std::cout << std::setw(2) + << static_cast<unsigned int>(c) << ' '; + } + } + else { + for(size_t i = sizeof(T) - 1; i < sizeof(T); --i) { + unsigned char c = *(reinterpret_cast<unsigned char*>(&val) + i); + std::cout << std::setw(2) + << static_cast<unsigned int>(c) << ' '; + } + } + } + else { + for(size_t i = 0; i < sizeof(T); ++i) + std::cout << "-- "; + } + + std::cout << '\n'; + std::cout << std::dec << std::setfill(' '); +} + +/* + +Sample output on an AMD Quadcore running MSVC 10 + + Processor: x86 or x64 + + This platform is little-endian. + BOOST_LITTTLE_ENDIAN is defined. + + ---------- float -------------------- + + 0 00 00 00 00 + sn.min 00 00 00 01 + -sn.min 80 00 00 01 + n.min/256 00 00 80 00 + n.min/2 00 40 00 00 + -n.min/2 80 40 00 00 + n.min 00 80 00 00 + 1 3f 80 00 00 + 3/4 3f 40 00 00 + 4/3 3f aa aa ab + max 7f 7f ff ff + inf 7f 80 00 00 + q.nan 7f c0 00 00 + s.nan 7f c0 00 01 + + + ---------- double ------------------- + + 0 00 00 00 00 00 00 00 00 + sn.min 00 00 00 00 00 00 00 01 + -sn.min 80 00 00 00 00 00 00 01 + n.min/256 00 00 10 00 00 00 00 00 + n.min/2 00 08 00 00 00 00 00 00 + -n.min/2 80 08 00 00 00 00 00 00 + n.min 00 10 00 00 00 00 00 00 + 1 3f f0 00 00 00 00 00 00 + 3/4 3f e8 00 00 00 00 00 00 + 4/3 3f f5 55 55 55 55 55 55 + max 7f ef ff ff ff ff ff ff + inf 7f f0 00 00 00 00 00 00 + q.nan 7f f8 00 00 00 00 00 00 + s.nan 7f f8 00 00 00 00 00 01 + + + ---------- long double -------------- + + 0 00 00 00 00 00 00 00 00 + sn.min 00 00 00 00 00 00 00 01 + -sn.min 80 00 00 00 00 00 00 01 + n.min/256 00 00 10 00 00 00 00 00 + n.min/2 00 08 00 00 00 00 00 00 + -n.min/2 80 08 00 00 00 00 00 00 + n.min 00 10 00 00 00 00 00 00 + 1 3f f0 00 00 00 00 00 00 + 3/4 3f e8 00 00 00 00 00 00 + 4/3 3f f5 55 55 55 55 55 55 + max 7f ef ff ff ff ff ff ff + inf 7f f0 00 00 00 00 00 00 + q.nan 7f f8 00 00 00 00 00 00 + s.nan 7f f8 00 00 00 00 00 01 + + */ diff --git a/src/boost/libs/math/example/inverse_chi_squared_bayes_eg.cpp b/src/boost/libs/math/example/inverse_chi_squared_bayes_eg.cpp new file mode 100644 index 000000000..364094325 --- /dev/null +++ b/src/boost/libs/math/example/inverse_chi_squared_bayes_eg.cpp @@ -0,0 +1,338 @@ +// inverse_chi_squared_bayes_eg.cpp + +// Copyright Thomas Mang 2011. +// Copyright Paul A. Bristow 2011. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// This file is written to be included from a Quickbook .qbk document. +// It can still be compiled by the C++ compiler, and run. +// Any output can also be added here as comment or included or pasted in elsewhere. +// Caution: this file contains Quickbook markup as well as code +// and comments: don't change any of the special comment markups! + +#include <iostream> +// using std::cout; using std::endl; + +//#define define possible error-handling macros here? + +#include "boost/math/distributions.hpp" +// using ::boost::math::inverse_chi_squared; + +int main() +{ + using std::cout; using std::endl; + + using ::boost::math::inverse_chi_squared; + using ::boost::math::inverse_gamma; + using ::boost::math::quantile; + using ::boost::math::cdf; + + cout << "Inverse_chi_squared_distribution Bayes example: " << endl <<endl; + + cout.precision(3); +// Examples of using the inverse_chi_squared distribution. + +//[inverse_chi_squared_bayes_eg_1 +/*` +The scaled-inversed-chi-squared distribution is the conjugate prior distribution +for the variance ([sigma][super 2]) parameter of a normal distribution +with known expectation ([mu]). +As such it has widespread application in Bayesian statistics: + +In [@http://en.wikipedia.org/wiki/Bayesian_inference Bayesian inference], +the strength of belief into certain parameter values is +itself described through a distribution. Parameters +hence become themselves modelled and interpreted as random variables. + +In this worked example, we perform such a Bayesian analysis by using +the scaled-inverse-chi-squared distribution as prior and posterior distribution +for the variance parameter of a normal distribution. + +For more general information on Bayesian type of analyses, +see: + +* Andrew Gelman, John B. Carlin, Hal E. Stern, Donald B. Rubin, Bayesian Data Analysis, +2003, ISBN 978-1439840955. + +* Jim Albert, Bayesian Computation with R, Springer, 2009, ISBN 978-0387922973. + +(As the scaled-inversed-chi-squared is another parameterization of the inverse-gamma distribution, +this example could also have used the inverse-gamma distribution). + +Consider precision machines which produce balls for a high-quality ball bearing. +Ideally each ball should have a diameter of precisely 3000 [mu]m (3 mm). +Assume that machines generally produce balls of that size on average (mean), +but individual balls can vary slightly in either direction +following (approximately) a normal distribution. Depending on various production conditions +(e.g. raw material used for balls, workplace temperature and humidity, maintenance frequency and quality) +some machines produce balls tighter distributed around the target of 3000 [mu]m, +while others produce balls with a wider distribution. +Therefore the variance parameter of the normal distribution of the ball sizes varies +from machine to machine. An extensive survey by the precision machinery manufacturer, however, +has shown that most machines operate with a variance between 15 and 50, +and near 25 [mu]m[super 2] on average. + +Using this information, we want to model the variance of the machines. +The variance is strictly positive, and therefore we look for a statistical distribution +with support in the positive domain of the real numbers. +Given the expectation of the normal distribution of the balls is known (3000 [mu]m), +for reasons of conjugacy, it is customary practice in Bayesian statistics +to model the variance to be scaled-inverse-chi-squared distributed. + +In a first step, we will try to use the survey information to model +the general knowledge about the variance parameter of machines measured by the manufacturer. +This will provide us with a generic prior distribution that is applicable +if nothing more specific is known about a particular machine. + +In a second step, we will then combine the prior-distribution information in a Bayesian analysis +with data on a specific single machine to derive a posterior distribution for that machine. + +[h5 Step one: Using the survey information.] + +Using the survey results, we try to find the parameter set +of a scaled-inverse-chi-squared distribution +so that the properties of this distribution match the results. +Using the mathematical properties of the scaled-inverse-chi-squared distribution +as guideline, we see that that both the mean and mode of the scaled-inverse-chi-squared distribution +are approximately given by the scale parameter (s) of the distribution. As the survey machines operated at a +variance of 25 [mu]m[super 2] on average, we hence set the scale parameter (s[sub prior]) of our prior distribution +equal to this value. Using some trial-and-error and calls to the global quantile function, we also find that a +value of 20 for the degrees-of-freedom ([nu][sub prior]) parameter is adequate so that +most of the prior distribution mass is located between 15 and 50 (see figure below). + +We first construct our prior distribution using these values, and then list out a few quantiles: + +*/ + double priorDF = 20.0; + double priorScale = 25.0; + + inverse_chi_squared prior(priorDF, priorScale); + // Using an inverse_gamma distribution instead, we could equivalently write + // inverse_gamma prior(priorDF / 2.0, priorScale * priorDF / 2.0); + + cout << "Prior distribution:" << endl << endl; + cout << " 2.5% quantile: " << quantile(prior, 0.025) << endl; + cout << " 50% quantile: " << quantile(prior, 0.5) << endl; + cout << " 97.5% quantile: " << quantile(prior, 0.975) << endl << endl; + + //] [/inverse_chi_squared_bayes_eg_1] + +//[inverse_chi_squared_bayes_eg_output_1 +/*`This produces this output: + + Prior distribution: + + 2.5% quantile: 14.6 + 50% quantile: 25.9 + 97.5% quantile: 52.1 + +*/ +//] [/inverse_chi_squared_bayes_eg_output_1] + +//[inverse_chi_squared_bayes_eg_2 +/*` +Based on this distribution, we can now calculate the probability of having a machine +working with an unusual work precision (variance) at <= 15 or > 50. +For this task, we use calls to the `boost::math::` functions `cdf` and `complement`, +respectively, and find a probability of about 0.031 (3.1%) for each case. +*/ + + cout << " probability variance <= 15: " << boost::math::cdf(prior, 15.0) << endl; + cout << " probability variance <= 25: " << boost::math::cdf(prior, 25.0) << endl; + cout << " probability variance > 50: " + << boost::math::cdf(boost::math::complement(prior, 50.0)) + << endl << endl; + //] [/inverse_chi_squared_bayes_eg_2] + +//[inverse_chi_squared_bayes_eg_output_2 +/*`This produces this output: + + probability variance <= 15: 0.031 + probability variance <= 25: 0.458 + probability variance > 50: 0.0318 + +*/ +//] [/inverse_chi_squared_bayes_eg_output_2] + +//[inverse_chi_squared_bayes_eg_3 +/*`Therefore, only 3.1% of all precision machines produce balls with a variance of 15 or less +(particularly precise machines), +but also only 3.2% of all machines produce balls +with a variance of as high as 50 or more (particularly imprecise machines). Moreover, slightly more than +one-half (1 - 0.458 = 54.2%) of the machines work at a variance greater than 25. + +Notice here the distinction between a +[@http://en.wikipedia.org/wiki/Bayesian_inference Bayesian] analysis and a +[@http://en.wikipedia.org/wiki/Frequentist_inference frequentist] analysis: +because we model the variance as random variable itself, +we can calculate and straightforwardly interpret probabilities for given parameter values directly, +while such an approach is not possible (and interpretationally a strict ['must-not]) in the frequentist +world. + +[h5 Step 2: Investigate a single machine] + +In the second step, we investigate a single machine, +which is suspected to suffer from a major fault +as the produced balls show fairly high size variability. +Based on the prior distribution of generic machinery performance (derived above) +and data on balls produced by the suspect machine, we calculate the posterior distribution for that +machine and use its properties for guidance regarding continued machine operation or suspension. + +It can be shown that if the prior distribution +was chosen to be scaled-inverse-chi-square distributed, +then the posterior distribution is also scaled-inverse-chi-squared-distributed +(prior and posterior distributions are hence conjugate). +For more details regarding conjugacy and formula to derive the parameters set +for the posterior distribution see +[@http://en.wikipedia.org/wiki/Conjugate_prior Conjugate prior]. + + +Given the prior distribution parameters and sample data (of size n), the posterior distribution parameters +are given by the two expressions: + +__spaces [nu][sub posterior] = [nu][sub prior] + n + +which gives the posteriorDF below, and + +__spaces s[sub posterior] = ([nu][sub prior]s[sub prior] + [Sigma][super n][sub i=1](x[sub i] - [mu])[super 2]) / ([nu][sub prior] + n) + +which after some rearrangement gives the formula for the posteriorScale below. + +Machine-specific data consist of 100 balls which were accurately measured +and show the expected mean of 3000 [mu]m and a sample variance of 55 (calculated for a sample mean defined to be 3000 exactly). +From these data, the prior parameterization, and noting that the term +[Sigma][super n][sub i=1](x[sub i] - [mu])[super 2] equals the sample variance multiplied by n - 1, +it follows that the posterior distribution of the variance parameter +is scaled-inverse-chi-squared distribution with degrees-of-freedom ([nu][sub posterior]) = 120 and +scale (s[sub posterior]) = 49.54. +*/ + + int ballsSampleSize = 100; + cout <<"balls sample size: " << ballsSampleSize << endl; + double ballsSampleVariance = 55.0; + cout <<"balls sample variance: " << ballsSampleVariance << endl; + + double posteriorDF = priorDF + ballsSampleSize; + cout << "prior degrees-of-freedom: " << priorDF << endl; + cout << "posterior degrees-of-freedom: " << posteriorDF << endl; + + double posteriorScale = + (priorDF * priorScale + (ballsSampleVariance * (ballsSampleSize - 1))) / posteriorDF; + cout << "prior scale: " << priorScale << endl; + cout << "posterior scale: " << posteriorScale << endl; + +/*`An interesting feature here is that one needs only to know a summary statistics of the sample +to parameterize the posterior distribution: the 100 individual ball measurements are irrelevant, +just knowledge of the sample variance and number of measurements is sufficient. +*/ + +//] [/inverse_chi_squared_bayes_eg_3] + +//[inverse_chi_squared_bayes_eg_output_3 +/*`That produces this output: + + + balls sample size: 100 + balls sample variance: 55 + prior degrees-of-freedom: 20 + posterior degrees-of-freedom: 120 + prior scale: 25 + posterior scale: 49.5 + + */ +//] [/inverse_chi_squared_bayes_eg_output_3] + +//[inverse_chi_squared_bayes_eg_4 +/*`To compare the generic machinery performance with our suspect machine, +we calculate again the same quantiles and probabilities as above, +and find a distribution clearly shifted to greater values (see figure). + +[graph prior_posterior_plot] + +*/ + + inverse_chi_squared posterior(posteriorDF, posteriorScale); + + cout << "Posterior distribution:" << endl << endl; + cout << " 2.5% quantile: " << boost::math::quantile(posterior, 0.025) << endl; + cout << " 50% quantile: " << boost::math::quantile(posterior, 0.5) << endl; + cout << " 97.5% quantile: " << boost::math::quantile(posterior, 0.975) << endl << endl; + + cout << " probability variance <= 15: " << boost::math::cdf(posterior, 15.0) << endl; + cout << " probability variance <= 25: " << boost::math::cdf(posterior, 25.0) << endl; + cout << " probability variance > 50: " + << boost::math::cdf(boost::math::complement(posterior, 50.0)) << endl; + +//] [/inverse_chi_squared_bayes_eg_4] + +//[inverse_chi_squared_bayes_eg_output_4 +/*`This produces this output: + + Posterior distribution: + + 2.5% quantile: 39.1 + 50% quantile: 49.8 + 97.5% quantile: 64.9 + + probability variance <= 15: 2.97e-031 + probability variance <= 25: 8.85e-010 + probability variance > 50: 0.489 + +*/ +//] [/inverse_chi_squared_bayes_eg_output_4] + +//[inverse_chi_squared_bayes_eg_5 +/*`Indeed, the probability that the machine works at a low variance (<= 15) is almost zero, +and even the probability of working at average or better performance is negligibly small +(less than one-millionth of a permille). +On the other hand, with an almost near-half probability (49%), the machine operates in the +extreme high variance range of > 50 characteristic for poorly performing machines. + +Based on this information the operation of the machine is taken out of use and serviced. + +In summary, the Bayesian analysis allowed us to make exact probabilistic statements about a +parameter of interest, and hence provided us results with straightforward interpretation. + +*/ +//] [/inverse_chi_squared_bayes_eg_5] + +} // int main() + +//[inverse_chi_squared_bayes_eg_output +/*` +[pre + Inverse_chi_squared_distribution Bayes example: + + Prior distribution: + + 2.5% quantile: 14.6 + 50% quantile: 25.9 + 97.5% quantile: 52.1 + + probability variance <= 15: 0.031 + probability variance <= 25: 0.458 + probability variance > 50: 0.0318 + + balls sample size: 100 + balls sample variance: 55 + prior degrees-of-freedom: 20 + posterior degrees-of-freedom: 120 + prior scale: 25 + posterior scale: 49.5 + Posterior distribution: + + 2.5% quantile: 39.1 + 50% quantile: 49.8 + 97.5% quantile: 64.9 + + probability variance <= 15: 2.97e-031 + probability variance <= 25: 8.85e-010 + probability variance > 50: 0.489 + +] [/pre] +*/ +//] [/inverse_chi_squared_bayes_eg_output] diff --git a/src/boost/libs/math/example/inverse_chi_squared_example.cpp b/src/boost/libs/math/example/inverse_chi_squared_example.cpp new file mode 100644 index 000000000..d21b0dc0c --- /dev/null +++ b/src/boost/libs/math/example/inverse_chi_squared_example.cpp @@ -0,0 +1,171 @@ +// inverse_chi_squared_distribution_example.cpp + +// Copyright Paul A. Bristow 2010. +// Copyright Thomas Mang 2010. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Example 1 of using inverse chi squared distribution +#include <boost/math/distributions/inverse_chi_squared.hpp> +using boost::math::inverse_chi_squared_distribution; // inverse_chi_squared_distribution. +using boost::math::inverse_chi_squared; //typedef for nverse_chi_squared_distribution double. + +#include <iostream> +using std::cout; using std::endl; +#include <iomanip> +using std::setprecision; +using std::setw; +#include <cmath> +using std::sqrt; + +template <class RealType> +RealType naive_pdf1(RealType df, RealType x) +{ // Formula from Wikipedia http://en.wikipedia.org/wiki/Inverse-chi-square_distribution + // definition 1 using tgamma for simplicity as a check. + using namespace std; // For ADL of std functions. + using boost::math::tgamma; + RealType df2 = df / 2; + RealType result = (pow(2., -df2) * pow(x, (-df2 -1)) * exp(-1/(2 * x) ) ) + / tgamma(df2); // + return result; +} + +template <class RealType> +RealType naive_pdf2(RealType df, RealType x) +{ // Formula from Wikipedia http://en.wikipedia.org/wiki/Inverse-chi-square_distribution + // Definition 2, using tgamma for simplicity as a check. + // Not scaled, so assumes scale = 1 and only uses nu aka df. + using namespace std; // For ADL of std functions. + using boost::math::tgamma; + RealType df2 = df / 2; + RealType result = (pow(df2, df2) * pow(x, (-df2 -1)) * exp(-df/(2*x) ) ) + / tgamma(df2); + return result; +} + +template <class RealType> +RealType naive_pdf3(RealType df, RealType scale, RealType x) +{ // Formula from Wikipedia http://en.wikipedia.org/wiki/Scaled-inverse-chi-square_distribution + // *Scaled* version, definition 3, df aka nu, scale aka sigma^2 + // using tgamma for simplicity as a check. + using namespace std; // For ADL of std functions. + using boost::math::tgamma; + RealType df2 = df / 2; + RealType result = (pow(scale * df2, df2) * exp(-df2 * scale/x) ) + / (tgamma(df2) * pow(x, 1+df2)); + return result; +} + +template <class RealType> +RealType naive_pdf4(RealType df, RealType scale, RealType x) +{ // Formula from http://mathworld.wolfram.com/InverseChi-SquaredDistribution.html + // Weisstein, Eric W. "Inverse Chi-Squared Distribution." From MathWorld--A Wolfram Web Resource. + // *Scaled* version, definition 3, df aka nu, scale aka sigma^2 + // using tgamma for simplicity as a check. + using namespace std; // For ADL of std functions. + using boost::math::tgamma; + RealType nu = df; // Wolfram uses greek symbols nu, + RealType xi = scale; // and xi. + RealType result = + pow(2, -nu/2) * exp(- (nu * xi)/(2 * x)) * pow(x, -1-nu/2) * pow((nu * xi), nu/2) + / tgamma(nu/2); + return result; +} + +int main() +{ + + cout << "Example (basic) using Inverse chi squared distribution. " << endl; + + // TODO find a more practical/useful example. Suggestions welcome? + +#ifdef BOOST_NO_CXX11_NUMERIC_LIMITS + int max_digits10 = 2 + (boost::math::policies::digits<double, boost::math::policies::policy<> >() * 30103UL) / 100000UL; + cout << "BOOST_NO_CXX11_NUMERIC_LIMITS is defined" << endl; +#else + int max_digits10 = std::numeric_limits<double>::max_digits10; +#endif + cout << "Show all potentially significant decimal digits std::numeric_limits<double>::max_digits10 = " + << max_digits10 << endl; + cout.precision(max_digits10); // + + inverse_chi_squared ichsqdef; // All defaults - not very useful! + cout << "default df = " << ichsqdef.degrees_of_freedom() + << ", default scale = " << ichsqdef.scale() << endl; // default df = 1, default scale = 0.5 + + inverse_chi_squared ichsqdef4(4); // Unscaled version, default scale = 1 / degrees_of_freedom + cout << "default df = " << ichsqdef4.degrees_of_freedom() + << ", default scale = " << ichsqdef4.scale() << endl; // default df = 4, default scale = 2 + + inverse_chi_squared ichsqdef32(3, 2); // Scaled version, both degrees_of_freedom and scale specified. + cout << "default df = " << ichsqdef32.degrees_of_freedom() + << ", default scale = " << ichsqdef32.scale() << endl; // default df = 3, default scale = 2 + + { + cout.precision(3); + double nu = 5.; + //double scale1 = 1./ nu; // 1st definition sigma^2 = 1/df; + //double scale2 = 1.; // 2nd definition sigma^2 = 1 + inverse_chi_squared ichsq(nu, 1/nu); // Not scaled + inverse_chi_squared sichsq(nu, 1/nu); // scaled + + cout << "nu = " << ichsq.degrees_of_freedom() << ", scale = " << ichsq.scale() << endl; + + int width = 8; + + cout << " x pdf pdf1 pdf2 pdf(scaled) pdf pdf cdf cdf" << endl; + for (double x = 0.0; x < 1.; x += 0.1) + { + cout + << setw(width) << x + << ' ' << setw(width) << pdf(ichsq, x) // unscaled + << ' ' << setw(width) << naive_pdf1(nu, x) // Wiki def 1 unscaled matches graph + << ' ' << setw(width) << naive_pdf2(nu, x) // scale = 1 - 2nd definition. + << ' ' << setw(width) << naive_pdf3(nu, 1/nu, x) // scaled + << ' ' << setw(width) << naive_pdf4(nu, 1/nu, x) // scaled + << ' ' << setw(width) << pdf(sichsq, x) // scaled + << ' ' << setw(width) << cdf(sichsq, x) // scaled + << ' ' << setw(width) << cdf(ichsq, x) // unscaled + << endl; + } + } + + cout.precision(max_digits10); + + inverse_chi_squared ichisq(2., 0.5); + cout << "pdf(ichisq, 1.) = " << pdf(ichisq, 1.) << endl; + cout << "cdf(ichisq, 1.) = " << cdf(ichisq, 1.) << endl; + + return 0; +} // int main() + +/* + +Output is: + Example (basic) using Inverse chi squared distribution. + Show all potentially significant decimal digits std::numeric_limits<double>::max_digits10 = 17 + default df = 1, default scale = 1 + default df = 4, default scale = 0.25 + default df = 3, default scale = 2 + nu = 5, scale = 0.2 + x pdf pdf1 pdf2 pdf(scaled) pdf pdf cdf cdf + 0 0 -1.#J -1.#J -1.#J -1.#J 0 0 0 + 0.1 2.83 2.83 3.26e-007 2.83 2.83 2.83 0.0752 0.0752 + 0.2 3.05 3.05 0.00774 3.05 3.05 3.05 0.416 0.416 + 0.3 1.7 1.7 0.121 1.7 1.7 1.7 0.649 0.649 + 0.4 0.941 0.941 0.355 0.941 0.941 0.941 0.776 0.776 + 0.5 0.553 0.553 0.567 0.553 0.553 0.553 0.849 0.849 + 0.6 0.345 0.345 0.689 0.345 0.345 0.345 0.893 0.893 + 0.7 0.227 0.227 0.728 0.227 0.227 0.227 0.921 0.921 + 0.8 0.155 0.155 0.713 0.155 0.155 0.155 0.94 0.94 + 0.9 0.11 0.11 0.668 0.11 0.11 0.11 0.953 0.953 + 1 0.0807 0.0807 0.61 0.0807 0.0807 0.0807 0.963 0.963 + pdf(ichisq, 1.) = 0.30326532985631671 + cdf(ichisq, 1.) = 0.60653065971263365 + + +*/ + diff --git a/src/boost/libs/math/example/inverse_chi_squared_find_df_example.cpp b/src/boost/libs/math/example/inverse_chi_squared_find_df_example.cpp new file mode 100644 index 000000000..ea0f932dc --- /dev/null +++ b/src/boost/libs/math/example/inverse_chi_squared_find_df_example.cpp @@ -0,0 +1,186 @@ +// inverse_chi_squared_distribution_find_df_example.cpp + +// Copyright Paul A. Bristow 2010. +// Copyright Thomas Mang 2010. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +//#define BOOST_MATH_INSTRUMENT + +// Example 1 of using inverse chi squared distribution +#include <boost/math/distributions/inverse_chi_squared.hpp> +using boost::math::inverse_chi_squared_distribution; // inverse_chi_squared_distribution. +using boost::math::inverse_chi_squared; //typedef for nverse_chi_squared_distribution double. + +#include <iostream> +using std::cout; using std::endl; +#include <iomanip> +using std::setprecision; +using std::setw; +#include <cmath> +using std::sqrt; + +int main() +{ + cout << "Example using Inverse chi squared distribution to find df. " << endl; + try + { + cout.precision(std::numeric_limits<double>::max_digits10); // + int i = std::numeric_limits<double>::max_digits10; + cout << "Show all potentially significant decimal digits std::numeric_limits<double>::max_digits10 = " << i << endl; + + cout.precision(3); + double nu = 10.; + double scale1 = 1./ nu; // 1st definition sigma^2 = 1/df; + double scale2 = 1.; // 2nd definition sigma^2 = 1 + inverse_chi_squared sichsq(nu, 1/nu); // Explicitly scaled to default scale = 1/df. + inverse_chi_squared ichsq(nu); // Implicitly scaled to default scale = 1/df. + // Try degrees of freedom estimator + + //double df = chi_squared::find_degrees_of_freedom(-diff, alpha[i], alpha[i], variance); + + cout << "ichsq.degrees_of_freedom() = " << ichsq.degrees_of_freedom() << endl; + + double diff = 0.5; // difference from variance to detect (delta). + double variance = 1.; // true variance + double alpha = 0.9; + double beta = 0.9; + + cout << "diff = " << diff + << ", variance = " << variance << ", ratio = " << diff/variance + << ", alpha = " << alpha << ", beta = " << beta << endl; + using boost::math::detail::inverse_chi_square_df_estimator; + using boost::math::policies::default_policy; + inverse_chi_square_df_estimator<> a_df(alpha, beta, variance, diff); + + cout << "df est" << endl; + for (double df = 1; df < 3; df += 0.1) + { + double est_df = a_df(1); + cout << df << " " << a_df(df) << endl; + } + + //template <class F, class T, class Tol, class Policy>std::pair<T, T> + // bracket_and_solve_root(F f, const T& guess, T factor, bool rising, Tol tol, boost::uintmax_t& max_iter, const Policy& pol) + + + //double df = inverse_chi_squared_distribution<>::find_degrees_of_freedom(diff, alpha, beta, variance, 0); + + double df = inverse_chi_squared::find_degrees_of_freedom(diff, alpha, beta, variance, 100); + + cout << df << endl; + } + catch(const std::exception& e) + { // Always useful to include try & catch blocks because default policies + // are to throw exceptions on arguments that cause errors like underflow, overflow. + // Lacking try & catch blocks, the program will abort without a message below, + // which may give some helpful clues as to the cause of the exception. + std::cout << + "\n""Message from thrown exception was:\n " << e.what() << std::endl; + } + return 0; +} // int main() + +/* + +Output is: + + Example using Inverse chi squared distribution to find df. + Show all potentially significant decimal digits std::numeric_limits<double>::max_digits10 = 17 + 10 + + Message from thrown exception was: + Error in function boost::math::inverse_chi_squared_distribution<double>::inverse_chi_squared_distribution: Degrees of freedom argument is 1.#INF, but must be > 0 ! +diff = 0.5, variance = 1, ratio = 0.5, alpha = 0.1, beta = 0.1 + df est + 1 1 + ratio+1 = 1.5, quantile(0.1) = 0.00618, cdf = 6.5e-037, result = -0.1 + 1.1 -0.1 + ratio+1 = 1.5, quantile(0.1) = 0.00903, cdf = 1.2e-025, result = -0.1 + 1.2 -0.1 + ratio+1 = 1.5, quantile(0.1) = 0.0125, cdf = 8.25e-019, result = -0.1 + 1.3 -0.1 + ratio+1 = 1.5, quantile(0.1) = 0.0166, cdf = 2.17e-014, result = -0.1 + 1.4 -0.1 + ratio+1 = 1.5, quantile(0.1) = 0.0212, cdf = 2.2e-011, result = -0.1 + 1.5 -0.1 + ratio+1 = 1.5, quantile(0.1) = 0.0265, cdf = 3e-009, result = -0.1 + 1.6 -0.1 + ratio+1 = 1.5, quantile(0.1) = 0.0323, cdf = 1.11e-007, result = -0.1 + 1.7 -0.1 + ratio+1 = 1.5, quantile(0.1) = 0.0386, cdf = 1.7e-006, result = -0.1 + 1.8 -0.1 + ratio+1 = 1.5, quantile(0.1) = 0.0454, cdf = 1.41e-005, result = -0.1 + 1.9 -0.1 + ratio+1 = 1.5, quantile(0.1) = 0.0527, cdf = 7.55e-005, result = -0.1 + 2 -0.1 + ratio+1 = 1.5, quantile(0.1) = 0.0604, cdf = 0.000291, result = -0.1 + 2.1 -0.1 + ratio+1 = 1.5, quantile(0.1) = 0.0685, cdf = 0.00088, result = -0.1 + 2.2 -0.1 + ratio+1 = 1.5, quantile(0.1) = 0.0771, cdf = 0.0022, result = -0.0999 + 2.3 -0.0999 + ratio+1 = 1.5, quantile(0.1) = 0.0859, cdf = 0.00475, result = -0.0997 + 2.4 -0.0997 + ratio+1 = 1.5, quantile(0.1) = 0.0952, cdf = 0.00911, result = -0.0993 + 2.5 -0.0993 + ratio+1 = 1.5, quantile(0.1) = 0.105, cdf = 0.0159, result = -0.0984 + 2.6 -0.0984 + ratio+1 = 1.5, quantile(0.1) = 0.115, cdf = 0.0257, result = -0.0967 + 2.7 -0.0967 + ratio+1 = 1.5, quantile(0.1) = 0.125, cdf = 0.039, result = -0.094 + 2.8 -0.094 + ratio+1 = 1.5, quantile(0.1) = 0.135, cdf = 0.056, result = -0.0897 + 2.9 -0.0897 + ratio+1 = 1.5, quantile(0.1) = 20.6, cdf = 1, result = 0.9 + + ichsq.degrees_of_freedom() = 10 + diff = 0.5, variance = 1, ratio = 0.5, alpha = 0.9, beta = 0.9 + df est + 1 1 + ratio+1 = 1.5, quantile(0.9) = 0.729, cdf = 0.269, result = -0.729 + 1.1 -0.729 + ratio+1 = 1.5, quantile(0.9) = 0.78, cdf = 0.314, result = -0.693 + 1.2 -0.693 + ratio+1 = 1.5, quantile(0.9) = 0.83, cdf = 0.36, result = -0.655 + 1.3 -0.655 + ratio+1 = 1.5, quantile(0.9) = 0.879, cdf = 0.405, result = -0.615 + 1.4 -0.615 + ratio+1 = 1.5, quantile(0.9) = 0.926, cdf = 0.449, result = -0.575 + 1.5 -0.575 + ratio+1 = 1.5, quantile(0.9) = 0.973, cdf = 0.492, result = -0.535 + 1.6 -0.535 + ratio+1 = 1.5, quantile(0.9) = 1.02, cdf = 0.534, result = -0.495 + 1.7 -0.495 + ratio+1 = 1.5, quantile(0.9) = 1.06, cdf = 0.574, result = -0.455 + 1.8 -0.455 + ratio+1 = 1.5, quantile(0.9) = 1.11, cdf = 0.612, result = -0.417 + 1.9 -0.417 + ratio+1 = 1.5, quantile(0.9) = 1.15, cdf = 0.648, result = -0.379 + 2 -0.379 + ratio+1 = 1.5, quantile(0.9) = 1.19, cdf = 0.681, result = -0.342 + 2.1 -0.342 + ratio+1 = 1.5, quantile(0.9) = 1.24, cdf = 0.713, result = -0.307 + 2.2 -0.307 + ratio+1 = 1.5, quantile(0.9) = 1.28, cdf = 0.742, result = -0.274 + 2.3 -0.274 + ratio+1 = 1.5, quantile(0.9) = 1.32, cdf = 0.769, result = -0.242 + 2.4 -0.242 + ratio+1 = 1.5, quantile(0.9) = 1.36, cdf = 0.793, result = -0.212 + 2.5 -0.212 + ratio+1 = 1.5, quantile(0.9) = 1.4, cdf = 0.816, result = -0.184 + 2.6 -0.184 + ratio+1 = 1.5, quantile(0.9) = 1.44, cdf = 0.836, result = -0.157 + 2.7 -0.157 + ratio+1 = 1.5, quantile(0.9) = 1.48, cdf = 0.855, result = -0.133 + 2.8 -0.133 + ratio+1 = 1.5, quantile(0.9) = 1.52, cdf = 0.872, result = -0.11 + 2.9 -0.11 + ratio+1 = 1.5, quantile(0.9) = 29.6, cdf = 1, result = 0.1 + + + */ + diff --git a/src/boost/libs/math/example/inverse_gamma_distribution_example.cpp b/src/boost/libs/math/example/inverse_gamma_distribution_example.cpp new file mode 100644 index 000000000..53e5ccf0f --- /dev/null +++ b/src/boost/libs/math/example/inverse_gamma_distribution_example.cpp @@ -0,0 +1,103 @@ +// inverse_gamma_distribution_example.cpp + +// Copyright Paul A. Bristow 2010. +// Copyright Thomas Mang 2010. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Example 1 of using inverse gamma +#include <boost/math/distributions/inverse_gamma.hpp> +using boost::math::inverse_gamma_distribution; // inverse_gamma_distribution. +using boost::math::inverse_gamma; + +#include <boost/math/special_functions/gamma.hpp> +using boost::math::tgamma; // Used for naive pdf as a comparison. + +#include <boost/math/distributions/gamma.hpp> +using boost::math::inverse_gamma_distribution; + +#include <iostream> +using std::cout; using std::endl; +#include <iomanip> +using std::setprecision; +#include <cmath> +using std::sqrt; + +int main() +{ + + cout << "Example using Inverse Gamma distribution. " << endl; + // TODO - awaiting a real example using Bayesian statistics. + +#ifdef BOOST_NO_CXX11_NUMERIC_LIMITS + int max_digits10 = 2 + (boost::math::policies::digits<double, boost::math::policies::policy<> >() * 30103UL) / 100000UL; + cout << "BOOST_NO_CXX11_NUMERIC_LIMITS is defined" << endl; +#else + int max_digits10 = std::numeric_limits<double>::max_digits10; +#endif + cout << "Show all potentially significant decimal digits std::numeric_limits<double>::max_digits10 = " + << max_digits10 << endl; + cout.precision(max_digits10); // + + double shape = 1.; + double scale = 1.; + double x = 0.5; + // Construction using default RealType double, and default shape and scale.. + inverse_gamma_distribution<> my_inverse_gamma(shape, scale); // (alpha, beta) + + cout << "my_inverse_gamma.shape() = " << my_inverse_gamma.shape() + << ", scale = "<< my_inverse_gamma.scale() << endl; + cout << "x = " << x << ", pdf = " << pdf(my_inverse_gamma, x) + << ", cdf = " << cdf(my_inverse_gamma, x) << endl; + + // Construct using typedef and default shape and scale parameters. + inverse_gamma my_ig; + + inverse_gamma my_ig23(2, 3); + cout << "my_inverse_gamma.shape() = " << my_ig23.shape() + << ", scale = "<< my_ig23.scale() << endl; + cout << "x = " << x << ", pdf = " << pdf(my_ig23, x) + << ", cdf = " << cdf(my_ig23, x) << endl; + + // Example of providing an 'out of domain' or 'bad' parameter, + // here a shape < 1, for which mean is not defined. + // Try block is essential to catch the exception message. + // (Uses the default policy which is to throw on all errors). + try + { + inverse_gamma if051(0.5, 1); + //inverse_gamma if051(0.5, 1); + cout << "mean(if051) = " << mean(if051) << endl; + } + catch(const std::exception& e) + { // Always useful to include try & catch blocks because default policies + // are to throw exceptions on arguments that cause errors like underflow, overflow. + // Lacking try & catch blocks, the program will abort without a message below, + // which may give some helpful clues as to the cause of the exception. + std::cout << + "\n""Message from thrown exception was:\n " << e.what() << std::endl; + } + + return 0; +} // int main() + +/* + +Output is: + Example using Inverse Gamma distribution. + std::numeric_limits<double>::max_digits10 = 17 + my_inverse_gamma.shape() = 1, scale = 1 + x = 0.5, pdf = 0.54134113294645081, cdf = 0.1353352832366127 + my_inverse_gamma.shape() = 2, scale = 3 + x = 0.5, pdf = 0.17847015671997774, cdf = 0.017351265236664509 + + Message from thrown exception was: + Error in function boost::math::mean(const inverse_gamma_distribution<double>&): Shape parameter is 0.5, but for a defined mean it must be > 1 + + +*/ + + diff --git a/src/boost/libs/math/example/inverse_gamma_example.cpp b/src/boost/libs/math/example/inverse_gamma_example.cpp new file mode 100644 index 000000000..5ec496659 --- /dev/null +++ b/src/boost/libs/math/example/inverse_gamma_example.cpp @@ -0,0 +1,57 @@ +// inverse_gamma_example.cpp + +// Copyright Paul A. Bristow 2010. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Example 1 of using inverse gamma functions. + +#include <boost/math/special_functions/gamma.hpp> + +using boost::math::gamma_p_inv; // Compute x given a +//using boost::math::gamma_q_inv; +//using boost::math::gamma_p_inva; // Compute a given x +//using boost::math::gamma_q_inva; + +#include <iostream> + using std::cout; using std::endl; +#include <iomanip> + using std::setprecision; +#include <cmath> + using std::sqrt; +#include <limits> + +int main() +{ + cout << "Example 1 using Inverse Gamma function. " << endl; + + #ifdef BOOST_NO_CXX11_NUMERIC_LIMITS + int max_digits10 = 2 + (boost::math::policies::digits<double, boost::math::policies::policy<> >() * 30103UL) / 100000UL; + cout << "BOOST_NO_CXX11_NUMERIC_LIMITS is defined" << endl; +#else + int max_digits10 = std::numeric_limits<double>::max_digits10; +#endif + cout << "Show all potentially significant decimal digits std::numeric_limits<double>::max_digits10 = " + << max_digits10 << endl; + cout.precision(max_digits10); // + + double x = 1.; + double a = 10; + + double r = boost::math::gamma_q_inv(a ,x); + + cout << " x = " << x << ", = gamma_q_inv(a,x)" << r << endl; // + + return 0; +} // int main() + +/* + +Output is: + +*/ + + diff --git a/src/boost/libs/math/example/inverse_gaussian_example.cpp b/src/boost/libs/math/example/inverse_gaussian_example.cpp new file mode 100644 index 000000000..4f212aa5e --- /dev/null +++ b/src/boost/libs/math/example/inverse_gaussian_example.cpp @@ -0,0 +1,513 @@ +// wald_example.cpp or inverse_gaussian_example.cpp + +// Copyright Paul A. Bristow 2010. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Example of using the Inverse Gaussian (or Inverse Normal) distribution. +// The Wald Distribution is + + +// Note that this file contains Quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +//[inverse_gaussian_basic1 +/*` +First we need some includes to access the normal distribution +(and some std output of course). +*/ + +#ifdef _MSC_VER +# pragma warning (disable : 4224) +# pragma warning (disable : 4189) +# pragma warning (disable : 4100) +# pragma warning (disable : 4224) +# pragma warning (disable : 4512) +# pragma warning (disable : 4702) +# pragma warning (disable : 4127) +#endif + +//#define BOOST_MATH_INSTRUMENT + +#define BOOST_MATH_OVERFLOW_ERROR_POLICY ignore_error +#define BOOST_MATH_DOMAIN_ERROR_POLICY ignore_error + +#include <boost/math/distributions/inverse_gaussian.hpp> // for inverse_gaussian_distribution + using boost::math::inverse_gaussian; // typedef provides default type is double. + using boost::math::inverse_gaussian_distribution; // for inverse gaussian distribution. + +#include <boost/math/distributions/normal.hpp> // for normal_distribution +using boost::math::normal; // typedef provides default type is double. + +#include <boost/array.hpp> +using boost::array; + +#include <iostream> + using std::cout; using std::endl; using std::left; using std::showpoint; using std::noshowpoint; +#include <iomanip> + using std::setw; using std::setprecision; +#include <limits> + using std::numeric_limits; +#include <sstream> + using std::string; +#include <string> + using std::stringstream; + +// const double tol = 3 * numeric_limits<double>::epsilon(); + +int main() +{ + cout << "Example: Inverse Gaussian Distribution."<< endl; + + try + { + + double tolfeweps = numeric_limits<double>::epsilon(); + //cout << "Tolerance = " << tol << endl; + + int precision = 17; // traditional tables are only computed to much lower precision. + cout.precision(17); // std::numeric_limits<double>::max_digits10; for 64-bit doubles. + + // Traditional tables and values. + double step = 0.2; // in z + double range = 4; // min and max z = -range to +range. + // Construct a (standard) inverse gaussian distribution s + inverse_gaussian w11(1, 1); + // (default mean = units, and standard deviation = unity) + cout << "(Standard) Inverse Gaussian distribution, mean = "<< w11.mean() + << ", scale = " << w11.scale() << endl; + +/*` First the probability distribution function (pdf). + */ + cout << "Probability distribution function (pdf) values" << endl; + cout << " z " " pdf " << endl; + cout.precision(5); + for (double z = (numeric_limits<double>::min)(); z < range + step; z += step) + { + cout << left << setprecision(3) << setw(6) << z << " " + << setprecision(precision) << setw(12) << pdf(w11, z) << endl; + } + cout.precision(6); // default + /*`And the area under the normal curve from -[infin] up to z, + the cumulative distribution function (cdf). +*/ + + // For a (default) inverse gaussian distribution. + cout << "Integral (area under the curve) from 0 up to z (cdf) " << endl; + cout << " z " " cdf " << endl; + for (double z = (numeric_limits<double>::min)(); z < range + step; z += step) + { + cout << left << setprecision(3) << setw(6) << z << " " + << setprecision(precision) << setw(12) << cdf(w11, z) << endl; + } + /*`giving the following table: +[pre + z pdf + 2.23e-308 -1.#IND + 0.2 0.90052111680384117 + 0.4 1.0055127039453111 + 0.6 0.75123750098955733 + 0.8 0.54377310461643302 + 1 0.3989422804014327 + 1.2 0.29846949816803292 + 1.4 0.2274579835638664 + 1.6 0.17614566625628389 + 1.8 0.13829083543591469 + 2 0.10984782236693062 + 2.2 0.088133964251182237 + 2.4 0.071327382959107177 + 2.6 0.058162562161661699 + 2.8 0.047742223328567722 + 3 0.039418357969819712 + 3.2 0.032715223861241892 + 3.4 0.027278388940958308 + 3.6 0.022840312999395804 + 3.8 0.019196657941016954 + 4 0.016189699458236451 + Integral (area under the curve) from 0 up to z (cdf) + z cdf + 2.23e-308 0 + 0.2 0.063753567519976254 + 0.4 0.2706136704424541 + 0.6 0.44638391340412931 + 0.8 0.57472390962590925 + 1 0.66810200122317065 + 1.2 0.73724578422952536 + 1.4 0.78944214237790356 + 1.6 0.82953458108474554 + 1.8 0.86079282968276671 + 2 0.88547542598600626 + 2.2 0.90517870624273966 + 2.4 0.92105495653509362 + 2.6 0.93395164268166786 + 2.8 0.94450240360053817 + 3 0.95318792074278835 + 3.2 0.96037753019309191 + 3.4 0.96635823989417369 + 3.6 0.97135533107998406 + 3.8 0.97554722413538364 + 4 0.97907636417888622 +] + +/*`We can get the inverse, the quantile, percentile, percentage point, or critical value +for a probability for a few probability from the above table, for z = 0.4, 1.0, 2.0: +*/ + cout << quantile(w11, 0.27061367044245421 ) << endl; // 0.4 + cout << quantile(w11, 0.66810200122317065) << endl; // 1.0 + cout << quantile(w11, 0.88547542598600615) << endl; // 2.0 +/*`turning the expect values apart from some 'computational noise' in the least significant bit or two. + +[pre + 0.40000000000000008 + 0.99999999999999967 + 1.9999999999999973 +] + +*/ + + // cout << "pnorm01(-0.406053) " << pnorm01(-0.406053) << ", cdfn01(-0.406053) = " << cdf(n01, -0.406053) << endl; + //cout << "pnorm01(0.5) = " << pnorm01(0.5) << endl; // R pnorm(0.5,0,1) = 0.6914625 == 0.69146246127401312 + // R qnorm(0.6914625,0,1) = 0.5 + + // formatC(SuppDists::qinvGauss(0.3649755481729598, 1, 1), digits=17) [1] "0.50000000969034875" + + + + // formatC(SuppDists::dinvGauss(0.01, 1, 1), digits=17) [1] "2.0811768202028392e-19" + // formatC(SuppDists::pinvGauss(0.01, 1, 1), digits=17) [1] "4.122313403318778e-23" + + + + //cout << " qinvgauss(0.3649755481729598, 1, 1) = " << qinvgauss(0.3649755481729598, 1, 1) << endl; // 0.5 + // cout << quantile(s, 0.66810200122317065) << endl; // expect 1, get 0.50517388467190727 + //cout << " qinvgauss(0.62502320258649202, 1, 1) = " << qinvgauss(0.62502320258649202, 1, 1) << endl; // 0.9 + //cout << " qinvgauss(0.063753567519976254, 1, 1) = " << qinvgauss(0.063753567519976254, 1, 1) << endl; // 0.2 + //cout << " qinvgauss(0.0040761113207110162, 1, 1) = " << qinvgauss(0.0040761113207110162, 1, 1) << endl; // 0.1 + + //double x = 1.; // SuppDists::pinvGauss(0.4, 1,1) [1] 0.2706137 + //double c = pinvgauss(x, 1, 1); // 0.3649755481729598 == cdf(x, 1,1) 0.36497554817295974 + //cout << " pinvgauss(x, 1, 1) = " << c << endl; // pinvgauss(x, 1, 1) = 0.27061367044245421 + //double p = pdf(w11, x); + //double c = cdf(w11, x); // cdf(1, 1, 1) = 0.66810200122317065 + //cout << "cdf(" << x << ", " << w11.mean() << ", "<< w11.scale() << ") = " << c << endl; // cdf(x, 1, 1) 0.27061367044245421 + //cout << "pdf(" << x << ", " << w11.mean() << ", "<< w11.scale() << ") = " << p << endl; + //double q = quantile(w11, c); + //cout << "quantile(w11, " << c << ") = " << q << endl; + + //cout << "quantile(w11, 4.122313403318778e-23) = "<< quantile(w11, 4.122313403318778e-23) << endl; // quantile + //cout << "quantile(w11, 4.8791443010851493e-219) = " << quantile(w11, 4.8791443010851493e-219) << endl; // quantile + + //double c1 = 1 - cdf(w11, x); // 1 - cdf(1, 1, 1) = 0.33189799877682935 + //cout << "1 - cdf(" << x << ", " << w11.mean() << ", " << w11.scale() << ") = " << c1 << endl; // cdf(x, 1, 1) 0.27061367044245421 + //double cc = cdf(complement(w11, x)); + //cout << "cdf(complement(" << x << ", " << w11.mean() << ", "<< w11.scale() << ")) = " << cc << endl; // cdf(x, 1, 1) 0.27061367044245421 + //// 1 - cdf(1000, 1, 1) = 0 + //// cdf(complement(1000, 1, 1)) = 4.8694344366900402e-222 + + //cout << "quantile(w11, " << c << ") = "<< quantile(w11, c) << endl; // quantile = 0.99999999999999978 == x = 1 + //cout << "quantile(w11, " << c << ") = "<< quantile(w11, 1 - c) << endl; // quantile complement. quantile(w11, 0.66810200122317065) = 0.46336593652340152 +// cout << "quantile(complement(w11, " << c << ")) = " << quantile(complement(w11, c)) << endl; // quantile complement = 0.46336593652340163 + + // cdf(1, 1, 1) = 0.66810200122317065 + // 1 - cdf(1, 1, 1) = 0.33189799877682935 + // cdf(complement(1, 1, 1)) = 0.33189799877682929 + + // quantile(w11, 0.66810200122317065) = 0.99999999999999978 + // 1 - quantile(w11, 0.66810200122317065) = 2.2204460492503131e-016 + // quantile(complement(w11, 0.33189799877682929)) = 0.99999999999999989 + + + // qinvgauss(c, 1, 1) = 0.3999999999999998 + // SuppDists::qinvGauss(0.270613670442454, 1, 1) [1] 0.4 + + + /* + double qs = pinvgaussU(c, 1, 1); // + cout << "qinvgaussU(c, 1, 1) = " << qs << endl; // qinvgaussU(c, 1, 1) = 0.86567442459240929 + // > z=q - exp(c) * p [1] 0.8656744 qs 0.86567442459240929 double + // Is this the complement? + cout << "qgamma(0.2, 0.5, 1) expect 0.0320923 = " << qgamma(0.2, 0.5, 1) << endl; + // qgamma(0.2, 0.5, 1) expect 0.0320923 = 0.032092377333650807 + + + cout << "qinvgauss(pinvgauss(x, 1, 1) = " << q + << ", diff = " << x - q << ", fraction = " << (x - q) /x << endl; // 0.5 + + */ // > SuppDists::pinvGauss(0.02, 1,1) [1] 4.139176e-12 + // > SuppDists::qinvGauss(4.139176e-12, 1,1) [1] 0.02000000 + + + // pinvGauss(1,1,1) = 0.668102 C++ == 0.66810200122317065 + // qinvGauss(0.668102,1,1) = 1 + + // SuppDists::pinvGauss(0.3,1,1) = 0.1657266 + // cout << "qinvGauss(0.0040761113207110162, 1, 1) = " << qinvgauss(0.0040761113207110162, 1, 1) << endl; + //cout << "quantile(s, 0.1657266) = " << quantile(s, 0.1657266) << endl; // expect 1. + + //wald s12(2, 1); + //cout << "qinvGauss(0.3, 2, 1) = " << qinvgauss(0.3, 2, 1) << endl; // SuppDists::qinvGauss(0.3,2,1) == 0.58288065635052944 + //// but actually get qinvGauss(0.3, 2, 1) = 0.58288064777632187 + //cout << "cdf(s12, 0.3) = " << cdf(s12, 0.3) << endl; // cdf(s12, 0.3) = 0.10895339868447573 + + // using boost::math::wald; + //cout.precision(6); + + /* + double m = 1; + double l = 1; + double x = 0.1; + //c = cdf(w, x); + double p = pinvgauss(x, m, l); + cout << "x = " << x << ", pinvgauss(x, m, l) = " << p << endl; // R 0.4 0.2706137 + double qg = qgamma(1.- p, 0.5, 1.0, true, false); + cout << " qgamma(1.- p, 0.5, 1.0, true, false) = " << qg << endl; // 0.606817 + double g = guess_whitmore(p, m, l); + cout << "m = " << m << ", l = " << l << ", x = " << x << ", guess = " << g + << ", diff = " << (x - g) << endl; + + g = guess_wheeler(p, m, l); + cout << "m = " << m << ", l = " << l << ", x = " << x << ", guess = " << g + << ", diff = " << (x - g) << endl; + + g = guess_bagshaw(p, m, l); + cout << "m = " << m << ", l = " << l << ", x = " << x << ", guess = " << g + << ", diff = " << (x - g) << endl; + + // m = 1, l = 10, x = 0.9, guess = 0.89792, diff = 0.00231075 so a better fit. + // x = 0.9, guess = 0.887907 + // x = 0.5, guess = 0.474977 + // x = 0.4, guess = 0.369597 + // x = 0.2, guess = 0.155196 + + // m = 1, l = 2, x = 0.9, guess = 1.0312, diff = -0.145778 + // m = 1, l = 2, x = 0.1, guess = 0.122201, diff = -0.222013 + // m = 1, l = 2, x = 0.2, guess = 0.299326, diff = -0.49663 + // m = 1, l = 2, x = 0.5, guess = 1.00437, diff = -1.00875 + // m = 1, l = 2, x = 0.7, guess = 1.01517, diff = -0.450247 + + double ls[7] = {0.1, 0.2, 0.5, 1., 2., 10, 100}; // scale values. + double ms[10] = {0.001, 0.02, 0.1, 0.2, 0.5, 0.9, 1., 2., 10, 100}; // mean values. + */ + + cout.precision(6); // Restore to default. + } // try + catch(const std::exception& e) + { // Always useful to include try & catch blocks because default policies + // are to throw exceptions on arguments that cause errors like underflow, overflow. + // Lacking try & catch blocks, the program will abort without a message below, + // which may give some helpful clues as to the cause of the exception. + std::cout << + "\n""Message from thrown exception was:\n " << e.what() << std::endl; + } + return 0; +} // int main() + + +/* + +Output is: + +inverse_gaussian_example.cpp + inverse_gaussian_example.vcxproj -> J:\Cpp\MathToolkit\test\Math_test\Debug\inverse_gaussian_example.exe + Example: Inverse Gaussian Distribution. + (Standard) Inverse Gaussian distribution, mean = 1, scale = 1 + Probability distribution function (pdf) values + z pdf + 2.23e-308 -1.#IND + 0.2 0.90052111680384117 + 0.4 1.0055127039453111 + 0.6 0.75123750098955733 + 0.8 0.54377310461643302 + 1 0.3989422804014327 + 1.2 0.29846949816803292 + 1.4 0.2274579835638664 + 1.6 0.17614566625628389 + 1.8 0.13829083543591469 + 2 0.10984782236693062 + 2.2 0.088133964251182237 + 2.4 0.071327382959107177 + 2.6 0.058162562161661699 + 2.8 0.047742223328567722 + 3 0.039418357969819712 + 3.2 0.032715223861241892 + 3.4 0.027278388940958308 + 3.6 0.022840312999395804 + 3.8 0.019196657941016954 + 4 0.016189699458236451 + Integral (area under the curve) from 0 up to z (cdf) + z cdf + 2.23e-308 0 + 0.2 0.063753567519976254 + 0.4 0.2706136704424541 + 0.6 0.44638391340412931 + 0.8 0.57472390962590925 + 1 0.66810200122317065 + 1.2 0.73724578422952536 + 1.4 0.78944214237790356 + 1.6 0.82953458108474554 + 1.8 0.86079282968276671 + 2 0.88547542598600626 + 2.2 0.90517870624273966 + 2.4 0.92105495653509362 + 2.6 0.93395164268166786 + 2.8 0.94450240360053817 + 3 0.95318792074278835 + 3.2 0.96037753019309191 + 3.4 0.96635823989417369 + 3.6 0.97135533107998406 + 3.8 0.97554722413538364 + 4 0.97907636417888622 + 0.40000000000000008 + 0.99999999999999967 + 1.9999999999999973 + + + +> SuppDists::dinvGauss(2, 1, 1) [1] 0.1098478 +> SuppDists::dinvGauss(0.4, 1, 1) [1] 1.005513 +> SuppDists::dinvGauss(0.5, 1, 1) [1] 0.8787826 +> SuppDists::dinvGauss(0.39, 1, 1) [1] 1.016559 +> SuppDists::dinvGauss(0.38, 1, 1) [1] 1.027006 +> SuppDists::dinvGauss(0.37, 1, 1) [1] 1.036748 +> SuppDists::dinvGauss(0.36, 1, 1) [1] 1.045661 +> SuppDists::dinvGauss(0.35, 1, 1) [1] 1.053611 +> SuppDists::dinvGauss(0.3, 1, 1) [1] 1.072888 +> SuppDists::dinvGauss(0.1, 1, 1) [1] 0.2197948 +> SuppDists::dinvGauss(0.2, 1, 1) [1] 0.9005211 +> +x = 0.3 [1, 1] 1.0728879234594337 // R SuppDists::dinvGauss(0.3, 1, 1) [1] 1.072888 + +x = 1 [1, 1] 0.3989422804014327 + + + 0 " NA" + 1 "0.3989422804014327" + 2 "0.10984782236693059" + 3 "0.039418357969819733" + 4 "0.016189699458236468" + 5 "0.007204168934430732" + 6 "0.003379893528659049" + 7 "0.0016462878258114036" + 8 "0.00082460931140859956" + 9 "0.00042207355643694234" +10 "0.00021979480031862676" + + +[1] " NA" " 0.690988298942671" "0.11539974210409144" + [4] "0.01799698883772935" "0.0029555399206496469" "0.00050863023587406587" + [7] "9.0761842931362914e-05" "1.6655279133132795e-05" "3.1243174913715429e-06" +[10] "5.96530227727434e-07" "1.1555606328299836e-07" + + +matC(dinvGauss(0:10, 1, 3), digits=17) df = 3 +[1] " NA" " 0.690988298942671" "0.11539974210409144" + [4] "0.01799698883772935" "0.0029555399206496469" "0.00050863023587406587" + [7] "9.0761842931362914e-05" "1.6655279133132795e-05" "3.1243174913715429e-06" +[10] "5.96530227727434e-07" "1.1555606328299836e-07" +$title +[1] "Inverse Gaussian" + +$nu +[1] 1 + +$lambda +[1] 3 + +$Mean +[1] 1 + +$Median +[1] 0.8596309 + +$Mode +[1] 0.618034 + +$Variance +[1] 0.3333333 + +$SD +[1] 0.5773503 + +$ThirdCentralMoment +[1] 0.3333333 + +$FourthCentralMoment +[1] 0.8888889 + +$PearsonsSkewness...mean.minus.mode.div.SD +[1] 0.6615845 + +$Skewness...sqrtB1 +[1] 1.732051 + +$Kurtosis...B2.minus.3 +[1] 5 + + Example: Wald distribution. + (Standard) Wald distribution, mean = 1, scale = 1 + 1 dx = 0.24890250442652451, x = 0.70924622051646713 + 2 dx = -0.038547954953794553, x = 0.46034371608994262 + 3 dx = -0.0011074090830291131, x = 0.49889167104373716 + 4 dx = -9.1987259926368029e-007, x = 0.49999908012676625 + 5 dx = -6.346513344581067e-013, x = 0.49999999999936551 + dx = 6.3168242705156857e-017 at i = 6 + qinvgauss(0.3649755481729598, 1, 1) = 0.50000000000000011 + 1 dx = 0.6719944578376621, x = 1.3735318786222666 + 2 dx = -0.16997432635769361, x = 0.70153742078460446 + 3 dx = -0.027865119206495724, x = 0.87151174714229807 + 4 dx = -0.00062283290009492603, x = 0.89937686634879377 + 5 dx = -3.0075104108208687e-007, x = 0.89999969924888867 + 6 dx = -7.0485322513588089e-014, x = 0.89999999999992975 + 7 dx = 9.557331866250277e-016, x = 0.90000000000000024 + dx = 0 at i = 8 + qinvgauss(0.62502320258649202, 1, 1) = 0.89999999999999925 + 1 dx = -0.0052296256747447678, x = 0.19483508278446249 + 2 dx = 6.4699046853900505e-005, x = 0.20006470845920726 + 3 dx = 9.4123530465288137e-009, x = 0.20000000941235335 + 4 dx = 2.7739513919147025e-016, x = 0.20000000000000032 + dx = 1.5410841066192808e-016 at i = 5 + qinvgauss(0.063753567519976254, 1, 1) = 0.20000000000000004 + 1 dx = -1, x = -0.46073286697416105 + 2 dx = 0.47665501251497061, x = 0.53926713302583895 + 3 dx = -0.171105768635964, x = 0.062612120510868341 + 4 dx = 0.091490360797512563, x = 0.23371788914683234 + 5 dx = 0.029410311722649803, x = 0.14222752834931979 + 6 dx = 0.010761845493592421, x = 0.11281721662666999 + 7 dx = 0.0019864890597643035, x = 0.10205537113307757 + 8 dx = 6.8800383732599561e-005, x = 0.10006888207331327 + 9 dx = 8.1689466405590418e-008, x = 0.10000008168958067 + 10 dx = 1.133634672475146e-013, x = 0.10000000000011428 + 11 dx = 5.9588135045224526e-016, x = 0.10000000000000091 + 12 dx = 3.433223674791152e-016, x = 0.10000000000000031 + dx = 9.0763384505974048e-017 at i = 13 + qinvgauss(0.0040761113207110162, 1, 1) = 0.099999999999999964 + + + wald_example.vcxproj -> J:\Cpp\MathToolkit\test\Math_test\Debug\wald_example.exe + Example: Wald distribution. + Tolerance = 6.66134e-016 + (Standard) Wald distribution, mean = 1, scale = 1 + cdf(x, 1,1) 4.1390252102096375e-012 + qinvgauss(pinvgauss(x, 1, 1) = 0.020116801973767886, diff = -0.00011680197376788548, fraction = -0.005840098688394274 + ____________________________________________________________ + wald 1, 1 + x = 0.02, diff x - qinvgauss(cdf) = -0.00011680197376788548 + x = 0.10000000000000001, diff x - qinvgauss(cdf) = 8.7430063189231078e-016 + x = 0.20000000000000001, diff x - qinvgauss(cdf) = -1.1102230246251565e-016 + x = 0.29999999999999999, diff x - qinvgauss(cdf) = 0 + x = 0.40000000000000002, diff x - qinvgauss(cdf) = 2.2204460492503131e-016 + x = 0.5, diff x - qinvgauss(cdf) = -1.1102230246251565e-016 + x = 0.59999999999999998, diff x - qinvgauss(cdf) = 1.1102230246251565e-016 + x = 0.80000000000000004, diff x - qinvgauss(cdf) = 1.1102230246251565e-016 + x = 0.90000000000000002, diff x - qinvgauss(cdf) = 0 + x = 0.98999999999999999, diff x - qinvgauss(cdf) = -1.1102230246251565e-016 + x = 0.999, diff x - qinvgauss(cdf) = -1.1102230246251565e-016 + + +*/ + + + diff --git a/src/boost/libs/math/example/jacobi_zeta_example.cpp b/src/boost/libs/math/example/jacobi_zeta_example.cpp new file mode 100644 index 000000000..062f27baa --- /dev/null +++ b/src/boost/libs/math/example/jacobi_zeta_example.cpp @@ -0,0 +1,104 @@ +// Copyright Paul A. Bristow, 2019 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +/*! \title Simple example of computation of the Jacobi Zeta function using Boost.Math, +and also using corresponding WolframAlpha commands. +*/ + +#ifdef BOOST_NO_CXX11_NUMERIC_LIMITS +# error "This example requires a C++ compiler that supports C++11 numeric_limits. Try C++11 or later." +#endif + +#include <boost/math/special_functions/jacobi_zeta.hpp> // For jacobi_zeta function. +#include <boost/multiprecision/cpp_bin_float.hpp> // For cpp_bin_float_50. + +#include <iostream> +#include <limits> +#include <iostream> +#include <exception> + +int main() +{ + try + { + std::cout.precision(std::numeric_limits<double>::max_digits10); // Show all potentially significant digits. + std::cout.setf(std::ios_base::showpoint); // Include any significant trailing zeros. + + using boost::math::jacobi_zeta; // jacobi_zeta(T1 k, T2 phi) |k| <=1, k = sqrt(m) + using boost::multiprecision::cpp_bin_float_50; + + // Wolfram Mathworld function JacobiZeta[phi, m] where m = k^2 + // JacobiZeta[phi,m] gives the Jacobi zeta function Z(phi | m) + + // If phi = 2, and elliptic modulus k = 0.9 so m = 0.9 * 0.9 = 0.81 + + // https://reference.wolfram.com/language/ref/JacobiZeta.html // Function information. + // A simple computation using phi = 2. and m = 0.9 * 0.9 + // JacobiZeta[2, 0.9 * 0.9] + // https://www.wolframalpha.com/input/?i=JacobiZeta%5B2,+0.9+*+0.9%5D + // -0.248584... + // To get the expected 17 decimal digits precision for a 64-bit double type, + // we need to ask thus: + // N[JacobiZeta[2, 0.9 * 0.9],17] + // https://www.wolframalpha.com/input/?i=N%5BJacobiZeta%5B2,+0.9+*+0.9%5D,17%5D + + double k = 0.9; + double m = k * k; + double phi = 2.; + + std::cout << "m = k^2 = " << m << std::endl; // m = k^2 = 0.81000000000000005 + std::cout << "jacobi_zeta(" << k << ", " << phi << " ) = " << jacobi_zeta(k, phi) << std::endl; + // jacobi_zeta(0.90000000000000002, 2.0000000000000000 ) = + // -0.24858442708494899 Boost.Math + // -0.24858442708494893 Wolfram + // that agree within the expected precision of 17 decimal digits for 64-bit type double. + + // We can also easily get a higher precision too: + // For example, to get 50 decimal digit precision using WolframAlpha: + // N[JacobiZeta[2, 0.9 * 0.9],50] + // https://www.wolframalpha.com/input/?i=N%5BJacobiZeta%5B2,+0.9+*+0.9%5D,50%5D + // -0.24858442708494893408462856109734087389683955309853 + + // Using Boost.Multiprecision we can do them same almost as easily. + + // To check that we are not losing precision, we show all the significant digits of the arguments ad result: + std::cout.precision(std::numeric_limits<cpp_bin_float_50>::digits10); // Show all significant digits. + + // We can force the computation to use 50 decimal digit precision thus: + cpp_bin_float_50 k50("0.9"); + cpp_bin_float_50 phi50("2."); + + std::cout << "jacobi_zeta(" << k50 << ", " << phi50 << " ) = " << jacobi_zeta(k50, phi50) << std::endl; + // jacobi_zeta(0.90000000000000000000000000000000000000000000000000, + // 2.0000000000000000000000000000000000000000000000000 ) + // = -0.24858442708494893408462856109734087389683955309853 + + // and a comparison with Wolfram shows agreement to the expected precision. + // -0.24858442708494893408462856109734087389683955309853 Boost.Math + // -0.24858442708494893408462856109734087389683955309853 Wolfram + + // Taking care not to fall into the awaiting pit, we ensure that ALL arguments passed are of the + // appropriate 50-digit precision and do NOT suffer from precision reduction to that of type double, + // We do NOT write: + std::cout << "jacobi_zeta<cpp_bin_float_50>(0.9, 2.) = " << jacobi_zeta<cpp_bin_float_50>(0.9, 2) << std::endl; + // jacobi_zeta(0.90000000000000000000000000000000000000000000000000, + // 2.0000000000000000000000000000000000000000000000000 ) + // = -0.24858442708494895921459900494815797085727097762164 << Wrong at about 17th digit! + // -0.24858442708494893408462856109734087389683955309853 Wolfram + } + catch (std::exception const& ex) + { + // Lacking try&catch blocks, the program will abort after any throw, whereas the + // message below from the thrown exception will give some helpful clues as to the cause of the problem. + std::cout << "\n""Message from thrown exception was:\n " << ex.what() << std::endl; + // An example of message: + // std::cout << " = " << jacobi_zeta(2, 0.5) << std::endl; + // Message from thrown exception was: + // Error in function boost::math::ellint_k<long double>(long double) : Got k = 2, function requires |k| <= 1 + // Shows that first parameter is k and is out of range, as the definition in docs jacobi_zeta(T1 k, T2 phi); + } +} // int main() diff --git a/src/boost/libs/math/example/lambert_w_basic_example.cpp b/src/boost/libs/math/example/lambert_w_basic_example.cpp new file mode 100644 index 000000000..869416194 --- /dev/null +++ b/src/boost/libs/math/example/lambert_w_basic_example.cpp @@ -0,0 +1,30 @@ +// Copyright Paul A. Bristow 2018 + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Example of most basic call of both lambert W functions. +// Only requires C++03 +// (and optionally a call of max_digits10 to show precision). + +#include <boost/math/special_functions/lambert_w.hpp> // For lambert_w0 and wm1 functions. + +#include <iostream> +#include <iomanip> + +int main() +{ + double z = 2.0; + double w0 = boost::math::lambert_w0(z); + std::cout.setf(std::ios_base::showpoint); // Include any trailing zeros. + std::cout.precision(std::numeric_limits<double>::max_digits10); // Show all possibly significant digits. + // Avoid using max_digfigs10 so as many old compilers can run the most basic lambert_w0 test? + // Require to get max_digits10 + // [ run lambert_w_basic_example.cpp : : : [ requires cxx11_numeric_limits ] ] + std::cout << " lambert_w0(" << z << ") = " << w0 << std::endl; // lambert_w0(2.00000) = 0.852606 + z = -0.2; + double wm1 = boost::math::lambert_wm1(z); + std::cout << " lambert_wm1(" << z << ") = " << wm1 << std::endl; // lambert_wm1(-0.200000) = -2.54264 + return 0; +} // int main() diff --git a/src/boost/libs/math/example/lambert_w_diode.cpp b/src/boost/libs/math/example/lambert_w_diode.cpp new file mode 100644 index 000000000..79c64bd26 --- /dev/null +++ b/src/boost/libs/math/example/lambert_w_diode.cpp @@ -0,0 +1,165 @@ +// Copyright Paul A. Bristow 2016 +// Copyright John Z. Maddock 2016 + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http ://www.boost.org/LICENSE_1_0.txt). + +/*! brief Example of using Lambert W function to compute current through a diode connected transistor with preset series resistance. + \details T. C. Banwell and A. Jayakumar, + Exact analytical solution of current flow through diode with series resistance, + Electron Letters, 36(4):291-2 (2000) + DOI: doi.org/10.1049/el:20000301 + + The current through a diode connected NPN bipolar junction transistor (BJT) + type 2N2222 (See https://en.wikipedia.org/wiki/2N2222 and + https://www.fairchildsemi.com/datasheets/PN/PN2222.pdf Datasheet) + was measured, for a voltage between 0.3 to 1 volt, see Fig 2 for a log plot, + showing a knee visible at about 0.6 V. + + The transistor parameter isat was estimated to be 25 fA and the ideality factor = 1.0. + The intrinsic emitter resistance re was estimated from the rsat = 0 data to be 0.3 ohm. + + The solid curves in Figure 2 are calculated using equation 5 with rsat included with re. + + http://www3.imperial.ac.uk/pls/portallive/docs/1/7292572.PDF +*/ + +#include <boost/math/special_functions/lambert_w.hpp> +using boost::math::lambert_w0; + +#include <iostream> +// using std::cout; +// using std::endl; +#include <exception> +#include <stdexcept> +#include <string> +#include <array> +#include <vector> + +/*! +Compute thermal voltage as a function of temperature, +about 25 mV at room temperature. +https://en.wikipedia.org/wiki/Boltzmann_constant#Role_in_semiconductor_physics:_the_thermal_voltage + +\param temperature Temperature (degrees centigrade). +*/ +const double v_thermal(double temperature) +{ + constexpr const double boltzmann_k = 1.38e-23; // joules/kelvin. + const double charge_q = 1.6021766208e-19; // Charge of an electron (columb). + double temp =+ 273; // Degrees C to K. + return boltzmann_k * temp / charge_q; +} // v_thermal + +/*! +Banwell & Jayakumar, equation 2 +*/ +double i(double isat, double vd, double vt, double nu) +{ + double i = isat * (exp(vd / (nu * vt)) - 1); + return i; +} // + +/*! + +Banwell & Jayakumar, Equation 4. +i current flow = isat +v voltage source. +isat reverse saturation current in equation 4. +(might implement equation 4 instead of simpler equation 5?). +vd voltage drop = v - i* rs (equation 1). +vt thermal voltage, 0.0257025 = 25 mV. +nu junction ideality factor (default = unity), also known as the emission coefficient. +re intrinsic emitter resistance, estimated to be 0.3 ohm from low current. +rsat reverse saturation current + +\param v Voltage V to compute current I(V). +\param vt Thermal voltage, for example 0.0257025 = 25 mV, computed from boltzmann_k * temp / charge_q; +\param rsat Resistance in series with the diode. +\param re Intrinsic emitter resistance (estimated to be 0.3 ohm from the Rs = 0 data) +\param isat Reverse saturation current (See equation 2). +\param nu Ideality factor (default = unity). + +\returns I amp as function of V volt. + +*/ +double iv(double v, double vt, double rsat, double re, double isat, double nu = 1.) +{ + // V thermal 0.0257025 = 25 mV + // was double i = (nu * vt/r) * lambert_w((i0 * r) / (nu * vt)); equ 5. + + rsat = rsat + re; + double i = nu * vt / rsat; + std::cout << "nu * vt / rsat = " << i << std::endl; // 0.000103223 + + double x = isat * rsat / (nu * vt); + std::cout << "isat * rsat / (nu * vt) = " << x << std::endl; + + double eterm = (v + isat * rsat) / (nu * vt); + std::cout << "(v + isat * rsat) / (nu * vt) = " << eterm << std::endl; + + double e = exp(eterm); + std::cout << "exp(eterm) = " << e << std::endl; + + double w0 = lambert_w0(x * e); + std::cout << "w0 = " << w0 << std::endl; + return i * w0 - isat; + +} // double iv + +std::array<double, 5> rss = {0., 2.18, 10., 51., 249}; // series resistance (ohm). +std::array<double, 8> vds = { 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 }; // Diode voltage. + +int main() +{ + try + { + std::cout << "Lambert W diode current example." << std::endl; + + //[lambert_w_diode_example_1 + double x = 0.01; + //std::cout << "Lambert W (" << x << ") = " << lambert_w(x) << std::endl; // 0.00990147 + + double nu = 1.0; // Assumed ideal. + double vt = v_thermal(25); // v thermal, Shockley equation, expect about 25 mV at room temperature. + double boltzmann_k = 1.38e-23; // joules/kelvin + double temp = 273 + 25; + double charge_q = 1.6e-19; // column + vt = boltzmann_k * temp / charge_q; + std::cout << "V thermal " + << vt << std::endl; // V thermal 0.0257025 = 25 mV + double rsat = 0.; + double isat = 25.e-15; // 25 fA; + std::cout << "Isat = " << isat << std::endl; + + double re = 0.3; // Estimated from slope of straight section of graph (equation 6). + + double v = 0.9; + double icalc = iv(v, vt, 249., re, isat); + + std::cout << "voltage = " << v << ", current = " << icalc << ", " << log(icalc) << std::endl; // voltage = 0.9, current = 0.00108485, -6.82631 + //] [/lambert_w_diode_example_1] + } + catch (std::exception& ex) + { + std::cout << ex.what() << std::endl; + } +} // int main() + +/* + Output: +//[lambert_w_output_1 + Lambert W diode current example. + V thermal 0.0257025 + Isat = 2.5e-14 + nu * vt / rsat = 0.000103099 + isat * rsat / (nu * vt) = 2.42486e-10 + (v + isat * rsat) / (nu * vt) = 35.016 + exp(eterm) = 1.61167e+15 + w0 = 10.5225 + voltage = 0.9, current = 0.00108485, -6.82631 + +//] [/lambert_w_output_1] +*/ + diff --git a/src/boost/libs/math/example/lambert_w_diode_graph.cpp b/src/boost/libs/math/example/lambert_w_diode_graph.cpp new file mode 100644 index 000000000..d9a4bcda5 --- /dev/null +++ b/src/boost/libs/math/example/lambert_w_diode_graph.cpp @@ -0,0 +1,280 @@ +// Copyright Paul A. Bristow 2016 +// Copyright John Z. Maddock 2016 + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http ://www.boost.org/LICENSE_1_0.txt). + +/*! \brief Graph showing use of Lambert W function to compute current +through a diode-connected transistor with preset series resistance. + +\details T. C. Banwell and A. Jayakumar, +Exact analytical solution of current flow through diode with series resistance, +Electron Letters, 36(4):291-2 (2000). +DOI: doi.org/10.1049/el:20000301 + +The current through a diode connected NPN bipolar junction transistor (BJT) +type 2N2222 (See https://en.wikipedia.org/wiki/2N2222 and +https://www.fairchildsemi.com/datasheets/PN/PN2222.pdf Datasheet) +was measured, for a voltage between 0.3 to 1 volt, see Fig 2 for a log plot, showing a knee visible at about 0.6 V. + +The transistor parameter I sat was estimated to be 25 fA and the ideality factor = 1.0. +The intrinsic emitter resistance re was estimated from the rsat = 0 data to be 0.3 ohm. + +The solid curves in Figure 2 are calculated using equation 5 with rsat included with re. + +http://www3.imperial.ac.uk/pls/portallive/docs/1/7292572.PDF + +*/ + +#include <boost/math/special_functions/lambert_w.hpp> +using boost::math::lambert_w0; +#include <boost/math/special_functions.hpp> +using boost::math::isfinite; +#include <boost/svg_plot/svg_2d_plot.hpp> +using namespace boost::svg; + +#include <iostream> +// using std::cout; +// using std::endl; +#include <exception> +#include <stdexcept> +#include <string> +#include <array> +#include <vector> +#include <utility> +using std::pair; +#include <map> +using std::map; +#include <set> +using std::multiset; +#include <limits> +using std::numeric_limits; +#include <cmath> // + +/*! +Compute thermal voltage as a function of temperature, +about 25 mV at room temperature. +https://en.wikipedia.org/wiki/Boltzmann_constant#Role_in_semiconductor_physics:_the_thermal_voltage + +\param temperature Temperature (degrees Celsius). +*/ +const double v_thermal(double temperature) +{ + BOOST_CONSTEXPR const double boltzmann_k = 1.38e-23; // joules/kelvin. + BOOST_CONSTEXPR double charge_q = 1.6021766208e-19; // Charge of an electron (columb). + double temp = +273; // Degrees C to K. + return boltzmann_k * temp / charge_q; +} // v_thermal + + /*! + Banwell & Jayakumar, equation 2, page 291. + */ +double i(double isat, double vd, double vt, double nu) +{ + double i = isat * (exp(vd / (nu * vt)) - 1); + return i; +} // + + /*! + Banwell & Jayakumar, Equation 4, page 291. + i current flow = isat + v voltage source. + isat reverse saturation current in equation 4. + (might implement equation 4 instead of simpler equation 5?). + vd voltage drop = v - i* rs (equation 1). + vt thermal voltage, 0.0257025 = 25 mV. + nu junction ideality factor (default = unity), also known as the emission coefficient. + re intrinsic emitter resistance, estimated to be 0.3 ohm from low current. + rsat reverse saturation current + + \param v Voltage V to compute current I(V). + \param vt Thermal voltage, for example 0.0257025 = 25 mV, computed from boltzmann_k * temp / charge_q; + \param rsat Resistance in series with the diode. + \param re Intrinsic emitter resistance (estimated to be 0.3 ohm from the Rs = 0 data) + \param isat Reverse saturation current (See equation 2). + \param nu Ideality factor (default = unity). + + \returns I amp as function of V volt. + */ + +//[lambert_w_diode_graph_2 +double iv(double v, double vt, double rsat, double re, double isat, double nu = 1.) +{ + // V thermal 0.0257025 = 25 mV + // was double i = (nu * vt/r) * lambert_w((i0 * r) / (nu * vt)); equ 5. + + rsat = rsat + re; + double i = nu * vt / rsat; + // std::cout << "nu * vt / rsat = " << i << std::endl; // 0.000103223 + + double x = isat * rsat / (nu * vt); +// std::cout << "isat * rsat / (nu * vt) = " << x << std::endl; + + double eterm = (v + isat * rsat) / (nu * vt); + // std::cout << "(v + isat * rsat) / (nu * vt) = " << eterm << std::endl; + + double e = exp(eterm); +// std::cout << "exp(eterm) = " << e << std::endl; + + double w0 = lambert_w0(x * e); +// std::cout << "w0 = " << w0 << std::endl; + return i * w0 - isat; +} // double iv + +//] [\lambert_w_diode_graph_2] + + +std::array<double, 5> rss = { 0., 2.18, 10., 51., 249 }; // series resistance (ohm). +std::array<double, 7> vds = { 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 }; // Diode voltage. +std::array<double, 7> lni = { -19.65, -15.75, -11.86, -7.97, -4.08, -0.0195, 3.6 }; // ln(current). + +int main() +{ + try + { + std::cout << "Lambert W diode current example." << std::endl; + +//[lambert_w_diode_graph_1 + double nu = 1.0; // Assumed ideal. + double vt = v_thermal(25); // v thermal, Shockley equation, expect about 25 mV at room temperature. + double boltzmann_k = 1.38e-23; // joules/kelvin + double temp = 273 + 25; + double charge_q = 1.6e-19; // column + vt = boltzmann_k * temp / charge_q; + std::cout << "V thermal " << vt << std::endl; // V thermal 0.0257025 = 25 mV + double rsat = 0.; + double isat = 25.e-15; // 25 fA; + std::cout << "Isat = " << isat << std::endl; + double re = 0.3; // Estimated from slope of straight section of graph (equation 6). + double v = 0.9; + double icalc = iv(v, vt, 249., re, isat); + std::cout << "voltage = " << v << ", current = " << icalc << ", " << log(icalc) << std::endl; // voltage = 0.9, current = 0.00108485, -6.82631 +//] [/lambert_w_diode_graph_1] + + // Plot a few measured data points. + std::map<const double, double> zero_data; // Extrapolated from slope of measurements with no external resistor. + zero_data[0.3] = -19.65; + zero_data[0.4] = -15.75; + zero_data[0.5] = -11.86; + zero_data[0.6] = -7.97; + zero_data[0.7] = -4.08; + zero_data[0.8] = -0.0195; + zero_data[0.9] = 3.9; + + std::map<const double, double> measured_zero_data; // No external series resistor. + measured_zero_data[0.3] = -19.65; + measured_zero_data[0.4] = -15.75; + measured_zero_data[0.5] = -11.86; + measured_zero_data[0.6] = -7.97; + measured_zero_data[0.7] = -4.2; + measured_zero_data[0.72] = -3.5; + measured_zero_data[0.74] = -2.8; + measured_zero_data[0.76] = -2.3; + measured_zero_data[0.78] = -2.0; + // Measured from Fig 2 as raw data not available. + + double step = 0.1; + for (int i = 0; i < vds.size(); i++) + { + zero_data[vds[i]] = lni[i]; + std::cout << lni[i] << " " << vds[i] << std::endl; + } + step = 0.01; + + std::map<const double, double> data_2; + for (double v = 0.3; v < 1.; v += step) + { + double current = iv(v, vt, 2., re, isat); + data_2[v] = log(current); + // std::cout << "v " << v << ", current = " << current << " log current = " << log(current) << std::endl; + } + std::map<const double, double> data_10; + for (double v = 0.3; v < 1.; v += step) + { + double current = iv(v, vt, 10., re, isat); + data_10[v] = log(current); + // std::cout << "v " << v << ", current = " << current << " log current = " << log(current) << std::endl; + } + std::map<const double, double> data_51; + for (double v = 0.3; v < 1.; v += step) + { + double current = iv(v, vt, 51., re, isat); + data_51[v] = log(current); + // std::cout << "v " << v << ", current = " << current << " log current = " << log(current) << std::endl; + } + std::map<const double, double> data_249; + for (double v = 0.3; v < 1.; v += step) + { + double current = iv(v, vt, 249., re, isat); + data_249[v] = log(current); + // std::cout << "v " << v << ", current = " << current << " log current = " << log(current) << std::endl; + } + + svg_2d_plot data_plot; + + data_plot.title("Diode current versus voltage") + .x_size(400) + .y_size(300) + .legend_on(true) + .legend_lines(true) + .x_label("voltage (V)") + .y_label("log(current) (A)") + //.x_label_on(true) + //.y_label_on(true) + //.xy_values_on(false) + .x_range(0.25, 1.) + .y_range(-20., +4.) + .x_major_interval(0.1) + .y_major_interval(4) + .x_major_grid_on(true) + .y_major_grid_on(true) + //.x_values_on(true) + //.y_values_on(true) + .y_values_rotation(horizontal) + //.plot_window_on(true) + .x_values_precision(3) + .y_values_precision(3) + .coord_precision(4) // Needed to avoid stepping on curves. + .copyright_holder("Paul A. Bristow") + .copyright_date("2016") + //.background_border_color(black); + ; + + // ₀ = subscript zero. + data_plot.plot(zero_data, "I₀(V)").fill_color(lightgray).shape(none).size(3).line_on(true).line_width(0.5); + data_plot.plot(measured_zero_data, "Rs=0 Ω").fill_color(lightgray).shape(square).size(3).line_on(true).line_width(0.5); + data_plot.plot(data_2, "Rs=2 Ω").line_color(blue).shape(none).line_on(true).bezier_on(false).line_width(1); + data_plot.plot(data_10, "Rs=10 Ω").line_color(purple).shape(none).line_on(true).bezier_on(false).line_width(1); + data_plot.plot(data_51, "Rs=51 Ω").line_color(green).shape(none).line_on(true).line_width(1); + data_plot.plot(data_249, "Rs=249 Ω").line_color(red).shape(none).line_on(true).line_width(1); + data_plot.write("./diode_iv_plot"); + + // bezier_on(true); + } + catch (std::exception& ex) + { + std::cout << ex.what() << std::endl; + } + + +} // int main() + + /* + + //[lambert_w_output_1 + Output: + Lambert W diode current example. + V thermal 0.0257025 + Isat = 2.5e-14 + voltage = 0.9, current = 0.00108485, -6.82631 + -19.65 0.3 + -15.75 0.4 + -11.86 0.5 + -7.97 0.6 + -4.08 0.7 + -0.0195 0.8 + 3.6 0.9 + + //] [/lambert_w_output_1] + */ diff --git a/src/boost/libs/math/example/lambert_w_example.cpp b/src/boost/libs/math/example/lambert_w_example.cpp new file mode 100644 index 000000000..28dbdf8a3 --- /dev/null +++ b/src/boost/libs/math/example/lambert_w_example.cpp @@ -0,0 +1,239 @@ +// Copyright Paul A. Bristow 2016. + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http ://www.boost.org/LICENSE_1_0.txt). + +// Test that can build and run a simple example of Lambert W function, +// using algorithm of Thomas Luu. +// https://svn.boost.org/trac/boost/ticket/11027 + +#include <boost/config.hpp> // for BOOST_PLATFORM, BOOST_COMPILER, BOOST_STDLIB ... +#include <boost/version.hpp> // for BOOST_MSVC versions. +#include <boost/cstdint.hpp> +#include <boost/exception/exception.hpp> // boost::exception +#include <boost/math/constants/constants.hpp> // For exp_minus_one == 3.67879441171442321595523770161460867e-01. + +#define BOOST_MATH_INSTRUMENT_LAMBERT_W // #define only for diagnostic output. + +// For lambert_w function. +#include <boost/math/special_functions/lambert_w.hpp> + +#include <iostream> +// using std::cout; +// using std::endl; +#include <exception> +#include <stdexcept> +#include <string> +#include <limits> // For std::numeric_limits. + +//! Show information about build, architecture, address model, platform, ... +std::string show_versions() +{ + std::ostringstream message; + + message << "Program: " << __FILE__ << "\n"; +#ifdef __TIMESTAMP__ + message << __TIMESTAMP__; +#endif + message << "\nBuildInfo:\n" " Platform " << BOOST_PLATFORM; + // http://stackoverflow.com/questions/1505582/determining-32-vs-64-bit-in-c +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) +#define IS64BIT 1 + message << ", 64-bit."; +#else +#define IS32BIT 1 + message << ", 32-bit."; +#endif + + message << "\n Compiler " BOOST_COMPILER; +#ifdef BOOST_MSC_VER +#ifdef _MSC_FULL_VER + message << "\n MSVC version " << BOOST_STRINGIZE(_MSC_FULL_VER) << "."; +#endif +#ifdef __WIN64 + mess age << "\n WIN64" << std::endl; +#endif // __WIN64 +#ifdef _WIN32 + message << "\n WIN32" << std::endl; +#endif // __WIN32 +#endif +#ifdef __GNUC__ + //PRINT_MACRO(__GNUC__); + //PRINT_MACRO(__GNUC_MINOR__); + //PRINT_MACRO(__GNUC_PATCH__); + std::cout << "GCC " << __VERSION__ << std::endl; + //PRINT_MACRO(LONG_MAX); +#endif // __GNUC__ + + message << "\n STL " << BOOST_STDLIB; + + message << "\n Boost version " << BOOST_VERSION / 100000 << "." << BOOST_VERSION / 100 % 1000 << "." << BOOST_VERSION % 100; + +#ifdef BOOST_HAS_FLOAT128 + message << ", BOOST_HAS_FLOAT128" << std::endl; +#endif + message << std::endl; + return message.str(); +} // std::string versions() + +int main() +{ + try + { + //std::cout << "Lambert W example basic!" << std::endl; + //std::cout << show_versions() << std::endl; + + //std::cout << exp(1) << std::endl; // 2.71828 + //std::cout << exp(-1) << std::endl; // 0.367879 + //std::cout << std::numeric_limits<double>::epsilon() / 2 << std::endl; // 1.11022e-16 + + using namespace boost::math; + using boost::math::constants::exp_minus_one; + double x = 1.; + + double W1 = lambert_w(1.); + // Note, NOT integer X, for example: lambert_w(1); or will get message like + // error C2338: Must be floating-point, not integer type, for example W(1.), not W(1)! + // + + std::cout << "Lambert W (" << x << ") = " << lambert_w(x) << std::endl; // 0.567143 + // This 'golden ratio' for exponentials is http://mathworld.wolfram.com/OmegaConstant.html + // since exp[-W(1)] = W(1) + // A030178 Decimal expansion of LambertW(1): the solution to x*exp(x) + // = 0.5671432904097838729999686622103555497538157871865125081351310792230457930866 + // http://oeis.org/A030178 + + double expplogone = exp(-lambert_w(1.)); + if (expplogone != W1) + { + std::cout << expplogone << " " << W1 << std::endl; // + } + + +//[lambert_w_example_1 + + x = 0.01; + std::cout << "Lambert W (" << x << ") = " << lambert_w(x) << std::endl; // 0.00990147 +//] [/lambert_w_example_1] + x = -0.01; + std::cout << "Lambert W (" << x << ") = " << lambert_w(x) << std::endl; // -0.0101015 + x = -0.1; + std::cout << "Lambert W (" << x << ") = " << lambert_w(x) << std::endl; // + /**/ + + for (double xd = 1.; xd < 1e20; xd *= 10) + { + + // 1. 0.56714329040978387 + // 0.56714329040978384 + + // 10 1.7455280027406994 + // 1.7455280027406994 + + // 100 3.3856301402900502 + // 3.3856301402900502 + // 1000 5.2496028524015959 + // 5.249602852401596227126056319697306282521472386059592844451465483991362228320942832739693150854347718 + + // 1e19 40.058769161984308 + // 40.05876916198431163898797971203180915622644925765346546858291325452428038208071849105889199253335063 + std::cout << "Lambert W (" << xd << ") = " << lambert_w(xd) << std::endl; // + } + // + // Test near singularity. + + // http://www.wolframalpha.com/input/?i=N%5Blambert_w%5B-0.367879%5D,17%5D test value N[lambert_w[-0.367879],17] + // -0.367879441171442321595523770161460867445811131031767834 + x = -0.367879; // < -exp(1) = -0.367879 + std::cout << "Lambert W (" << x << ") = " << lambert_w(x) << std::endl; // Lambert W (-0.36787900000000001) = -0.99845210378080340 + // -0.99845210378080340 + // -0.99845210378072726 N[lambert_w[-0.367879],17] wolfram so very close. + + x = -0.3678794; // expect -0.99952696660756813 + std::cout << "Lambert W (" << x << ") = " << lambert_w(x) << std::endl; // 0.0 + x = -0.36787944; // expect -0.99992019848408340 + std::cout << "Lambert W (" << x << ") = " << lambert_w(x) << std::endl; // 0.0 + x = -0.367879441; // -0.99996947070054883 + std::cout << "Lambert W (" << x << ") = " << lambert_w(x) << std::endl; // 0.0 + x = -0.36787944117; // -0.99999719977527159 + std::cout << "Lambert W (" << x << ") = " << lambert_w(x) << std::endl; // 0.0 + x = -0.367879441171; // -0.99999844928821992 + std::cout << "Lambert W (" << x << ") = " << lambert_w(x) << std::endl; // 0.0 + + x = -exp_minus_one<double>() + std::numeric_limits<double>::epsilon(); + // Lambert W (-0.36787944117144211) = -0.99999996349975895 + // N[lambert_w[-0.36787944117144211],17] == -0.99999996608315303 + std::cout << "Lambert W (" << x << ") = " << lambert_w(x) << std::endl; // 0.0 + std::cout << " 1 - sqrt(eps) = " << static_cast<double>(1) - sqrt(std::numeric_limits<double>::epsilon()) << std::endl; + x = -exp_minus_one<double>(); + // N[lambert_w[-0.36787944117144233],17] == -1.000000000000000 + 6.7595465843924897*10^-9i + std::cout << "Lambert W (" << x << ") = " << lambert_w(x) << std::endl; // 0.0 + // At Singularity - 0.36787944117144233 == -0.36787944117144233 returned - 1.0000000000000000 + // Lambert W(-0.36787944117144233) = -1.0000000000000000 + + + x = (std::numeric_limits<double>::max)()/4; + std::cout << "Lambert W (" << x << ") = " << lambert_w(x) << std::endl; // OK 702.023799146706 + x = (std::numeric_limits<double>::max)()/2; + std::cout << "Lambert W (" << x << ") = " << lambert_w(x) << std::endl; // + x = (std::numeric_limits<double>::max)(); + std::cout << "Lambert W (" << x << ") = " << lambert_w(x) << std::endl; // + // Error in function boost::math::log1p<double>(double): numeric overflow + /* */ + + } + catch (std::exception& ex) + { + std::cout << ex.what() << std::endl; + } + + +} // int main() + + /* + +//[lambert_w_output_1 + Output: + + 1> example_basic.cpp +1> Generating code +1> All 237 functions were compiled because no usable IPDB/IOBJ from previous compilation was found. +1> Finished generating code +1> LambertW.vcxproj -> J:\Cpp\Misc\x64\Release\LambertW.exe +1> LambertW.vcxproj -> J:\Cpp\Misc\x64\Release\LambertW.pdb (Full PDB) +1> Lambert W example basic! +1> Platform: Win32 +1> Compiler: Microsoft Visual C++ version 14.0 +1> STL : Dinkumware standard library version 650 +1> Boost : 1.63.0 +1> _MSC_FULL_VER = 190024123 +1> Win32 +1> x64 +1> (x64) +1> Iteration #0, w0 0.577547206058041, w1 = 0.567143616915443, difference = 0.0289944962755619, relative 0.018343835374856 +1> Iteration #1, w0 0.567143616915443, w1 = 0.567143290409784, difference = 9.02208135089566e-07, relative 5.75702234328901e-07 +1> Final 0.567143290409784 after 2 iterations, difference = 0 +1> Iteration #0, w0 0.577547206058041, w1 = 0.567143616915443, difference = 0.0289944962755619, relative 0.018343835374856 +1> Iteration #1, w0 0.567143616915443, w1 = 0.567143290409784, difference = 9.02208135089566e-07, relative 5.75702234328901e-07 +1> Final 0.567143290409784 after 2 iterations, difference = 0 +1> Lambert W (1) = 0.567143290409784 +1> Iteration #0, w0 0.577547206058041, w1 = 0.567143616915443, difference = 0.0289944962755619, relative 0.018343835374856 +1> Iteration #1, w0 0.567143616915443, w1 = 0.567143290409784, difference = 9.02208135089566e-07, relative 5.75702234328901e-07 +1> Final 0.567143290409784 after 2 iterations, difference = 0 +1> Iteration #0, w0 0.0099072820916067, w1 = 0.00990147384359511, difference = 5.92416060777624e-06, relative 0.000586604388734591 +1> Final 0.00990147384359511 after 1 iterations, difference = 0 +1> Lambert W (0.01) = 0.00990147384359511 +1> Iteration #0, w0 -0.0101016472705154, w1 = -0.0101015271985388, difference = -1.17664437923951e-07, relative 1.18865171889748e-05 +1> Final -0.0101015271985388 after 1 iterations, difference = 0 +1> Lambert W (-0.01) = -0.0101015271985388 +1> Iteration #0, w0 -0.111843322610692, w1 = -0.111832559158964, difference = -8.54817065376601e-06, relative 9.62461362694622e-05 +1> Iteration #1, w0 -0.111832559158964, w1 = -0.111832559158963, difference = -5.68989300120393e-16, relative 6.43929354282591e-15 +1> Final -0.111832559158963 after 2 iterations, difference = 0 +1> Lambert W (-0.1) = -0.111832559158963 +1> Iteration #0, w0 -0.998452103785573, w1 = -0.998452103780803, difference = -2.72004641033163e-15, relative 4.77662354114727e-12 +1> Final -0.998452103780803 after 1 iterations, difference = 0 +1> Lambert W (-0.367879) = -0.998452103780803 + +//] [/lambert_w_output_1] + */ diff --git a/src/boost/libs/math/example/lambert_w_graph.cpp b/src/boost/libs/math/example/lambert_w_graph.cpp new file mode 100644 index 000000000..3eb43f75a --- /dev/null +++ b/src/boost/libs/math/example/lambert_w_graph.cpp @@ -0,0 +1,286 @@ +// Copyright Paul A. Bristow 2017 +// Copyright John Z. Maddock 2017 + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http ://www.boost.org/LICENSE_1_0.txt). + +/*! \brief Graph showing use of Lambert W function. + +\details + +Both Lambert W0 and W-1 branches can be shown on one graph. +But useful to have another graph for larger values of argument z. +Need two separate graphs for Lambert W0 and -1 prime because +the sensible ranges and axes are too different. + +One would get too small LambertW0 in top right and W-1 in bottom left. + +*/ + +#include <boost/math/special_functions/lambert_w.hpp> +using boost::math::lambert_w0; +using boost::math::lambert_wm1; +using boost::math::lambert_w0_prime; +using boost::math::lambert_wm1_prime; + +#include <boost/math/special_functions.hpp> +using boost::math::isfinite; +#include <boost/svg_plot/svg_2d_plot.hpp> +using namespace boost::svg; +#include <boost/svg_plot/show_2d_settings.hpp> +using boost::svg::show_2d_plot_settings; + +#include <iostream> +// using std::cout; +// using std::endl; +#include <exception> +#include <stdexcept> +#include <string> +#include <array> +#include <vector> +#include <utility> +using std::pair; +#include <map> +using std::map; +#include <set> +using std::multiset; +#include <limits> +using std::numeric_limits; +#include <cmath> // + + /*! + */ +int main() +{ + try + { + std::cout << "Lambert W graph example." << std::endl; + +//[lambert_w_graph_1 +//] [/lambert_w_graph_1] + { + std::map<const double, double> wm1s; // Lambert W-1 branch values. + std::map<const double, double> w0s; // Lambert W0 branch values. + + std::cout.precision(std::numeric_limits<double>::max_digits10); + + int count = 0; + for (double z = -0.36787944117144232159552377016146086744581113103176804; z < 2.8; z += 0.001) + { + double w0 = lambert_w0(z); + w0s[z] = w0; + // std::cout << "z " << z << ", w = " << w0 << std::endl; + count++; + } + std::cout << "points " << count << std::endl; + + count = 0; + for (double z = -0.3678794411714423215955237701614608727; z < -0.001; z += 0.001) + { + double wm1 = lambert_wm1(z); + wm1s[z] = wm1; + count++; + } + std::cout << "points " << count << std::endl; + + svg_2d_plot data_plot; + data_plot.title("Lambert W function.") + .x_size(400) + .y_size(300) + .legend_on(true) + .legend_lines(true) + .x_label("z") + .y_label("W") + .x_range(-1, 3.) + .y_range(-4., +1.) + .x_major_interval(1.) + .y_major_interval(1.) + .x_major_grid_on(true) + .y_major_grid_on(true) + //.x_values_on(true) + //.y_values_on(true) + .y_values_rotation(horizontal) + //.plot_window_on(true) + .x_values_precision(3) + .y_values_precision(3) + .coord_precision(4) // Needed to avoid stepping on curves. + .copyright_holder("Paul A. Bristow") + .copyright_date("2018") + //.background_border_color(black); + ; + data_plot.plot(w0s, "W0 branch").line_color(red).shape(none).line_on(true).bezier_on(false).line_width(1); + data_plot.plot(wm1s, "W-1 branch").line_color(blue).shape(none).line_on(true).bezier_on(false).line_width(1); + data_plot.write("./lambert_w_graph"); + + show_2d_plot_settings(data_plot); // For plot diagnosis only. + + } // small z Lambert W + + { // bigger argument z Lambert W + + std::map<const double, double> w0s_big; // Lambert W0 branch values for large z and W. + std::map<const double, double> wm1s_big; // Lambert W-1 branch values for small z and large -W. + int count = 0; + for (double z = -0.3678794411714423215955237701614608727; z < 10000.; z += 50.) + { + double w0 = lambert_w0(z); + w0s_big[z] = w0; + count++; + } + std::cout << "points " << count << std::endl; + + count = 0; + for (double z = -0.3678794411714423215955237701614608727; z < -0.001; z += 0.001) + { + double wm1 = lambert_wm1(z); + wm1s_big[z] = wm1; + count++; + } + std::cout << "Lambert W0 large z argument points = " << count << std::endl; + + svg_2d_plot data_plot2; + data_plot2.title("Lambert W0 function for larger z.") + .x_size(400) + .y_size(300) + .legend_on(false) + .x_label("z") + .y_label("W") + //.x_label_on(true) + //.y_label_on(true) + //.xy_values_on(false) + .x_range(-1, 10000.) + .y_range(-1., +8.) + .x_major_interval(2000.) + .y_major_interval(1.) + .x_major_grid_on(true) + .y_major_grid_on(true) + //.x_values_on(true) + //.y_values_on(true) + .y_values_rotation(horizontal) + //.plot_window_on(true) + .x_values_precision(3) + .y_values_precision(3) + .coord_precision(4) // Needed to avoid stepping on curves. + .copyright_holder("Paul A. Bristow") + .copyright_date("2018") + //.background_border_color(black); + ; + + data_plot2.plot(w0s_big, "W0 branch").line_color(red).shape(none).line_on(true).bezier_on(false).line_width(1); + // data_plot2.plot(wm1s_big, "W-1 branch").line_color(blue).shape(none).line_on(true).bezier_on(false).line_width(1); + // This wouldn't show anything useful. + data_plot2.write("./lambert_w_graph_big_w"); + } // Big argument z Lambert W + + { // Lambert W0 Derivative plots + + // std::map<const double, double> wm1ps; // Lambert W-1 prime branch values. + std::map<const double, double> w0ps; // Lambert W0 prime branch values. + + std::cout.precision(std::numeric_limits<double>::max_digits10); + + int count = 0; + for (double z = -0.36; z < 3.; z += 0.001) + { + double w0p = lambert_w0_prime(z); + w0ps[z] = w0p; + // std::cout << "z " << z << ", w0 = " << w0 << std::endl; + count++; + } + std::cout << "points " << count << std::endl; + + //count = 0; + //for (double z = -0.36; z < -0.1; z += 0.001) + //{ + // double wm1p = lambert_wm1_prime(z); + // std::cout << "z " << z << ", w-1 = " << wm1p << std::endl; + // wm1ps[z] = wm1p; + // count++; + //} + //std::cout << "points " << count << std::endl; + + svg_2d_plot data_plotp; + data_plotp.title("Lambert W0 prime function.") + .x_size(400) + .y_size(300) + .legend_on(false) + .x_label("z") + .y_label("W0'") + .x_range(-0.3, +1.) + .y_range(0., +5.) + .x_major_interval(0.2) + .y_major_interval(2.) + .x_major_grid_on(true) + .y_major_grid_on(true) + .y_values_rotation(horizontal) + .x_values_precision(3) + .y_values_precision(3) + .coord_precision(4) // Needed to avoid stepping on curves. + .copyright_holder("Paul A. Bristow") + .copyright_date("2018") + ; + + // derivative of N[productlog(0, x), 55] at x=0 to 10 + // Plot[D[N[ProductLog[0, x], 55], x], {x, 0, 10}] + // Plot[ProductLog[x]/(x + x ProductLog[x]), {x, 0, 10}] + data_plotp.plot(w0ps, "W0 prime branch").line_color(red).shape(none).line_on(true).bezier_on(false).line_width(1); + data_plotp.write("./lambert_w0_prime_graph"); + } // Lambert W0 Derivative plots + + { // Lambert Wm1 Derivative plots + + std::map<const double, double> wm1ps; // Lambert W-1 prime branch values. + + std::cout.precision(std::numeric_limits<double>::max_digits10); + + int count = 0; + for (double z = -0.3678; z < -0.00001; z += 0.001) + { + double wm1p = lambert_wm1_prime(z); + // std::cout << "z " << z << ", w-1 = " << wm1p << std::endl; + wm1ps[z] = wm1p; + count++; + } + std::cout << "Lambert W-1 prime points = " << count << std::endl; + + svg_2d_plot data_plotp; + data_plotp.title("Lambert W-1 prime function.") + .x_size(400) + .y_size(300) + .legend_on(false) + .x_label("z") + .y_label("W-1'") + .x_range(-0.4, +0.01) + .x_major_interval(0.1) + .y_range(-20., -5.) + .y_major_interval(5.) + .x_major_grid_on(true) + .y_major_grid_on(true) + .y_values_rotation(horizontal) + .x_values_precision(3) + .y_values_precision(3) + .coord_precision(4) // Needed to avoid stepping on curves. + .copyright_holder("Paul A. Bristow") + .copyright_date("2018") + ; + + // derivative of N[productlog(0, x), 55] at x=0 to 10 + // Plot[D[N[ProductLog[0, x], 55], x], {x, 0, 10}] + // Plot[ProductLog[x]/(x + x ProductLog[x]), {x, 0, 10}] + data_plotp.plot(wm1ps, "W-1 prime branch").line_color(blue).shape(none).line_on(true).bezier_on(false).line_width(1); + data_plotp.write("./lambert_wm1_prime_graph"); + } // Lambert W-1 prime graph + } // try + catch (std::exception& ex) + { + std::cout << ex.what() << std::endl; + } +} // int main() + + /* + + //[lambert_w_graph_1_output + + //] [/lambert_w_graph_1_output] + */ diff --git a/src/boost/libs/math/example/lambert_w_precision_example.cpp b/src/boost/libs/math/example/lambert_w_precision_example.cpp new file mode 100644 index 000000000..e95f3b193 --- /dev/null +++ b/src/boost/libs/math/example/lambert_w_precision_example.cpp @@ -0,0 +1,263 @@ +// Copyright Paul A. Bristow 2016, 2018. + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http ://www.boost.org/LICENSE_1_0.txt). + +//! Lambert W examples of controlling precision + +// #define BOOST_MATH_INSTRUMENT_LAMBERT_W // #define only for (much) diagnostic output. + +#include <boost/config.hpp> // for BOOST_PLATFORM, BOOST_COMPILER, BOOST_STDLIB ... +#include <boost/version.hpp> // for BOOST_MSVC versions. +#include <boost/cstdint.hpp> +#include <boost/exception/exception.hpp> // boost::exception +#include <boost/math/constants/constants.hpp> // For exp_minus_one == 3.67879441171442321595523770161460867e-01. +#include <boost/math/policies/policy.hpp> +#include <boost/math/special_functions/next.hpp> // for float_distance. +#include <boost/math/special_functions/relative_difference.hpp> // for relative and epsilon difference. + +// Built-in/fundamental GCC float128 or Intel Quad 128-bit type, if available. +#ifdef BOOST_HAS_FLOAT128 +#include <boost/multiprecision/float128.hpp> // Not available for MSVC. +// sets BOOST_MP_USE_FLOAT128 for GCC +using boost::multiprecision::float128; +#endif //# NOT _MSC_VER + +#include <boost/multiprecision/cpp_dec_float.hpp> // boost::multiprecision::cpp_dec_float_50 +using boost::multiprecision::cpp_dec_float_50; // 50 decimal digits type. +using boost::multiprecision::cpp_dec_float_100; // 100 decimal digits type. + +#include <boost/multiprecision/cpp_bin_float.hpp> +using boost::multiprecision::cpp_bin_float_double_extended; +using boost::multiprecision::cpp_bin_float_double; +using boost::multiprecision::cpp_bin_float_quad; +// For lambert_w function. +#include <boost/math/special_functions/lambert_w.hpp> +// using boost::math::lambert_w0; +// using boost::math::lambert_wm1; + +#include <iostream> +#include <exception> +#include <stdexcept> +#include <string> +#include <limits> // For std::numeric_limits. + +int main() +{ + try + { + std::cout << "Lambert W examples of precision control." << std::endl; + std::cout.precision(std::numeric_limits<double>::max_digits10); + std::cout << std::showpoint << std::endl; // Show any trailing zeros. + + using boost::math::constants::exp_minus_one; + + using boost::math::lambert_w0; + using boost::math::lambert_wm1; + + // Error handling policy examples. + using namespace boost::math::policies; + using boost::math::policies::make_policy; + using boost::math::policies::policy; + using boost::math::policies::evaluation_error; + using boost::math::policies::domain_error; + using boost::math::policies::overflow_error; + using boost::math::policies::throw_on_error; + +//[lambert_w_precision_reference_w + + using boost::multiprecision::cpp_bin_float_50; + using boost::math::float_distance; + + cpp_bin_float_50 z("10."); // Note use a decimal digit string, not a double 10. + cpp_bin_float_50 r; + std::cout.precision(std::numeric_limits<cpp_bin_float_50>::digits10); + + r = lambert_w0(z); // Default policy. + std::cout << "lambert_w0(z) cpp_bin_float_50 = " << r << std::endl; + //lambert_w0(z) cpp_bin_float_50 = 1.7455280027406993830743012648753899115352881290809 + // [N[productlog[10], 50]] == 1.7455280027406993830743012648753899115352881290809 + std::cout.precision(std::numeric_limits<double>::max_digits10); + std::cout << "lambert_w0(z) static_cast from cpp_bin_float_50 = " + << static_cast<double>(r) << std::endl; + // double lambert_w0(z) static_cast from cpp_bin_float_50 = 1.7455280027406994 + // [N[productlog[10], 17]] == 1.7455280027406994 + std::cout << "bits different from Wolfram = " + << static_cast<int>(float_distance(static_cast<double>(r), 1.7455280027406994)) + << std::endl; // 0 + + +//] [/lambert_w_precision_reference_w] + +//[lambert_w_precision_0 + std::cout.precision(std::numeric_limits<float>::max_digits10); // Show all potentially significant decimal digits, + std::cout << std::showpoint << std::endl; // and show any significant trailing zeros too. + + float x = 10.; + std::cout << "Lambert W (" << x << ") = " << lambert_w0(x) << std::endl; +//] [/lambert_w_precision_0] + +/* +//[lambert_w_precision_output_0 +Lambert W (10.0000000) = 1.74552800 +//] [/lambert_w_precision_output_0] +*/ + { // Lambert W0 Halley step example +//[lambert_w_precision_1 + using boost::math::lambert_w_detail::lambert_w_halley_step; + using boost::math::epsilon_difference; + using boost::math::relative_difference; + + std::cout << std::showpoint << std::endl; // and show any significant trailing zeros too. + std::cout.precision(std::numeric_limits<double>::max_digits10); // 17 decimal digits for double. + + cpp_bin_float_50 z50("1.23"); // Note: use a decimal digit string, not a double 1.23! + double z = static_cast<double>(z50); + cpp_bin_float_50 w50; + w50 = lambert_w0(z50); + std::cout.precision(std::numeric_limits<cpp_bin_float_50>::max_digits10); // 50 decimal digits. + std::cout << "Reference Lambert W (" << z << ") =\n " + << w50 << std::endl; + std::cout.precision(std::numeric_limits<double>::max_digits10); // 17 decimal digits for double. + double wr = static_cast<double>(w50); + std::cout << "Reference Lambert W (" << z << ") = " << wr << std::endl; + + double w = lambert_w0(z); + std::cout << "Rat/poly Lambert W (" << z << ") = " << lambert_w0(z) << std::endl; + // Add a Halley step to the value obtained from rational polynomial approximation. + double ww = lambert_w_halley_step(lambert_w0(z), z); + std::cout << "Halley Step Lambert W (" << z << ") = " << lambert_w_halley_step(lambert_w0(z), z) << std::endl; + + std::cout << "absolute difference from Halley step = " << w - ww << std::endl; + std::cout << "relative difference from Halley step = " << relative_difference(w, ww) << std::endl; + std::cout << "epsilon difference from Halley step = " << epsilon_difference(w, ww) << std::endl; + std::cout << "epsilon for float = " << std::numeric_limits<double>::epsilon() << std::endl; + std::cout << "bits different from Halley step = " << static_cast<int>(float_distance(w, ww)) << std::endl; +//] [/lambert_w_precision_1] + + +/* +//[lambert_w_precision_output_1 + Reference Lambert W (1.2299999999999999822364316059974953532218933105468750) = + 0.64520356959320237759035605255334853830173300262666480 + Reference Lambert W (1.2300000000000000) = 0.64520356959320235 + Rat/poly Lambert W (1.2300000000000000) = 0.64520356959320224 + Halley Step Lambert W (1.2300000000000000) = 0.64520356959320235 + absolute difference from Halley step = -1.1102230246251565e-16 + relative difference from Halley step = 1.7207329236029286e-16 + epsilon difference from Halley step = 0.77494921535422934 + epsilon for float = 2.2204460492503131e-16 + bits different from Halley step = 1 +//] [/lambert_w_precision_output_1] +*/ + + } // Lambert W0 Halley step example + + { // Lambert W-1 Halley step example + //[lambert_w_precision_2 + using boost::math::lambert_w_detail::lambert_w_halley_step; + using boost::math::epsilon_difference; + using boost::math::relative_difference; + + std::cout << std::showpoint << std::endl; // and show any significant trailing zeros too. + std::cout.precision(std::numeric_limits<double>::max_digits10); // 17 decimal digits for double. + + cpp_bin_float_50 z50("-0.123"); // Note: use a decimal digit string, not a double -1.234! + double z = static_cast<double>(z50); + cpp_bin_float_50 wm1_50; + wm1_50 = lambert_wm1(z50); + std::cout.precision(std::numeric_limits<cpp_bin_float_50>::max_digits10); // 50 decimal digits. + std::cout << "Reference Lambert W-1 (" << z << ") =\n " + << wm1_50 << std::endl; + std::cout.precision(std::numeric_limits<double>::max_digits10); // 17 decimal digits for double. + double wr = static_cast<double>(wm1_50); + std::cout << "Reference Lambert W-1 (" << z << ") = " << wr << std::endl; + + double w = lambert_wm1(z); + std::cout << "Rat/poly Lambert W-1 (" << z << ") = " << lambert_wm1(z) << std::endl; + // Add a Halley step to the value obtained from rational polynomial approximation. + double ww = lambert_w_halley_step(lambert_wm1(z), z); + std::cout << "Halley Step Lambert W (" << z << ") = " << lambert_w_halley_step(lambert_wm1(z), z) << std::endl; + + std::cout << "absolute difference from Halley step = " << w - ww << std::endl; + std::cout << "relative difference from Halley step = " << relative_difference(w, ww) << std::endl; + std::cout << "epsilon difference from Halley step = " << epsilon_difference(w, ww) << std::endl; + std::cout << "epsilon for float = " << std::numeric_limits<double>::epsilon() << std::endl; + std::cout << "bits different from Halley step = " << static_cast<int>(float_distance(w, ww)) << std::endl; + //] [/lambert_w_precision_2] + } + /* + //[lambert_w_precision_output_2 + Reference Lambert W-1 (-0.12299999999999999822364316059974953532218933105468750) = + -3.2849102557740360179084675531714935199110302996513384 + Reference Lambert W-1 (-0.12300000000000000) = -3.2849102557740362 + Rat/poly Lambert W-1 (-0.12300000000000000) = -3.2849102557740357 + Halley Step Lambert W (-0.12300000000000000) = -3.2849102557740362 + absolute difference from Halley step = 4.4408920985006262e-16 + relative difference from Halley step = 1.3519066740696092e-16 + epsilon difference from Halley step = 0.60884463935795785 + epsilon for float = 2.2204460492503131e-16 + bits different from Halley step = -1 + //] [/lambert_w_precision_output_2] + */ + + + + // Similar example using cpp_bin_float_quad (128-bit floating-point types). + + cpp_bin_float_quad zq = 10.; + std::cout << "\nTest evaluation of cpp_bin_float_quad Lambert W(" << zq << ")" + << std::endl; + std::cout << std::setprecision(3) << "std::numeric_limits<cpp_bin_float_quad>::digits = " << std::numeric_limits<cpp_bin_float_quad>::digits << std::endl; + std::cout << std::setprecision(3) << "std::numeric_limits<cpp_bin_float_quad>::epsilon() = " << std::numeric_limits<cpp_bin_float_quad>::epsilon() << std::endl; + std::cout << std::setprecision(3) << "std::numeric_limits<cpp_bin_float_quad>::max_digits10 = " << std::numeric_limits<cpp_bin_float_quad>::max_digits10 << std::endl; + std::cout << std::setprecision(3) << "std::numeric_limits<cpp_bin_float_quad>::digits10 = " << std::numeric_limits<cpp_bin_float_quad>::digits10 << std::endl; + std::cout.precision(std::numeric_limits<cpp_bin_float_quad>::max_digits10); + // All are same precision because double precision first approximation used before Halley. + + /* + + */ + + { // Reference value for lambert_w0(10) + cpp_dec_float_50 z("10"); + cpp_dec_float_50 r; + std::cout.precision(std::numeric_limits<cpp_dec_float_50>::digits10); + + r = lambert_w0(z); // Default policy. + std::cout << "lambert_w0(z) cpp_dec_float_50 = " << r << std::endl; // 0.56714329040978387299996866221035554975381578718651 + std::cout.precision(std::numeric_limits<cpp_bin_float_quad>::max_digits10); + + std::cout << "lambert_w0(z) cpp_dec_float_50 cast to quad (max_digits10(" << std::numeric_limits<cpp_bin_float_quad>::max_digits10 << + " ) = " << static_cast<cpp_bin_float_quad>(r) << std::endl; // 1.7455280027406993830743012648753899115352881290809 + std::cout.precision(std::numeric_limits<cpp_bin_float_quad>::digits10); // 1.745528002740699383074301264875389837 + std::cout << "lambert_w0(z) cpp_dec_float_50 cast to quad (digits10(" << std::numeric_limits<cpp_bin_float_quad>::digits10 << + " ) = " << static_cast<cpp_bin_float_quad>(r) << std::endl; // 1.74552800274069938307430126487539 + std::cout.precision(std::numeric_limits<cpp_bin_float_quad>::digits10 + 1); // + + std::cout << "lambert_w0(z) cpp_dec_float_50 cast to quad (digits10(" << std::numeric_limits<cpp_bin_float_quad>::digits10 << + " ) = " << static_cast<cpp_bin_float_quad>(r) << std::endl; // 1.74552800274069938307430126487539 + + // [N[productlog[10], 50]] == 1.7455280027406993830743012648753899115352881290809 + + // [N[productlog[10], 37]] == 1.745528002740699383074301264875389912 + // [N[productlog[10], 34]] == 1.745528002740699383074301264875390 + // [N[productlog[10], 33]] == 1.74552800274069938307430126487539 + + // lambert_w0(z) cpp_dec_float_50 cast to quad = 1.745528002740699383074301264875389837 + + // lambert_w0(z) cpp_dec_float_50 = 1.7455280027406993830743012648753899115352881290809 + // lambert_w0(z) cpp_dec_float_50 cast to quad = 1.745528002740699383074301264875389837 + // lambert_w0(z) cpp_dec_float_50 cast to quad = 1.74552800274069938307430126487539 + } + } + catch (std::exception& ex) + { + std::cout << ex.what() << std::endl; + } +} // int main() + + + + diff --git a/src/boost/libs/math/example/lambert_w_simple_examples.cpp b/src/boost/libs/math/example/lambert_w_simple_examples.cpp new file mode 100644 index 000000000..3c422e062 --- /dev/null +++ b/src/boost/libs/math/example/lambert_w_simple_examples.cpp @@ -0,0 +1,251 @@ +// Copyright Paul A. Bristow 2016, 2017. + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http ://www.boost.org/LICENSE_1_0.txt). + +// Build and run a simple examples of Lambert W function. + +// Some macros that will show some(or much) diagnostic values if #defined. +//#define-able macros +//#define BOOST_MATH_INSTRUMENT_LAMBERT_W0 // W0 branch diagnostics. +//#define BOOST_MATH_INSTRUMENT_LAMBERT_Wm1 // W1 branch diagnostics. +//#define BOOST_MATH_INSTRUMENT_LAMBERT_W_HALLEY // Halley refinement diagnostics. +//#define BOOST_MATH_INSTRUMENT_LAMBERT_W_SCHROEDER // Schroeder refinement diagnostics. +//#define BOOST_MATH_INSTRUMENT_LAMBERT_W_TERMS // Number of terms used for near-singularity series. +//#define BOOST_MATH_INSTRUMENT_LAMBERT_W0_NOT_BUILTIN // higher than built-in precision types approximation and refinement. +//#define BOOST_MATH_INSTRUMENT_LAMBERT_W_SINGULARITY_SERIES // Show evaluation of series near branch singularity. +//#define BOOST_MATH_INSTRUMENT_LAMBERT_W_SMALL_Z_SERIES_ITERATIONS // Show evaluation of series for small z. +//#define BOOST_MATH_INSTRUMENT_LAMBERT_W0_LOOKUP // Show results from lookup table. + +#include <boost/config.hpp> // for BOOST_PLATFORM, BOOST_COMPILER, BOOST_STDLIB ... +#include <boost/version.hpp> // for BOOST_MSVC versions. +#include <boost/cstdint.hpp> +#include <boost/exception/exception.hpp> // boost::exception +#include <boost/math/constants/constants.hpp> // For exp_minus_one == 3.67879441171442321595523770161460867e-01. +#include <boost/math/policies/policy.hpp> + +#include <boost/multiprecision/cpp_dec_float.hpp> // boost::multiprecision::cpp_dec_float_50 +using boost::multiprecision::cpp_dec_float_50; // 50 decimal digits type. +using boost::multiprecision::cpp_dec_float_100; // 100 decimal digits type. +using boost::multiprecision::backends::cpp_dec_float; +using boost::multiprecision::number; +typedef number<cpp_dec_float<1000> > cpp_dec_float_1000; // 1000 decimal digit types + +#include <boost/multiprecision/cpp_bin_float.hpp> +using boost::multiprecision::cpp_bin_float_double; // == double +using boost::multiprecision::cpp_bin_float_double_extended; // 80-bit long double emulation. +using boost::multiprecision::cpp_bin_float_quad; // 128-bit quad precision. + +//[lambert_w_simple_examples_includes +#include <boost/math/special_functions/lambert_w.hpp> // For lambert_w function. + +using boost::math::lambert_w0; +using boost::math::lambert_wm1; +//] //[/lambert_w_simple_examples_includes] + +#include <iostream> +// using std::cout; +// using std::endl; +#include <exception> +#include <stdexcept> +#include <string> +#include <limits> // For std::numeric_limits. + +//! Show value of z to the full possibly-significant max_digits10 precision of type T. +template<typename T> +void show_value(T z) +{ + std::streamsize precision = std::cout.precision(std::numeric_limits<T>::max_digits10); // Save. + std::cout.precision(std::numeric_limits<T>::max_digits10); // Show all possibly significant digits. + std::ios::fmtflags flags(std::cout.flags()); + std::cout.setf(std::ios_base::showpoint); // Include any trailing zeros. + std::cout << z; + // Restore: + std::cout.precision(precision); + std::cout.flags(flags); +} // template<typename T> void show_value(T z) + +int main() +{ + try + { + std::cout << "Lambert W simple examples." << std::endl; + + using boost::math::constants::exp_minus_one; //-1/e, the branch point, a singularity ~= -0.367879. + + // using statements needed for changing error handling policy. + using boost::math::policies::policy; + using boost::math::policies::make_policy; + using boost::math::policies::evaluation_error; + using boost::math::policies::domain_error; + using boost::math::policies::overflow_error; + using boost::math::policies::ignore_error; + using boost::math::policies::throw_on_error; + + { +//[lambert_w_simple_examples_0 + std::cout.precision(std::numeric_limits<double>::max_digits10); + // Show all potentially significant decimal digits, + std::cout << std::showpoint << std::endl; + // and show significant trailing zeros too. + + double z = 10.; + double r = lambert_w0(z); // Default policy for double. + std::cout << "lambert_w0(z) = " << r << std::endl; + // lambert_w0(z) = 1.7455280027406994 +//] [/lambert_w_simple_examples_0] + } + { + // Other floating-point types can be used too, here float. + // It is convenient to use a function like `show_value` + // to display all potentially significant decimal digits + // for the type, including any significant trailing zeros. + //[lambert_w_simple_examples_1 + float z = 10.F; + float r; + r = lambert_w0(z); // Default policy digits10 = 7, digits2 = 24 + std::cout << "lambert_w0("; + show_value(z); + std::cout << ") = "; + show_value(r); + std::cout << std::endl; // lambert_w0(10.0000000) = 1.74552798 + //] //[/lambert_w_simple_examples_1] + } + { + // Example of an integer argument to lambert_w, + // showing that an integer is correctly promoted to a double. +//[lambert_w_simple_examples_2 + std::cout.precision(std::numeric_limits<double>::max_digits10); + double r = lambert_w0(10); // Pass an int argument "10" that should be promoted to double argument. + std::cout << "lambert_w0(10) = " << r << std::endl; // lambert_w0(10) = 1.7455280027406994 + double rp = lambert_w0(10); + std::cout << "lambert_w0(10) = " << rp << std::endl; + // lambert_w0(10) = 1.7455280027406994 + auto rr = lambert_w0(10); // C++11 needed. + std::cout << "lambert_w0(10) = " << rr << std::endl; + // lambert_w0(10) = 1.7455280027406994 too, showing that rr has been promoted to double. +//] //[/lambert_w_simple_examples_2] + } + { + // Using multiprecision types to get much higher precision is painless. + //[lambert_w_simple_examples_3 + cpp_dec_float_50 z("10"); + // Note construction using a decimal digit string "10", + // NOT a floating-point double literal 10. + cpp_dec_float_50 r; + r = lambert_w0(z); + std::cout << "lambert_w0("; show_value(z); std::cout << ") = "; + show_value(r); + std::cout << std::endl; + // lambert_w0(10.000000000000000000000000000000000000000000000000000000000000000000000000000000) = + // 1.7455280027406993830743012648753899115352881290809413313533156980404446940000000 + //] //[/lambert_w_simple_examples_3] + } + // Using multiprecision types to get multiprecision precision wrong! + { + //[lambert_w_simple_examples_4 + cpp_dec_float_50 z(0.7777777777777777777777777777777777777777777777777777777777777777777777777); + // Compiler evaluates the nearest double-precision binary representation, + // from the max_digits10 of the floating_point literal double 0.7777777777777777777777777777..., + // so any extra digits in the multiprecision type + // beyond max_digits10 (usually 17) are random and meaningless. + cpp_dec_float_50 r; + r = lambert_w0(z); + std::cout << "lambert_w0("; + show_value(z); + std::cout << ") = "; show_value(r); + std::cout << std::endl; + // lambert_w0(0.77777777777777779011358916250173933804035186767578125000000000000000000000000000) + // = 0.48086152073210493501934682309060873341910109230469724725005039758139532631901386 + //] //[/lambert_w_simple_examples_4] + } + { + //[lambert_w_simple_examples_4a + cpp_dec_float_50 z(0.9); // Construct from floating_point literal double 0.9. + cpp_dec_float_50 r; + r = lambert_w0(0.9); + std::cout << "lambert_w0("; + show_value(z); + std::cout << ") = "; show_value(r); + std::cout << std::endl; + // lambert_w0(0.90000000000000002220446049250313080847263336181640625000000000000000000000000000) + // = 0.52983296563343440510607251781038939952850341796875000000000000000000000000000000 + std::cout << "lambert_w0(0.9) = " << lambert_w0(static_cast<double>(0.9)) + // lambert_w0(0.9) + // = 0.52983296563343441 + << std::endl; + //] //[/lambert_w_simple_examples_4a] + } + { + // Using multiprecision types to get multiprecision precision right! + //[lambert_w_simple_examples_4b + cpp_dec_float_50 z("0.9"); // Construct from decimal digit string. + cpp_dec_float_50 r; + r = lambert_w0(z); + std::cout << "lambert_w0("; + show_value(z); + std::cout << ") = "; show_value(r); + std::cout << std::endl; + // 0.90000000000000000000000000000000000000000000000000000000000000000000000000000000) + // = 0.52983296563343441213336643954546304857788132269804249284012528304239956413801252 + //] //[/lambert_w_simple_examples_4b] + } + // Getting extreme precision (1000 decimal digits) Lambert W values. + { + std::cout.precision(std::numeric_limits<cpp_dec_float_1000>::digits10); + cpp_dec_float_1000 z("2.0"); + cpp_dec_float_1000 r; + r = lambert_w0(z); + std::cout << "lambert_w0(z) = " << r << std::endl; + // 0.8526055020137254913464724146953174668984533001514035087721073946525150656742630448965773783502494847334503972691804119834761668851953598826198984364998343940330324849743119327028383008883133161249045727544669202220292076639777316648311871183719040610274221013237163543451621208284315007250267190731048119566857455987975973474411544571619699938899354169616378479326962044241495398851839432070255805880208619490399218130868317114428351234208216131218024303904457925834743326836272959669122797896855064630871955955318383064292191644322931561534814178034773896739684452724587331245831001449498844495771266728242975586931792421997636537572767708722190588748148949667744956650966402600446780664924889043543203483210769017254907808218556111831854276511280553252641907484685164978750601216344998778097446525021666473925144772131644151718261199915247932015387685261438125313159125475113124470774926288823525823567568542843625471594347837868505309329628014463491611881381186810879712667681285740515197493390563 + // Wolfram alpha command N[productlog[0, 2.0],1000] gives the identical result: + // 0.8526055020137254913464724146953174668984533001514035087721073946525150656742630448965773783502494847334503972691804119834761668851953598826198984364998343940330324849743119327028383008883133161249045727544669202220292076639777316648311871183719040610274221013237163543451621208284315007250267190731048119566857455987975973474411544571619699938899354169616378479326962044241495398851839432070255805880208619490399218130868317114428351234208216131218024303904457925834743326836272959669122797896855064630871955955318383064292191644322931561534814178034773896739684452724587331245831001449498844495771266728242975586931792421997636537572767708722190588748148949667744956650966402600446780664924889043543203483210769017254907808218556111831854276511280553252641907484685164978750601216344998778097446525021666473925144772131644151718261199915247932015387685261438125313159125475113124470774926288823525823567568542843625471594347837868505309329628014463491611881381186810879712667681285740515197493390563 + } + { +//[lambert_w_simple_examples_error_policies + // Define an error handling policy: + typedef policy< + domain_error<throw_on_error>, + overflow_error<ignore_error> // possibly unwise? + > my_throw_policy; + + std::cout.precision(std::numeric_limits<double>::max_digits10); + // Show all potentially significant decimal digits, + std::cout << std::showpoint << std::endl; + // and show significant trailing zeros too. + double z = +1; + std::cout << "Lambert W (" << z << ") = " << lambert_w0(z) << std::endl; + // Lambert W (1.0000000000000000) = 0.56714329040978384 + std::cout << "\nLambert W (" << z << ", my_throw_policy()) = " + << lambert_w0(z, my_throw_policy()) << std::endl; + // Lambert W (1.0000000000000000, my_throw_policy()) = 0.56714329040978384 + //] //[/lambert_w_simple_example_error_policies] + } + { + // Show error reporting from passing a value to lambert_wm1 that is out of range, + // (and probably was meant to be passed to lambert_0 instead). +//[lambert_w_simple_examples_out_of_range + double z = +1.; + double r = lambert_wm1(z); + std::cout << "lambert_wm1(+1.) = " << r << std::endl; + //] [/lambert_w_simple_examples_out_of_range] + // Error in function boost::math::lambert_wm1<RealType>(<RealType>): + // Argument z = 1 is out of range (z <= 0) for Lambert W-1 branch! (Try Lambert W0 branch?) + } + } + catch (std::exception& ex) + { + std::cout << ex.what() << std::endl; + } +} // int main() + + /* + + Output: +//[lambert_w_simple_examples_error_message_1 +Error in function boost::math::lambert_wm1<RealType>(<RealType>): +Argument z = 1 is out of range (z <= 0) for Lambert W-1 branch! (Try Lambert W0 branch?) +//] [/lambert_w_simple_examples_error_message_1] + + */ diff --git a/src/boost/libs/math/example/laplace_example.cpp b/src/boost/libs/math/example/laplace_example.cpp new file mode 100644 index 000000000..ed99dba21 --- /dev/null +++ b/src/boost/libs/math/example/laplace_example.cpp @@ -0,0 +1,169 @@ +// laplace_example.cpp + +// Copyright Paul A. Bristow 2008, 2010. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Example of using laplace (& comparing with normal) distribution. + +// Note that this file contains Quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +//[laplace_example1 +/*` +First we need some includes to access the laplace & normal distributions +(and some std output of course). +*/ + +#include <boost/math/distributions/laplace.hpp> // for laplace_distribution + using boost::math::laplace; // typedef provides default type is double. +#include <boost/math/distributions/normal.hpp> // for normal_distribution + using boost::math::normal; // typedef provides default type is double. + +#include <iostream> + using std::cout; using std::endl; using std::left; using std::showpoint; using std::noshowpoint; +#include <iomanip> + using std::setw; using std::setprecision; +#include <limits> + using std::numeric_limits; + +int main() +{ + cout << "Example: Laplace distribution." << endl; + + try + { + { // Traditional tables and values. +/*`Let's start by printing some traditional tables. +*/ + double step = 1.; // in z + double range = 4; // min and max z = -range to +range. + //int precision = 17; // traditional tables are only computed to much lower precision. + int precision = 4; // traditional table at much lower precision. + int width = 10; // for use with setw. + + // Construct standard laplace & normal distributions l & s + normal s; // (default location or mean = zero, and scale or standard deviation = unity) + cout << "Standard normal distribution, mean or location = "<< s.location() + << ", standard deviation or scale = " << s.scale() << endl; + laplace l; // (default mean = zero, and standard deviation = unity) + cout << "Laplace normal distribution, location = "<< l.location() + << ", scale = " << l.scale() << endl; + +/*` First the probability distribution function (pdf). +*/ + cout << "Probability distribution function values" << endl; + cout << " z PDF normal laplace (difference)" << endl; + cout.precision(5); + for (double z = -range; z < range + step; z += step) + { + cout << left << setprecision(3) << setw(6) << z << " " + << setprecision(precision) << setw(width) << pdf(s, z) << " " + << setprecision(precision) << setw(width) << pdf(l, z)<< " (" + << setprecision(precision) << setw(width) << pdf(l, z) - pdf(s, z) // difference. + << ")" << endl; + } + cout.precision(6); // default +/*`Notice how the laplace is less at z = 1 , but has 'fatter' tails at 2 and 3. + + And the area under the normal curve from -[infin] up to z, + the cumulative distribution function (cdf). +*/ + // For a standard distribution + cout << "Standard location = "<< s.location() + << ", scale = " << s.scale() << endl; + cout << "Integral (area under the curve) from - infinity up to z " << endl; + cout << " z CDF normal laplace (difference)" << endl; + for (double z = -range; z < range + step; z += step) + { + cout << left << setprecision(3) << setw(6) << z << " " + << setprecision(precision) << setw(width) << cdf(s, z) << " " + << setprecision(precision) << setw(width) << cdf(l, z) << " (" + << setprecision(precision) << setw(width) << cdf(l, z) - cdf(s, z) // difference. + << ")" << endl; + } + cout.precision(6); // default + +/*` +Pretty-printing a traditional 2-dimensional table is left as an exercise for the student, +but why bother now that the Boost Math Toolkit lets you write +*/ + double z = 2.; + cout << "Area for gaussian z = " << z << " is " << cdf(s, z) << endl; // to get the area for z. + cout << "Area for laplace z = " << z << " is " << cdf(l, z) << endl; // +/*` +Correspondingly, we can obtain the traditional 'critical' values for significance levels. +For the 95% confidence level, the significance level usually called alpha, +is 0.05 = 1 - 0.95 (for a one-sided test), so we can write +*/ + cout << "95% of gaussian area has a z below " << quantile(s, 0.95) << endl; + cout << "95% of laplace area has a z below " << quantile(l, 0.95) << endl; + // 95% of area has a z below 1.64485 + // 95% of laplace area has a z below 2.30259 +/*`and a two-sided test (a comparison between two levels, rather than a one-sided test) + +*/ + cout << "95% of gaussian area has a z between " << quantile(s, 0.975) + << " and " << -quantile(s, 0.975) << endl; + cout << "95% of laplace area has a z between " << quantile(l, 0.975) + << " and " << -quantile(l, 0.975) << endl; + // 95% of area has a z between 1.95996 and -1.95996 + // 95% of laplace area has a z between 2.99573 and -2.99573 +/*`Notice how much wider z has to be to enclose 95% of the area. +*/ + } +//] [/[laplace_example1] + } + catch(const std::exception& e) + { // Always useful to include try & catch blocks because default policies + // are to throw exceptions on arguments that cause errors like underflow, overflow. + // Lacking try & catch blocks, the program will abort without a message below, + // which may give some helpful clues as to the cause of the exception. + std::cout << + "\n""Message from thrown exception was:\n " << e.what() << std::endl; + } + return 0; +} // int main() + +/* + +Output is: + +Example: Laplace distribution. +Standard normal distribution, mean or location = 0, standard deviation or scale = 1 +Laplace normal distribution, location = 0, scale = 1 +Probability distribution function values + z PDF normal laplace (difference) +-4 0.0001338 0.009158 (0.009024 ) +-3 0.004432 0.02489 (0.02046 ) +-2 0.05399 0.06767 (0.01368 ) +-1 0.242 0.1839 (-0.05803 ) +0 0.3989 0.5 (0.1011 ) +1 0.242 0.1839 (-0.05803 ) +2 0.05399 0.06767 (0.01368 ) +3 0.004432 0.02489 (0.02046 ) +4 0.0001338 0.009158 (0.009024 ) +Standard location = 0, scale = 1 +Integral (area under the curve) from - infinity up to z + z CDF normal laplace (difference) +-4 3.167e-005 0.009158 (0.009126 ) +-3 0.00135 0.02489 (0.02354 ) +-2 0.02275 0.06767 (0.04492 ) +-1 0.1587 0.1839 (0.02528 ) +0 0.5 0.5 (0 ) +1 0.8413 0.8161 (-0.02528 ) +2 0.9772 0.9323 (-0.04492 ) +3 0.9987 0.9751 (-0.02354 ) +4 1 0.9908 (-0.009126 ) +Area for gaussian z = 2 is 0.97725 +Area for laplace z = 2 is 0.932332 +95% of gaussian area has a z below 1.64485 +95% of laplace area has a z below 2.30259 +95% of gaussian area has a z between 1.95996 and -1.95996 +95% of laplace area has a z between 2.99573 and -2.99573 + +*/ + diff --git a/src/boost/libs/math/example/legendre_stieltjes_example.cpp b/src/boost/libs/math/example/legendre_stieltjes_example.cpp new file mode 100644 index 000000000..00ceba277 --- /dev/null +++ b/src/boost/libs/math/example/legendre_stieltjes_example.cpp @@ -0,0 +1,110 @@ +// Copyright Nick Thompson 2017. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <iostream> +#include <string> +#include <boost/math/constants/constants.hpp> +#include <boost/multiprecision/cpp_bin_float.hpp> +#include <boost/multiprecision/cpp_dec_float.hpp> +#include <boost/math/special_functions/legendre_stieltjes.hpp> + +using boost::math::legendre_p; +using boost::math::legendre_p_zeros; +using boost::math::legendre_p_prime; +using boost::math::legendre_stieltjes; +using boost::multiprecision::cpp_bin_float_quad; +using boost::multiprecision::cpp_bin_float_100; +using boost::multiprecision::cpp_dec_float_100; + +template<class Real> +void gauss_kronrod_rule(size_t order) +{ + std::cout << std::setprecision(std::numeric_limits<Real>::digits10); + std::cout << std::fixed; + auto gauss_nodes = boost::math::legendre_p_zeros<Real>(order); + auto E = legendre_stieltjes<Real>(order + 1); + std::vector<Real> gauss_weights(gauss_nodes.size(), std::numeric_limits<Real>::quiet_NaN()); + std::vector<Real> gauss_kronrod_weights(gauss_nodes.size(), std::numeric_limits<Real>::quiet_NaN()); + for (size_t i = 0; i < gauss_nodes.size(); ++i) + { + Real node = gauss_nodes[i]; + Real lp = legendre_p_prime<Real>(order, node); + gauss_weights[i] = 2/( (1-node*node)*lp*lp); + // P_n(x) = (2n)!/(2^n (n!)^2) pi_n(x), where pi_n is the monic Legendre polynomial. + gauss_kronrod_weights[i] = gauss_weights[i] + static_cast<Real>(2)/(static_cast<Real>(order+1)*legendre_p_prime(order, node)*E(node)); + } + + std::cout << "static const std::vector<Real> gauss_nodes {\n"; + for (auto const & node : gauss_nodes) + { + std::cout << " boost::lexical_cast<Real>(\"" << node << "\"),\n"; + } + std::cout << "};\n\n"; + + std::cout << "static const std::vector<Real> gauss_weights {\n"; + for (auto const & weight : gauss_weights) + { + std::cout << " boost::lexical_cast<Real>(\"" << weight << "\"),\n"; + } + std::cout << "};\n\n"; + + std::cout << "static const std::vector<Real> gauss_kronrod_weights {\n"; + for (auto const & weight : gauss_kronrod_weights) + { + std::cout << " boost::lexical_cast<Real>(\"" << weight << "\"),\n"; + } + std::cout << "};\n\n"; + + auto kronrod_nodes = E.zeros(); + std::vector<Real> kronrod_weights(kronrod_nodes.size()); + for (size_t i = 0; i < kronrod_weights.size(); ++i) + { + Real node = kronrod_nodes[i]; + kronrod_weights[i] = static_cast<Real>(2)/(static_cast<Real>(order+1)*legendre_p(order, node)*E.prime(node)); + } + + std::cout << "static const std::vector<Real> kronrod_nodes {\n"; + for (auto node : kronrod_nodes) + { + std::cout << " boost::lexical_cast<Real>(\"" << node << "\"),\n"; + } + std::cout << "};\n\n"; + + std::cout << "static const std::vector<Real> kronrod_weights {\n"; + for (auto const & weight : kronrod_weights) + { + std::cout << " boost::lexical_cast<Real>(\"" << weight << "\"),\n"; + } + std::cout << "};\n\n"; + +} + +int main() +{ + //std::cout << "Gauss-Kronrod 7-15 Rule:\n"; + //gauss_kronrod_rule<cpp_dec_float_100>(7); + + //std::cout << "\n\nGauss-Kronrod 10-21 Rule:\n"; + //gauss_kronrod_rule<cpp_dec_float_100>(10); + + std::cout << "\n\nGauss-Kronrod 15-31 Rule:\n"; + gauss_kronrod_rule<cpp_dec_float_100>(15); + /* + std::cout << "\n\nGauss-Kronrod 20-41 Rule:\n"; + gauss_kronrod_rule<cpp_dec_float_100>(20); + + std::cout << "\n\nGauss-Kronrod 25-51 Rule:\n"; + gauss_kronrod_rule<cpp_dec_float_100>(25); + + std::cout << "\n\nGauss-Kronrod 30-61 Rule:\n"; + gauss_kronrod_rule<cpp_dec_float_100>(30); + + std::cout << "\n\nGauss-Kronrod 35-71 Rule:\n"; + gauss_kronrod_rule<cpp_dec_float_100>(35); + + std::cout << "\n\nGauss-Kronrod 40-81 Rule:\n"; + gauss_kronrod_rule<cpp_dec_float_100>(40);*/ +} diff --git a/src/boost/libs/math/example/lexical_cast_native.cpp b/src/boost/libs/math/example/lexical_cast_native.cpp new file mode 100644 index 000000000..508b35fda --- /dev/null +++ b/src/boost/libs/math/example/lexical_cast_native.cpp @@ -0,0 +1,133 @@ +/** lexical_cast_nonfinite_facets.cpp +* +* Copyright (c) 2011 Paul A. Bristow +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt +* or copy at http://www.boost.org/LICENSE_1_0.txt) +* +* This very simple program illustrates how to use the +* `boost/math/nonfinite_num_facets.hpp' with lexical cast +* to obtain C99 representation of infinity and NaN. +* This example is from the original Floating Point Utilities contribution by Johan Rade. +* Floating Point Utility library has been accepted into Boost, +* but the utilities are incorporated into Boost.Math library. +* +\file + +\brief A very simple example of using lexical cast with +non_finite_num facet for C99 standard output of infinity and NaN. + +\detail This example shows how to create a C99 non-finite locale, +and imbue input and output streams with the non_finite_num put and get facets. +This allows lexical_cast output and input of infinity and NaN in a Standard portable way, +This permits 'loop-back' of output back into input (and portably across different system too). + +*/ + +#include <boost/math/special_functions/nonfinite_num_facets.hpp> +using boost::math::nonfinite_num_get; +using boost::math::nonfinite_num_put; + +#include <boost/lexical_cast.hpp> +using boost::lexical_cast; + +#include <iostream> +using std::cout; +using std::endl; +using std::cerr; + +#include <iomanip> +using std::setw; +using std::left; +using std::right; +using std::internal; + +#include <string> +using std::string; + +#include <sstream> +using std::istringstream; + +#include <limits> +using std::numeric_limits; + +#include <locale> +using std::locale; + +#include <boost/assert.hpp> + +int main () +{ + std::cout << "lexical_cast example (NOT using finite_num_facet)." << std::endl; + + if((std::numeric_limits<double>::has_infinity == false) || (std::numeric_limits<double>::infinity() == 0)) + { + std::cout << "Infinity not supported on this platform." << std::endl; + return 0; + } + + if((std::numeric_limits<double>::has_quiet_NaN == false) || (std::numeric_limits<double>::quiet_NaN() == 0)) + { + std::cout << "NaN not supported on this platform." << std::endl; + return 0; + } + + // Some tests that are expected to fail on some platforms. + // (But these tests are expected to pass using non_finite num_put and num_get facets). + + // Use the current 'native' default locale. + std::locale default_locale (std::locale::classic ()); // Note the current (default C) locale. + + // Create plus and minus infinity. + double plus_infinity = +std::numeric_limits<double>::infinity(); + double minus_infinity = -std::numeric_limits<double>::infinity(); + + // and create a NaN (NotANumber). + double NaN = +std::numeric_limits<double>::quiet_NaN (); + + // Output the nonfinite values using the current (default C) locale. + // The default representations differ from system to system, + // for example, using Microsoft compilers, 1.#INF, -1.#INF, and 1.#QNAN. + cout << "Using default locale" << endl; + cout << "+std::numeric_limits<double>::infinity() = " << plus_infinity << endl; + cout << "-std::numeric_limits<double>::infinity() = " << minus_infinity << endl; + cout << "+std::numeric_limits<double>::quiet_NaN () = " << NaN << endl; + + // Checks below are expected to fail on some platforms! + + // Now try some 'round-tripping', 'reading' "inf" + double x = boost::lexical_cast<double>("inf"); + // and check we get a floating-point infinity. + BOOST_ASSERT(x == std::numeric_limits<double>::infinity()); + + // Check we can convert the other way from floating-point infinity, + string s = boost::lexical_cast<string>(numeric_limits<double>::infinity()); + // to a C99 string representation as "inf". + BOOST_ASSERT(s == "inf"); + + // Finally try full 'round-tripping' (in both directions): + BOOST_ASSERT(lexical_cast<double>(lexical_cast<string>(numeric_limits<double>::infinity())) + == numeric_limits<double>::infinity()); + BOOST_ASSERT(lexical_cast<string>(lexical_cast<double>("inf")) == "inf"); + + return 0; +} // int main() + +/* + +Output: + +from MSVC 10, fails (as expected) + + lexical_cast_native.vcxproj -> J:\Cpp\fp_facet\fp_facet\Debug\lexical_cast_native.exe + lexical_cast example (NOT using finite_num_facet). + Using default locale + +std::numeric_limits<double>::infinity() = 1.#INF + -std::numeric_limits<double>::infinity() = -1.#INF + +std::numeric_limits<double>::quiet_NaN () = 1.#QNAN +C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets(183,5): error MSB3073: The command ""J:\Cpp\fp_facet\fp_facet\Debug\lexical_cast_native.exe" +C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets(183,5): error MSB3073: :VCEnd" exited with code 3. + + +*/ diff --git a/src/boost/libs/math/example/lexical_cast_nonfinite_facets.cpp b/src/boost/libs/math/example/lexical_cast_nonfinite_facets.cpp new file mode 100644 index 000000000..ecbda89ae --- /dev/null +++ b/src/boost/libs/math/example/lexical_cast_nonfinite_facets.cpp @@ -0,0 +1,133 @@ +/** lexical_cast_nonfinite_facets.cpp +* +* Copyright (c) 2011 Paul A. Bristow +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt +* or copy at http://www.boost.org/LICENSE_1_0.txt) +* +* This very simple program illustrates how to use the +* `boost/math/nonfinite_num_facets.hpp' with lexical cast +* to obtain C99 representation of infinity and NaN. +* This example is from the original Floating Point Utilities contribution by Johan Rade. +* Floating Point Utility library has been accepted into Boost, +* but the utilities are incorporated into Boost.Math library. +* +\file + +\brief A very simple example of using lexical cast with +non_finite_num facet for C99 standard output of infinity and NaN. + +\detail This example shows how to create a C99 non-finite locale, +and imbue input and output streams with the non_finite_num put and get facets. +This allows lexical_cast output and input of infinity and NaN in a Standard portable way, +This permits 'loop-back' of output back into input (and portably across different system too). + +See also lexical_cast_native.cpp which is expected to fail on many systems, +but might succeed if the default locale num_put and num_get facets +comply with C99 nonfinite input and output specification. + +*/ + +#include <boost/math/special_functions/nonfinite_num_facets.hpp> +using boost::math::nonfinite_num_get; +using boost::math::nonfinite_num_put; + +#include <boost/lexical_cast.hpp> +using boost::lexical_cast; + +#include <iostream> +using std::cout; +using std::endl; +using std::cerr; + +#include <iomanip> +using std::setw; +using std::left; +using std::right; +using std::internal; + +#include <string> +using std::string; + +#include <sstream> +using std::istringstream; + +#include <limits> +using std::numeric_limits; + +#include <locale> +using std::locale; + +#include <boost/assert.hpp> + +int main () +{ + std::cout << "finite_num_facet with lexical_cast example." << std::endl; + + // Example of using non_finite num_put and num_get facets with lexical_cast. + //locale old_locale; + //locale tmp_locale(old_locale, new nonfinite_num_put<char>); + //// Create a new temporary output locale, and add the output nonfinite_num_put facet. + + //locale new_locale(tmp_locale, new nonfinite_num_get<char>); + // Create a new output locale (from the tmp locale), and add the input nonfinite_num_get facet. + + // Note that you can only add facets one at a time, + // unless you chain thus: + + std::locale new_locale(std::locale(std::locale(), + new boost::math::nonfinite_num_put<char>), + new boost::math::nonfinite_num_get<char>); + + locale::global(new_locale); // Newly constructed streams + // (including those streams inside lexical_cast) + // now use new_locale with nonfinite facets. + + // Output using the new locale. + cout << "Using C99_out_locale " << endl; + cout.imbue(new_locale); + // Necessary because cout already constructed using default C locale, + // and default facets for nonfinites. + + // Create plus and minus infinity. + double plus_infinity = +std::numeric_limits<double>::infinity(); + double minus_infinity = -std::numeric_limits<double>::infinity(); + + // and create a NaN (NotANumber) + double NaN = +std::numeric_limits<double>::quiet_NaN (); + cout << "+std::numeric_limits<double>::infinity() = " << plus_infinity << endl; + cout << "-std::numeric_limits<double>::infinity() = " << minus_infinity << endl; + cout << "+std::numeric_limits<double>::quiet_NaN () = " << NaN << endl; + + // Now try some 'round-tripping', 'reading' "inf". + double x = boost::lexical_cast<double>("inf"); + // and check we get a floating-point infinity. + BOOST_ASSERT(x == std::numeric_limits<double>::infinity()); + cout << "boost::lexical_cast<double>(\"inf\") = " << x << endl; + + // Check we can convert the other way from floating-point infinity, + string s = boost::lexical_cast<string>(numeric_limits<double>::infinity()); + // to a C99 string representation as "inf". + BOOST_ASSERT(s == "inf"); + + // Finally try full 'round-tripping' (in both directions): + BOOST_ASSERT(lexical_cast<double>(lexical_cast<string>(numeric_limits<double>::infinity())) + == numeric_limits<double>::infinity()); + BOOST_ASSERT(lexical_cast<string>(lexical_cast<double>("inf")) == "inf"); + + return 0; +} // int main() + +/* + +Output: + finite_num_facet with lexical_cast example. + Using C99_out_locale + +std::numeric_limits<double>::infinity() = inf + -std::numeric_limits<double>::infinity() = -inf + +std::numeric_limits<double>::quiet_NaN () = nan + boost::lexical_cast<double>("inf") = inf + + +*/ diff --git a/src/boost/libs/math/example/naive_monte_carlo_example.cpp b/src/boost/libs/math/example/naive_monte_carlo_example.cpp new file mode 100644 index 000000000..800eb6794 --- /dev/null +++ b/src/boost/libs/math/example/naive_monte_carlo_example.cpp @@ -0,0 +1,136 @@ +/* + * Copyright Nick Thompson, 2017 + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ + +#include <boost/math/quadrature/naive_monte_carlo.hpp> +#include <iostream> +#include <iomanip> +#include <limits> +#include <cmath> +#include <thread> +#include <future> +#include <string> +#include <chrono> +#include <boost/math/special_functions/pow.hpp> +#include <boost/math/constants/constants.hpp> + +using std::vector; +using std::pair; +using boost::math::quadrature::naive_monte_carlo; + +void display_progress(double progress, + double error_estimate, + double current_estimate, + std::chrono::duration<double> estimated_time_to_completion) +{ + int barWidth = 70; + + std::cout << "["; + int pos = barWidth * progress; + for (int i = 0; i < barWidth; ++i) { + if (i < pos) std::cout << "="; + else if (i == pos) std::cout << ">"; + else std::cout << " "; + } + std::cout << "] " + << int(progress * 100.0) + << "%, E = " + << std::setprecision(3) + << error_estimate + << ", time to completion: " + << estimated_time_to_completion.count() + << " seconds, estimate: " + << std::setprecision(5) + << current_estimate + << " \r"; + + std::cout.flush(); +} + +int main() +{ + double exact = 1.3932039296856768591842462603255; + double A = 1.0 / boost::math::pow<3>(boost::math::constants::pi<double>()); + auto g = [&](std::vector<double> const & x) + { + return A / (1.0 - cos(x[0])*cos(x[1])*cos(x[2])); + }; + vector<pair<double, double>> bounds{{0, boost::math::constants::pi<double>() }, {0, boost::math::constants::pi<double>() }, {0, boost::math::constants::pi<double>() }}; + naive_monte_carlo<double, decltype(g)> mc(g, bounds, 0.001); + + auto task = mc.integrate(); + + int s = 0; + std::cout << "Hit ctrl-c to cancel.\n"; + while (task.wait_for(std::chrono::seconds(1)) != std::future_status::ready) + { + display_progress(mc.progress(), + mc.current_error_estimate(), + mc.current_estimate(), + mc.estimated_time_to_completion()); + // TODO: The following shows that cancellation works, + // but it would be nice to show how it works with a ctrl-c signal handler. + if (s++ > 25){ + mc.cancel(); + std::cout << "\nCancelling because this is too slow!\n"; + } + } + double y = task.get(); + display_progress(mc.progress(), + mc.current_error_estimate(), + mc.current_estimate(), + mc.estimated_time_to_completion()); + std::cout << std::setprecision(std::numeric_limits<double>::digits10) << std::fixed; + std::cout << "\nFinal value: " << y << std::endl; + std::cout << "Exact : " << exact << std::endl; + std::cout << "Final error estimate: " << mc.current_error_estimate() << std::endl; + std::cout << "Actual error : " << abs(y - exact) << std::endl; + std::cout << "Function calls: " << mc.calls() << std::endl; + std::cout << "Is this good enough? [y/N] "; + bool goodenough = true; + std::string line; + std::getline(std::cin, line); + if (line[0] != 'y') + { + goodenough = false; + } + double new_error = -1; + if (!goodenough) + { + std::cout << "What is the new target error? "; + std::getline(std::cin, line); + new_error = atof(line.c_str()); + if (new_error >= mc.current_error_estimate()) + { + std::cout << "That error bound is already satisfied.\n"; + return 0; + } + } + if (new_error > 0) + { + mc.update_target_error(new_error); + auto task = mc.integrate(); + std::cout << "Hit ctrl-c to cancel.\n"; + while (task.wait_for(std::chrono::seconds(1)) != std::future_status::ready) + { + display_progress(mc.progress(), + mc.current_error_estimate(), + mc.current_estimate(), + mc.estimated_time_to_completion()); + } + double y = task.get(); + display_progress(mc.progress(), + mc.current_error_estimate(), + mc.current_estimate(), + mc.estimated_time_to_completion()); + std::cout << std::setprecision(std::numeric_limits<double>::digits10) << std::fixed; + std::cout << "\nFinal value: " << y << std::endl; + std::cout << "Exact : " << exact << std::endl; + std::cout << "Final error estimate: " << mc.current_error_estimate() << std::endl; + std::cout << "Actual error : " << abs(y - exact) << std::endl; + std::cout << "Function calls: " << mc.calls() << std::endl; + } +} diff --git a/src/boost/libs/math/example/nc_chi_sq_example.cpp b/src/boost/libs/math/example/nc_chi_sq_example.cpp new file mode 100644 index 000000000..75bfa9443 --- /dev/null +++ b/src/boost/libs/math/example/nc_chi_sq_example.cpp @@ -0,0 +1,115 @@ +// Copyright John Maddock 2008 +// Copyright Paul A. Bristow 2010, 2013 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Caution: this file contains Quickbook markup as well as code +// and comments, don't change any of the special comment markups! + +//[nccs_eg + +/*` + +This example computes a table of the power of the [chi][super 2] +test at the 5% significance level, for various degrees of freedom +and non-centrality parameters. The table is deliberately the same +as Table 6 from "The Non-Central [chi][super 2] and F-Distributions and +their applications.", P. B. Patnaik, Biometrika, Vol. 36, No. 1/2 (June 1949), +202-232. + +First we need some includes to access the non-central chi squared distribution +(and some basic std output of course). + +*/ + +#include <boost/math/distributions/non_central_chi_squared.hpp> +using boost::math::chi_squared; +using boost::math::non_central_chi_squared; + +#include <iostream> +using std::cout; using std::endl; +using std::setprecision; + +int main() +{ + /*` + Create a table of the power of the [chi][super 2] test at + 5% significance level, start with a table header: + */ + cout << "[table\n[[[nu]]"; + for(int lam = 2; lam <= 20; lam += 2) + { + cout << "[[lambda]=" << lam << "]"; + } + cout << "]\n"; + + /*` + (Note: the enclosing [] brackets are to format as a table in Boost.Quickbook). + + Enumerate the rows and columns and print the power of the test + for each table cell: + */ + + for(int n = 2; n <= 20; ++n) + { + cout << "[[" << n << "]"; + for(int lam = 2; lam <= 20; lam += 2) + { + /*` + Calculate the [chi][super 2] statistic for a 5% significance: + */ + double cs = quantile(complement(chi_squared(n), 0.05)); + /*` + The power of the test is given by the complement of the CDF + of the non-central [chi][super 2] distribution: + */ + double beta = cdf(complement(non_central_chi_squared(n, lam), cs)); + /*` + Then output the cell value: + */ + cout << "[" << setprecision(3) << beta << "]"; + } + cout << "]" << endl; + } + cout << "]" << endl; +} + +/*` +The output from this program is a table in Boost.Quickbook format as shown below. + +We can interpret this as follows - for example if [nu]=10 and [lambda]=10 +then the power of the test is 0.542 - so we have only a 54% chance of +correctly detecting that our null hypothesis is false, and a 46% chance +of incurring a type II error (failing to reject the null hypothesis when +it is in fact false): + +[table +[[[nu]][[lambda]=2][[lambda]=4][[lambda]=6][[lambda]=8][[lambda]=10][[lambda]=12][[lambda]=14][[lambda]=16][[lambda]=18][[lambda]=20]] +[[2][0.226][0.415][0.584][0.718][0.815][0.883][0.928][0.957][0.974][0.985]] +[[3][0.192][0.359][0.518][0.654][0.761][0.84][0.896][0.934][0.959][0.975]] +[[4][0.171][0.32][0.47][0.605][0.716][0.802][0.866][0.912][0.943][0.964]] +[[5][0.157][0.292][0.433][0.564][0.677][0.769][0.839][0.89][0.927][0.952]] +[[6][0.146][0.27][0.403][0.531][0.644][0.738][0.813][0.869][0.911][0.94]] +[[7][0.138][0.252][0.378][0.502][0.614][0.71][0.788][0.849][0.895][0.928]] +[[8][0.131][0.238][0.357][0.477][0.588][0.685][0.765][0.829][0.879][0.915]] +[[9][0.125][0.225][0.339][0.454][0.564][0.661][0.744][0.811][0.863][0.903]] +[[10][0.121][0.215][0.323][0.435][0.542][0.64][0.723][0.793][0.848][0.891]] +[[11][0.117][0.206][0.309][0.417][0.523][0.62][0.704][0.775][0.833][0.878]] +[[12][0.113][0.198][0.297][0.402][0.505][0.601][0.686][0.759][0.818][0.866]] +[[13][0.11][0.191][0.286][0.387][0.488][0.584][0.669][0.743][0.804][0.854]] +[[14][0.108][0.185][0.276][0.374][0.473][0.567][0.653][0.728][0.791][0.842]] +[[15][0.105][0.179][0.267][0.362][0.459][0.552][0.638][0.713][0.777][0.83]] +[[16][0.103][0.174][0.259][0.351][0.446][0.538][0.623][0.699][0.764][0.819]] +[[17][0.101][0.169][0.251][0.341][0.434][0.525][0.609][0.686][0.752][0.807]] +[[18][0.0992][0.165][0.244][0.332][0.423][0.512][0.596][0.673][0.74][0.796]] +[[19][0.0976][0.161][0.238][0.323][0.412][0.5][0.584][0.66][0.728][0.786]] +[[20][0.0961][0.158][0.232][0.315][0.402][0.489][0.572][0.648][0.716][0.775]] +] + +See [@../../example/nc_chi_sq_example.cpp nc_chi_sq_example.cpp] for the full C++ source code. + +*/ + +//] diff --git a/src/boost/libs/math/example/neg_binom_confidence_limits.cpp b/src/boost/libs/math/example/neg_binom_confidence_limits.cpp new file mode 100644 index 000000000..6cca70cb6 --- /dev/null +++ b/src/boost/libs/math/example/neg_binom_confidence_limits.cpp @@ -0,0 +1,178 @@ +// neg_binomial_confidence_limits.cpp + +// Copyright John Maddock 2006 +// Copyright Paul A. Bristow 2007, 2010 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Caution: this file contains quickbook markup as well as code +// and comments, don't change any of the special comment markups! + +//[neg_binomial_confidence_limits + +/*` + +First we need some includes to access the negative binomial distribution +(and some basic std output of course). + +*/ + +#include <boost/math/distributions/negative_binomial.hpp> +using boost::math::negative_binomial; + +#include <iostream> +using std::cout; using std::endl; +#include <iomanip> +using std::setprecision; +using std::setw; using std::left; using std::fixed; using std::right; + +/*` +First define a table of significance levels: these are the +probabilities that the true occurrence frequency lies outside the calculated +interval: +*/ + + double alpha[] = { 0.5, 0.25, 0.1, 0.05, 0.01, 0.001, 0.0001, 0.00001 }; + +/*` +Confidence value as % is (1 - alpha) * 100, so alpha 0.05 == 95% confidence +that the true occurrence frequency lies *inside* the calculated interval. + +We need a function to calculate and print confidence limits +for an observed frequency of occurrence +that follows a negative binomial distribution. + +*/ + +void confidence_limits_on_frequency(unsigned trials, unsigned successes) +{ + // trials = Total number of trials. + // successes = Total number of observed successes. + // failures = trials - successes. + // success_fraction = successes /trials. + // Print out general info: + cout << + "______________________________________________\n" + "2-Sided Confidence Limits For Success Fraction\n" + "______________________________________________\n\n"; + cout << setprecision(7); + cout << setw(40) << left << "Number of trials" << " = " << trials << "\n"; + cout << setw(40) << left << "Number of successes" << " = " << successes << "\n"; + cout << setw(40) << left << "Number of failures" << " = " << trials - successes << "\n"; + cout << setw(40) << left << "Observed frequency of occurrence" << " = " << double(successes) / trials << "\n"; + + // Print table header: + cout << "\n\n" + "___________________________________________\n" + "Confidence Lower Upper\n" + " Value (%) Limit Limit\n" + "___________________________________________\n"; + + +/*` +And now for the important part - the bounds themselves. +For each value of /alpha/, we call `find_lower_bound_on_p` and +`find_upper_bound_on_p` to obtain lower and upper bounds respectively. +Note that since we are calculating a two-sided interval, +we must divide the value of alpha in two. Had we been calculating a +single-sided interval, for example: ['"Calculate a lower bound so that we are P% +sure that the true occurrence frequency is greater than some value"] +then we would *not* have divided by two. +*/ + + // Now print out the upper and lower limits for the alpha table values. + for(unsigned i = 0; i < sizeof(alpha)/sizeof(alpha[0]); ++i) + { + // Confidence value: + cout << fixed << setprecision(3) << setw(10) << right << 100 * (1-alpha[i]); + // Calculate bounds: + double lower = negative_binomial::find_lower_bound_on_p(trials, successes, alpha[i]/2); + double upper = negative_binomial::find_upper_bound_on_p(trials, successes, alpha[i]/2); + // Print limits: + cout << fixed << setprecision(5) << setw(15) << right << lower; + cout << fixed << setprecision(5) << setw(15) << right << upper << endl; + } + cout << endl; +} // void confidence_limits_on_frequency(unsigned trials, unsigned successes) + +/*` + +And then call confidence_limits_on_frequency with increasing numbers of trials, +but always the same success fraction 0.1, or 1 in 10. + +*/ + +int main() +{ + confidence_limits_on_frequency(20, 2); // 20 trials, 2 successes, 2 in 20, = 1 in 10 = 0.1 success fraction. + confidence_limits_on_frequency(200, 20); // More trials, but same 0.1 success fraction. + confidence_limits_on_frequency(2000, 200); // Many more trials, but same 0.1 success fraction. + + return 0; +} // int main() + +//] [/negative_binomial_confidence_limits_eg end of Quickbook in C++ markup] + +/* + +______________________________________________ +2-Sided Confidence Limits For Success Fraction +______________________________________________ +Number of trials = 20 +Number of successes = 2 +Number of failures = 18 +Observed frequency of occurrence = 0.1 +___________________________________________ +Confidence Lower Upper + Value (%) Limit Limit +___________________________________________ + 50.000 0.04812 0.13554 + 75.000 0.03078 0.17727 + 90.000 0.01807 0.22637 + 95.000 0.01235 0.26028 + 99.000 0.00530 0.33111 + 99.900 0.00164 0.41802 + 99.990 0.00051 0.49202 + 99.999 0.00016 0.55574 +______________________________________________ +2-Sided Confidence Limits For Success Fraction +______________________________________________ +Number of trials = 200 +Number of successes = 20 +Number of failures = 180 +Observed frequency of occurrence = 0.1000000 +___________________________________________ +Confidence Lower Upper + Value (%) Limit Limit +___________________________________________ + 50.000 0.08462 0.11350 + 75.000 0.07580 0.12469 + 90.000 0.06726 0.13695 + 95.000 0.06216 0.14508 + 99.000 0.05293 0.16170 + 99.900 0.04343 0.18212 + 99.990 0.03641 0.20017 + 99.999 0.03095 0.21664 +______________________________________________ +2-Sided Confidence Limits For Success Fraction +______________________________________________ +Number of trials = 2000 +Number of successes = 200 +Number of failures = 1800 +Observed frequency of occurrence = 0.1000000 +___________________________________________ +Confidence Lower Upper + Value (%) Limit Limit +___________________________________________ + 50.000 0.09536 0.10445 + 75.000 0.09228 0.10776 + 90.000 0.08916 0.11125 + 95.000 0.08720 0.11352 + 99.000 0.08344 0.11802 + 99.900 0.07921 0.12336 + 99.990 0.07577 0.12795 + 99.999 0.07282 0.13206 +*/ + diff --git a/src/boost/libs/math/example/neg_binomial_sample_sizes.cpp b/src/boost/libs/math/example/neg_binomial_sample_sizes.cpp new file mode 100644 index 000000000..d01089e9d --- /dev/null +++ b/src/boost/libs/math/example/neg_binomial_sample_sizes.cpp @@ -0,0 +1,209 @@ +// neg_binomial_sample_sizes.cpp + +// Copyright John Maddock 2006 +// Copyright Paul A. Bristow 2007, 2010 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/math/distributions/negative_binomial.hpp> +using boost::math::negative_binomial; + +// Default RealType is double so this permits use of: +double find_minimum_number_of_trials( +double k, // number of failures (events), k >= 0. +double p, // fraction of trails for which event occurs, 0 <= p <= 1. +double probability); // probability threshold, 0 <= probability <= 1. + +#include <iostream> +using std::cout; +using std::endl; +using std::fixed; +using std::right; +#include <iomanip> +using std::setprecision; +using std::setw; + +//[neg_binomial_sample_sizes + +/*` +It centres around a routine that prints out a table of +minimum sample sizes (number of trials) for various probability thresholds: +*/ + void find_number_of_trials(double failures, double p); +/*` +First define a table of significance levels: these are the maximum +acceptable probability that /failure/ or fewer events will be observed. +*/ + double alpha[] = { 0.5, 0.25, 0.1, 0.05, 0.01, 0.001, 0.0001, 0.00001 }; +/*` +Confidence value as % is (1 - alpha) * 100, so alpha 0.05 == 95% confidence +that the desired number of failures will be observed. +The values range from a very low 0.5 or 50% confidence up to an extremely high +confidence of 99.999. + +Much of the rest of the program is pretty-printing, the important part +is in the calculation of minimum number of trials required for each +value of alpha using: + + (int)ceil(negative_binomial::find_minimum_number_of_trials(failures, p, alpha[i]); + +find_minimum_number_of_trials returns a double, +so `ceil` rounds this up to ensure we have an integral minimum number of trials. +*/ + +void find_number_of_trials(double failures, double p) +{ + // trials = number of trials + // failures = number of failures before achieving required success(es). + // p = success fraction (0 <= p <= 1.). + // + // Calculate how many trials we need to ensure the + // required number of failures DOES exceed "failures". + + cout << "\n""Target number of failures = " << (int)failures; + cout << ", Success fraction = " << fixed << setprecision(1) << 100 * p << "%" << endl; + // Print table header: + cout << "____________________________\n" + "Confidence Min Number\n" + " Value (%) Of Trials \n" + "____________________________\n"; + // Now print out the data for the alpha table values. + for(unsigned i = 0; i < sizeof(alpha)/sizeof(alpha[0]); ++i) + { // Confidence values %: + cout << fixed << setprecision(3) << setw(10) << right << 100 * (1-alpha[i]) << " " + // find_minimum_number_of_trials + << setw(6) << right + << (int)ceil(negative_binomial::find_minimum_number_of_trials(failures, p, alpha[i])) + << endl; + } + cout << endl; +} // void find_number_of_trials(double failures, double p) + +/*` finally we can produce some tables of minimum trials for the chosen confidence levels: +*/ + +int main() +{ + find_number_of_trials(5, 0.5); + find_number_of_trials(50, 0.5); + find_number_of_trials(500, 0.5); + find_number_of_trials(50, 0.1); + find_number_of_trials(500, 0.1); + find_number_of_trials(5, 0.9); + + return 0; +} // int main() + +//] [/neg_binomial_sample_sizes.cpp end of Quickbook in C++ markup] + +/* + +Output is: +Target number of failures = 5, Success fraction = 50.0% + ____________________________ + Confidence Min Number + Value (%) Of Trials + ____________________________ + 50.000 11 + 75.000 14 + 90.000 17 + 95.000 18 + 99.000 22 + 99.900 27 + 99.990 31 + 99.999 36 + + + Target number of failures = 50, Success fraction = 50.0% + ____________________________ + Confidence Min Number + Value (%) Of Trials + ____________________________ + 50.000 101 + 75.000 109 + 90.000 115 + 95.000 119 + 99.000 128 + 99.900 137 + 99.990 146 + 99.999 154 + + + Target number of failures = 500, Success fraction = 50.0% + ____________________________ + Confidence Min Number + Value (%) Of Trials + ____________________________ + 50.000 1001 + 75.000 1023 + 90.000 1043 + 95.000 1055 + 99.000 1078 + 99.900 1104 + 99.990 1126 + 99.999 1146 + + + Target number of failures = 50, Success fraction = 10.0% + ____________________________ + Confidence Min Number + Value (%) Of Trials + ____________________________ + 50.000 56 + 75.000 58 + 90.000 60 + 95.000 61 + 99.000 63 + 99.900 66 + 99.990 68 + 99.999 71 + + + Target number of failures = 500, Success fraction = 10.0% + ____________________________ + Confidence Min Number + Value (%) Of Trials + ____________________________ + 50.000 556 + 75.000 562 + 90.000 567 + 95.000 570 + 99.000 576 + 99.900 583 + 99.990 588 + 99.999 594 + + + Target number of failures = 5, Success fraction = 90.0% + ____________________________ + Confidence Min Number + Value (%) Of Trials + ____________________________ + 50.000 57 + 75.000 73 + 90.000 91 + 95.000 103 + 99.000 127 + 99.900 159 + 99.990 189 + 99.999 217 + + + Target number of failures = 5, Success fraction = 95.0% + ____________________________ + Confidence Min Number + Value (%) Of Trials + ____________________________ + 50.000 114 + 75.000 148 + 90.000 184 + 95.000 208 + 99.000 259 + 99.900 324 + 99.990 384 + 99.999 442 + +*/ diff --git a/src/boost/libs/math/example/negative_binomial_example1.cpp b/src/boost/libs/math/example/negative_binomial_example1.cpp new file mode 100644 index 000000000..92fe48ce2 --- /dev/null +++ b/src/boost/libs/math/example/negative_binomial_example1.cpp @@ -0,0 +1,513 @@ +// negative_binomial_example1.cpp + +// Copyright Paul A. Bristow 2007, 2010. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Example 1 of using negative_binomial distribution. + +//[negative_binomial_eg1_1 + +/*` +Based on [@http://en.wikipedia.org/wiki/Negative_binomial_distribution +a problem by Dr. Diane Evans, +Professor of Mathematics at Rose-Hulman Institute of Technology]. + +Pat is required to sell candy bars to raise money for the 6th grade field trip. +There are thirty houses in the neighborhood, +and Pat is not supposed to return home until five candy bars have been sold. +So the child goes door to door, selling candy bars. +At each house, there is a 0.4 probability (40%) of selling one candy bar +and a 0.6 probability (60%) of selling nothing. + +What is the probability mass (density) function (pdf) for selling the last (fifth) +candy bar at the nth house? + +The Negative Binomial(r, p) distribution describes the probability of k failures +and r successes in k+r Bernoulli(p) trials with success on the last trial. +(A [@http://en.wikipedia.org/wiki/Bernoulli_distribution Bernoulli trial] +is one with only two possible outcomes, success of failure, +and p is the probability of success). +See also [@ http://en.wikipedia.org/wiki/Bernoulli_distribution Bernoulli distribution] +and [@http://www.math.uah.edu/stat/bernoulli/Introduction.xhtml Bernoulli applications]. + +In this example, we will deliberately produce a variety of calculations +and outputs to demonstrate the ways that the negative binomial distribution +can be implemented with this library: it is also deliberately over-commented. + +First we need to #define macros to control the error and discrete handling policies. +For this simple example, we want to avoid throwing +an exception (the default policy) and just return infinity. +We want to treat the distribution as if it was continuous, +so we choose a discrete_quantile policy of real, +rather than the default policy integer_round_outwards. +*/ +#define BOOST_MATH_OVERFLOW_ERROR_POLICY ignore_error +#define BOOST_MATH_DISCRETE_QUANTILE_POLICY real +/*` +After that we need some includes to provide easy access to the negative binomial distribution, +[caution It is vital to #include distributions etc *after* the above #defines] +and we need some std library iostream, of course. +*/ +#include <boost/math/distributions/negative_binomial.hpp> + // for negative_binomial_distribution + using boost::math::negative_binomial; // typedef provides default type is double. + using ::boost::math::pdf; // Probability mass function. + using ::boost::math::cdf; // Cumulative density function. + using ::boost::math::quantile; + +#include <iostream> + using std::cout; using std::endl; + using std::noshowpoint; using std::fixed; using std::right; using std::left; +#include <iomanip> + using std::setprecision; using std::setw; + +#include <limits> + using std::numeric_limits; +//] [negative_binomial_eg1_1] + +int main() +{ + cout <<"Selling candy bars - using the negative binomial distribution." + << "\nby Dr. Diane Evans," + "\nProfessor of Mathematics at Rose-Hulman Institute of Technology," + << "\nsee http://en.wikipedia.org/wiki/Negative_binomial_distribution\n" + << endl; + cout << endl; + cout.precision(5); + // None of the values calculated have a useful accuracy as great this, but + // INF shows wrongly with < 5 ! + // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=240227 +//[negative_binomial_eg1_2 +/*` +It is always sensible to use try and catch blocks because defaults policies are to +throw an exception if anything goes wrong. + +A simple catch block (see below) will ensure that you get a +helpful error message instead of an abrupt program abort. +*/ + try + { +/*` +Selling five candy bars means getting five successes, so successes r = 5. +The total number of trials (n, in this case, houses visited) this takes is therefore + = successes + failures or k + r = k + 5. +*/ + double sales_quota = 5; // Pat's sales quota - successes (r). +/*` +At each house, there is a 0.4 probability (40%) of selling one candy bar +and a 0.6 probability (60%) of selling nothing. +*/ + double success_fraction = 0.4; // success_fraction (p) - so failure_fraction is 0.6. +/*` +The Negative Binomial(r, p) distribution describes the probability of k failures +and r successes in k+r Bernoulli(p) trials with success on the last trial. +(A [@http://en.wikipedia.org/wiki/Bernoulli_distribution Bernoulli trial] +is one with only two possible outcomes, success of failure, +and p is the probability of success). + +We therefore start by constructing a negative binomial distribution +with parameters sales_quota (required successes) and probability of success. +*/ + negative_binomial nb(sales_quota, success_fraction); // type double by default. +/*` +To confirm, display the success_fraction & successes parameters of the distribution. +*/ + cout << "Pat has a sales per house success rate of " << success_fraction + << ".\nTherefore he would, on average, sell " << nb.success_fraction() * 100 + << " bars after trying 100 houses." << endl; + + int all_houses = 30; // The number of houses on the estate. + + cout << "With a success rate of " << nb.success_fraction() + << ", he might expect, on average,\n" + "to need to visit about " << success_fraction * all_houses + << " houses in order to sell all " << nb.successes() << " bars. " << endl; +/*` +[pre +Pat has a sales per house success rate of 0.4. +Therefore he would, on average, sell 40 bars after trying 100 houses. +With a success rate of 0.4, he might expect, on average, +to need to visit about 12 houses in order to sell all 5 bars. +] + +The random variable of interest is the number of houses +that must be visited to sell five candy bars, +so we substitute k = n - 5 into a negative_binomial(5, 0.4) +and obtain the __pdf of the distribution of houses visited. +Obviously, the best possible case is that Pat makes sales on all the first five houses. + +We calculate this using the pdf function: +*/ + cout << "Probability that Pat finishes on the " << sales_quota << "th house is " + << pdf(nb, 5 - sales_quota) << endl; // == pdf(nb, 0) +/*` +Of course, he could not finish on fewer than 5 houses because he must sell 5 candy bars. +So the 5th house is the first that he could possibly finish on. + +To finish on or before the 8th house, Pat must finish at the 5th, 6th, 7th or 8th house. +The probability that he will finish on *exactly* ( == ) on any house +is the Probability Density Function (pdf). +*/ + cout << "Probability that Pat finishes on the 6th house is " + << pdf(nb, 6 - sales_quota) << endl; + cout << "Probability that Pat finishes on the 7th house is " + << pdf(nb, 7 - sales_quota) << endl; + cout << "Probability that Pat finishes on the 8th house is " + << pdf(nb, 8 - sales_quota) << endl; +/*` +[pre +Probability that Pat finishes on the 6th house is 0.03072 +Probability that Pat finishes on the 7th house is 0.055296 +Probability that Pat finishes on the 8th house is 0.077414 +] + +The sum of the probabilities for these houses is the Cumulative Distribution Function (cdf). +We can calculate it by adding the individual probabilities. +*/ + cout << "Probability that Pat finishes on or before the 8th house is sum " + "\n" << "pdf(sales_quota) + pdf(6) + pdf(7) + pdf(8) = " + // Sum each of the mass/density probabilities for houses sales_quota = 5, 6, 7, & 8. + << pdf(nb, 5 - sales_quota) // 0 failures. + + pdf(nb, 6 - sales_quota) // 1 failure. + + pdf(nb, 7 - sales_quota) // 2 failures. + + pdf(nb, 8 - sales_quota) // 3 failures. + << endl; +/*`[pre +pdf(sales_quota) + pdf(6) + pdf(7) + pdf(8) = 0.17367 +] + +Or, usually better, by using the negative binomial *cumulative* distribution function. +*/ + cout << "\nProbability of selling his quota of " << sales_quota + << " bars\non or before the " << 8 << "th house is " + << cdf(nb, 8 - sales_quota) << endl; +/*`[pre +Probability of selling his quota of 5 bars on or before the 8th house is 0.17367 +]*/ + cout << "\nProbability that Pat finishes exactly on the 10th house is " + << pdf(nb, 10 - sales_quota) << endl; + cout << "\nProbability of selling his quota of " << sales_quota + << " bars\non or before the " << 10 << "th house is " + << cdf(nb, 10 - sales_quota) << endl; +/*` +[pre +Probability that Pat finishes exactly on the 10th house is 0.10033 +Probability of selling his quota of 5 bars on or before the 10th house is 0.3669 +]*/ + cout << "Probability that Pat finishes exactly on the 11th house is " + << pdf(nb, 11 - sales_quota) << endl; + cout << "\nProbability of selling his quota of " << sales_quota + << " bars\non or before the " << 11 << "th house is " + << cdf(nb, 11 - sales_quota) << endl; +/*`[pre +Probability that Pat finishes on the 11th house is 0.10033 +Probability of selling his quota of 5 candy bars +on or before the 11th house is 0.46723 +]*/ + cout << "Probability that Pat finishes exactly on the 12th house is " + << pdf(nb, 12 - sales_quota) << endl; + + cout << "\nProbability of selling his quota of " << sales_quota + << " bars\non or before the " << 12 << "th house is " + << cdf(nb, 12 - sales_quota) << endl; +/*`[pre +Probability that Pat finishes on the 12th house is 0.094596 +Probability of selling his quota of 5 candy bars +on or before the 12th house is 0.56182 +] +Finally consider the risk of Pat not selling his quota of 5 bars +even after visiting all the houses. +Calculate the probability that he /will/ sell on +or before the last house: +Calculate the probability that he would sell all his quota on the very last house. +*/ + cout << "Probability that Pat finishes on the " << all_houses + << " house is " << pdf(nb, all_houses - sales_quota) << endl; +/*` +Probability of selling his quota of 5 bars on the 30th house is +[pre +Probability that Pat finishes on the 30 house is 0.00069145 +] +when he'd be very unlucky indeed! + +What is the probability that Pat exhausts all 30 houses in the neighborhood, +and *still* doesn't sell the required 5 candy bars? +*/ + cout << "\nProbability of selling his quota of " << sales_quota + << " bars\non or before the " << all_houses << "th house is " + << cdf(nb, all_houses - sales_quota) << endl; +/*` +[pre +Probability of selling his quota of 5 bars +on or before the 30th house is 0.99849 +] + +So the risk of failing even after visiting all the houses is 1 - this probability, + ``1 - cdf(nb, all_houses - sales_quota`` +But using this expression may cause serious inaccuracy, +so it would be much better to use the complement of the cdf: +So the risk of failing even at, or after, the 31th (non-existent) houses is 1 - this probability, + ``1 - cdf(nb, all_houses - sales_quota)`` +But using this expression may cause serious inaccuracy. +So it would be much better to use the __complement of the cdf (see __why_complements). +*/ + cout << "\nProbability of failing to sell his quota of " << sales_quota + << " bars\neven after visiting all " << all_houses << " houses is " + << cdf(complement(nb, all_houses - sales_quota)) << endl; +/*` +[pre +Probability of failing to sell his quota of 5 bars +even after visiting all 30 houses is 0.0015101 +] +We can also use the quantile (percentile), the inverse of the cdf, to +predict which house Pat will finish on. So for the 8th house: +*/ + double p = cdf(nb, (8 - sales_quota)); + cout << "Probability of meeting sales quota on or before 8th house is "<< p << endl; +/*` +[pre +Probability of meeting sales quota on or before 8th house is 0.174 +] +*/ + cout << "If the confidence of meeting sales quota is " << p + << ", then the finishing house is " << quantile(nb, p) + sales_quota << endl; + + cout<< " quantile(nb, p) = " << quantile(nb, p) << endl; +/*` +[pre +If the confidence of meeting sales quota is 0.17367, then the finishing house is 8 +] +Demanding absolute certainty that all 5 will be sold, +implies an infinite number of trials. +(Of course, there are only 30 houses on the estate, +so he can't ever be *certain* of selling his quota). +*/ + cout << "If the confidence of meeting sales quota is " << 1. + << ", then the finishing house is " << quantile(nb, 1) + sales_quota << endl; + // 1.#INF == infinity. +/*`[pre +If the confidence of meeting sales quota is 1, then the finishing house is 1.#INF +] +And similarly for a few other probabilities: +*/ + cout << "If the confidence of meeting sales quota is " << 0. + << ", then the finishing house is " << quantile(nb, 0.) + sales_quota << endl; + + cout << "If the confidence of meeting sales quota is " << 0.5 + << ", then the finishing house is " << quantile(nb, 0.5) + sales_quota << endl; + + cout << "If the confidence of meeting sales quota is " << 1 - 0.00151 // 30 th + << ", then the finishing house is " << quantile(nb, 1 - 0.00151) + sales_quota << endl; +/*` +[pre +If the confidence of meeting sales quota is 0, then the finishing house is 5 +If the confidence of meeting sales quota is 0.5, then the finishing house is 11.337 +If the confidence of meeting sales quota is 0.99849, then the finishing house is 30 +] + +Notice that because we chose a discrete quantile policy of real, +the result can be an 'unreal' fractional house. + +If the opposite is true, we don't want to assume any confidence, then this is tantamount +to assuming that all the first sales_quota trials will be successful sales. +*/ + cout << "If confidence of meeting quota is zero\n(we assume all houses are successful sales)" + ", then finishing house is " << sales_quota << endl; +/*` +[pre +If confidence of meeting quota is zero (we assume all houses are successful sales), then finishing house is 5 +If confidence of meeting quota is 0, then finishing house is 5 +] +We can list quantiles for a few probabilities: +*/ + + double ps[] = {0., 0.001, 0.01, 0.05, 0.1, 0.5, 0.9, 0.95, 0.99, 0.999, 1.}; + // Confidence as fraction = 1-alpha, as percent = 100 * (1-alpha[i]) % + cout.precision(3); + for (unsigned i = 0; i < sizeof(ps)/sizeof(ps[0]); i++) + { + cout << "If confidence of meeting quota is " << ps[i] + << ", then finishing house is " << quantile(nb, ps[i]) + sales_quota + << endl; + } + +/*` +[pre +If confidence of meeting quota is 0, then finishing house is 5 +If confidence of meeting quota is 0.001, then finishing house is 5 +If confidence of meeting quota is 0.01, then finishing house is 5 +If confidence of meeting quota is 0.05, then finishing house is 6.2 +If confidence of meeting quota is 0.1, then finishing house is 7.06 +If confidence of meeting quota is 0.5, then finishing house is 11.3 +If confidence of meeting quota is 0.9, then finishing house is 17.8 +If confidence of meeting quota is 0.95, then finishing house is 20.1 +If confidence of meeting quota is 0.99, then finishing house is 24.8 +If confidence of meeting quota is 0.999, then finishing house is 31.1 +If confidence of meeting quota is 1, then finishing house is 1.#INF +] + +We could have applied a ceil function to obtain a 'worst case' integer value for house. +``ceil(quantile(nb, ps[i]))`` + +Or, if we had used the default discrete quantile policy, integer_outside, by omitting +``#define BOOST_MATH_DISCRETE_QUANTILE_POLICY real`` +we would have achieved the same effect. + +The real result gives some suggestion which house is most likely. +For example, compare the real and integer_outside for 95% confidence. + +[pre +If confidence of meeting quota is 0.95, then finishing house is 20.1 +If confidence of meeting quota is 0.95, then finishing house is 21 +] +The real value 20.1 is much closer to 20 than 21, so integer_outside is pessimistic. +We could also use integer_round_nearest policy to suggest that 20 is more likely. + +Finally, we can tabulate the probability for the last sale being exactly on each house. +*/ + cout << "\nHouse for " << sales_quota << "th (last) sale. Probability (%)" << endl; + cout.precision(5); + for (int i = (int)sales_quota; i < all_houses+1; i++) + { + cout << left << setw(3) << i << " " << setw(8) << cdf(nb, i - sales_quota) << endl; + } + cout << endl; +/*` +[pre +House for 5 th (last) sale. Probability (%) +5 0.01024 +6 0.04096 +7 0.096256 +8 0.17367 +9 0.26657 +10 0.3669 +11 0.46723 +12 0.56182 +13 0.64696 +14 0.72074 +15 0.78272 +16 0.83343 +17 0.874 +18 0.90583 +19 0.93039 +20 0.94905 +21 0.96304 +22 0.97342 +23 0.98103 +24 0.98655 +25 0.99053 +26 0.99337 +27 0.99539 +28 0.99681 +29 0.9978 +30 0.99849 +] + +As noted above, using a catch block is always a good idea, even if you do not expect to use it. +*/ + } + catch(const std::exception& e) + { // Since we have set an overflow policy of ignore_error, + // an overflow exception should never be thrown. + std::cout << "\nMessage from thrown exception was:\n " << e.what() << std::endl; +/*` +For example, without a ignore domain error policy, if we asked for ``pdf(nb, -1)`` for example, we would get: +[pre +Message from thrown exception was: + Error in function boost::math::pdf(const negative_binomial_distribution<double>&, double): + Number of failures argument is -1, but must be >= 0 ! +] +*/ +//] [/ negative_binomial_eg1_2] + } + return 0; +} // int main() + + +/* + +Output is: + +Selling candy bars - using the negative binomial distribution. +by Dr. Diane Evans, +Professor of Mathematics at Rose-Hulman Institute of Technology, +see http://en.wikipedia.org/wiki/Negative_binomial_distribution +Pat has a sales per house success rate of 0.4. +Therefore he would, on average, sell 40 bars after trying 100 houses. +With a success rate of 0.4, he might expect, on average, +to need to visit about 12 houses in order to sell all 5 bars. +Probability that Pat finishes on the 5th house is 0.01024 +Probability that Pat finishes on the 6th house is 0.03072 +Probability that Pat finishes on the 7th house is 0.055296 +Probability that Pat finishes on the 8th house is 0.077414 +Probability that Pat finishes on or before the 8th house is sum +pdf(sales_quota) + pdf(6) + pdf(7) + pdf(8) = 0.17367 +Probability of selling his quota of 5 bars +on or before the 8th house is 0.17367 +Probability that Pat finishes exactly on the 10th house is 0.10033 +Probability of selling his quota of 5 bars +on or before the 10th house is 0.3669 +Probability that Pat finishes exactly on the 11th house is 0.10033 +Probability of selling his quota of 5 bars +on or before the 11th house is 0.46723 +Probability that Pat finishes exactly on the 12th house is 0.094596 +Probability of selling his quota of 5 bars +on or before the 12th house is 0.56182 +Probability that Pat finishes on the 30 house is 0.00069145 +Probability of selling his quota of 5 bars +on or before the 30th house is 0.99849 +Probability of failing to sell his quota of 5 bars +even after visiting all 30 houses is 0.0015101 +Probability of meeting sales quota on or before 8th house is 0.17367 +If the confidence of meeting sales quota is 0.17367, then the finishing house is 8 + quantile(nb, p) = 3 +If the confidence of meeting sales quota is 1, then the finishing house is 1.#INF +If the confidence of meeting sales quota is 0, then the finishing house is 5 +If the confidence of meeting sales quota is 0.5, then the finishing house is 11.337 +If the confidence of meeting sales quota is 0.99849, then the finishing house is 30 +If confidence of meeting quota is zero +(we assume all houses are successful sales), then finishing house is 5 +If confidence of meeting quota is 0, then finishing house is 5 +If confidence of meeting quota is 0.001, then finishing house is 5 +If confidence of meeting quota is 0.01, then finishing house is 5 +If confidence of meeting quota is 0.05, then finishing house is 6.2 +If confidence of meeting quota is 0.1, then finishing house is 7.06 +If confidence of meeting quota is 0.5, then finishing house is 11.3 +If confidence of meeting quota is 0.9, then finishing house is 17.8 +If confidence of meeting quota is 0.95, then finishing house is 20.1 +If confidence of meeting quota is 0.99, then finishing house is 24.8 +If confidence of meeting quota is 0.999, then finishing house is 31.1 +If confidence of meeting quota is 1, then finishing house is 1.#J +House for 5th (last) sale. Probability (%) +5 0.01024 +6 0.04096 +7 0.096256 +8 0.17367 +9 0.26657 +10 0.3669 +11 0.46723 +12 0.56182 +13 0.64696 +14 0.72074 +15 0.78272 +16 0.83343 +17 0.874 +18 0.90583 +19 0.93039 +20 0.94905 +21 0.96304 +22 0.97342 +23 0.98103 +24 0.98655 +25 0.99053 +26 0.99337 +27 0.99539 +28 0.99681 +29 0.9978 +30 0.99849 + +*/ diff --git a/src/boost/libs/math/example/negative_binomial_example2.cpp b/src/boost/libs/math/example/negative_binomial_example2.cpp new file mode 100644 index 000000000..c1c90916a --- /dev/null +++ b/src/boost/libs/math/example/negative_binomial_example2.cpp @@ -0,0 +1,182 @@ +// negative_binomial_example2.cpp + +// Copyright Paul A. Bristow 2007, 2010. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Simple example demonstrating use of the Negative Binomial Distribution. + +#include <boost/math/distributions/negative_binomial.hpp> + using boost::math::negative_binomial_distribution; + using boost::math::negative_binomial; // typedef + +// In a sequence of trials or events +// (Bernoulli, independent, yes or no, succeed or fail) +// with success_fraction probability p, +// negative_binomial is the probability that k or fewer failures +// precede the r th trial's success. + +#include <iostream> +using std::cout; +using std::endl; +using std::setprecision; +using std::showpoint; +using std::setw; +using std::left; +using std::right; +#include <limits> +using std::numeric_limits; + +int main() +{ + cout << "Negative_binomial distribution - simple example 2" << endl; + // Construct a negative binomial distribution with: + // 8 successes (r), success fraction (p) 0.25 = 25% or 1 in 4 successes. + negative_binomial mynbdist(8, 0.25); // Shorter method using typedef. + + // Display (to check) properties of the distribution just constructed. + cout << "mean(mynbdist) = " << mean(mynbdist) << endl; // 24 + cout << "mynbdist.successes() = " << mynbdist.successes() << endl; // 8 + // r th successful trial, after k failures, is r + k th trial. + cout << "mynbdist.success_fraction() = " << mynbdist.success_fraction() << endl; + // success_fraction = failures/successes or k/r = 0.25 or 25%. + cout << "mynbdist.percent success = " << mynbdist.success_fraction() * 100 << "%" << endl; + // Show as % too. + // Show some cumulative distribution function values for failures k = 2 and 8 + cout << "cdf(mynbdist, 2.) = " << cdf(mynbdist, 2.) << endl; // 0.000415802001953125 + cout << "cdf(mynbdist, 8.) = " << cdf(mynbdist, 8.) << endl; // 0.027129956288263202 + cout << "cdf(complement(mynbdist, 8.)) = " << cdf(complement(mynbdist, 8.)) << endl; // 0.9728700437117368 + // Check that cdf plus its complement is unity. + cout << "cdf + complement = " << cdf(mynbdist, 8.) + cdf(complement(mynbdist, 8.)) << endl; // 1 + // Note: No complement for pdf! + + // Compare cdf with sum of pdfs. + double sum = 0.; // Calculate the sum of all the pdfs, + int k = 20; // for 20 failures + for(signed i = 0; i <= k; ++i) + { + sum += pdf(mynbdist, double(i)); + } + // Compare with the cdf + double cdf8 = cdf(mynbdist, static_cast<double>(k)); + double diff = sum - cdf8; // Expect the difference to be very small. + cout << setprecision(17) << "Sum pdfs = " << sum << ' ' // sum = 0.40025683281803698 + << ", cdf = " << cdf(mynbdist, static_cast<double>(k)) // cdf = 0.40025683281803687 + << ", difference = " // difference = 0.50000000000000000 + << setprecision(1) << diff/ (std::numeric_limits<double>::epsilon() * sum) + << " in epsilon units." << endl; + + // Note: Use boost::math::tools::epsilon rather than std::numeric_limits + // to cover RealTypes that do not specialize numeric_limits. + +//[neg_binomial_example2 + + // Print a table of values that can be used to plot + // using Excel, or some other superior graphical display tool. + + cout.precision(17); // Use max_digits10 precision, the maximum available for a reference table. + cout << showpoint << endl; // include trailing zeros. + // This is a maximum possible precision for the type (here double) to suit a reference table. + int maxk = static_cast<int>(2. * mynbdist.successes() / mynbdist.success_fraction()); + // This maxk shows most of the range of interest, probability about 0.0001 to 0.999. + cout << "\n"" k pdf cdf""\n" << endl; + for (int k = 0; k < maxk; k++) + { + cout << right << setprecision(17) << showpoint + << right << setw(3) << k << ", " + << left << setw(25) << pdf(mynbdist, static_cast<double>(k)) + << left << setw(25) << cdf(mynbdist, static_cast<double>(k)) + << endl; + } + cout << endl; +//] [/ neg_binomial_example2] + return 0; +} // int main() + +/* + +Output is: + +negative_binomial distribution - simple example 2 +mean(mynbdist) = 24 +mynbdist.successes() = 8 +mynbdist.success_fraction() = 0.25 +mynbdist.percent success = 25% +cdf(mynbdist, 2.) = 0.000415802001953125 +cdf(mynbdist, 8.) = 0.027129956288263202 +cdf(complement(mynbdist, 8.)) = 0.9728700437117368 +cdf + complement = 1 +Sum pdfs = 0.40025683281803692 , cdf = 0.40025683281803687, difference = 0.25 in epsilon units. + +//[neg_binomial_example2_1 + k pdf cdf + 0, 1.5258789062500000e-005 1.5258789062500003e-005 + 1, 9.1552734375000000e-005 0.00010681152343750000 + 2, 0.00030899047851562522 0.00041580200195312500 + 3, 0.00077247619628906272 0.0011882781982421875 + 4, 0.0015932321548461918 0.0027815103530883789 + 5, 0.0028678178787231476 0.0056493282318115234 + 6, 0.0046602040529251142 0.010309532284736633 + 7, 0.0069903060793876605 0.017299838364124298 + 8, 0.0098301179241389001 0.027129956288263202 + 9, 0.013106823898851871 0.040236780187115073 + 10, 0.016711200471036140 0.056947980658151209 + 11, 0.020509200578089786 0.077457181236241013 + 12, 0.024354675686481652 0.10181185692272265 + 13, 0.028101548869017230 0.12991340579173993 + 14, 0.031614242477644432 0.16152764826938440 + 15, 0.034775666725408917 0.19630331499479325 + 16, 0.037492515688331451 0.23379583068312471 + 17, 0.039697957787645101 0.27349378847076977 + 18, 0.041352039362130305 0.31484582783290005 + 19, 0.042440250924291580 0.35728607875719176 + 20, 0.042970754060845245 0.40025683281803687 + 21, 0.042970754060845225 0.44322758687888220 + 22, 0.042482450037426581 0.48571003691630876 + 23, 0.041558918514873783 0.52726895543118257 + 24, 0.040260202311284021 0.56752915774246648 + 25, 0.038649794218832620 0.60617895196129912 + 26, 0.036791631035234917 0.64297058299653398 + 27, 0.034747651533277427 0.67771823452981139 + 28, 0.032575923312447595 0.71029415784225891 + 29, 0.030329307911589130 0.74062346575384819 + 30, 0.028054609818219924 0.76867807557206813 + 31, 0.025792141284492545 0.79447021685656061 + 32, 0.023575629142856460 0.81804584599941710 + 33, 0.021432390129869489 0.83947823612928651 + 34, 0.019383705779220189 0.85886194190850684 + 35, 0.017445335201298231 0.87630727710980494 + 36, 0.015628112784496322 0.89193538989430121 + 37, 0.013938587078064250 0.90587397697236549 + 38, 0.012379666154859701 0.91825364312722524 + 39, 0.010951243136991251 0.92920488626421649 + 40, 0.0096507830144735539 0.93885566927869002 + 41, 0.0084738582566109364 0.94732952753530097 + 42, 0.0074146259745345548 0.95474415350983555 + 43, 0.0064662435824429246 0.96121039709227851 + 44, 0.0056212231142827853 0.96683162020656122 + 45, 0.0048717266990450708 0.97170334690560634 + 46, 0.0042098073105878630 0.97591315421619418 + 47, 0.0036275999165703964 0.97954075413276465 + 48, 0.0031174686783026818 0.98265822281106729 + 49, 0.0026721160099737302 0.98533033882104104 + 50, 0.0022846591885275322 0.98761499800956853 + 51, 0.0019486798960970148 0.98956367790566557 + 52, 0.0016582516423517923 0.99122192954801736 + 53, 0.0014079495076571762 0.99262987905567457 + 54, 0.0011928461106539983 0.99382272516632852 + 55, 0.0010084971662802015 0.99483122233260868 + 56, 0.00085091948404891532 0.99568214181665760 + 57, 0.00071656377604119542 0.99639870559269883 + 58, 0.00060228420831048650 0.99700098980100937 + 59, 0.00050530624256557675 0.99750629604357488 + 60, 0.00042319397814867202 0.99792949002172360 + 61, 0.00035381791615708398 0.99828330793788067 + 62, 0.00029532382517950324 0.99857863176306016 + 63, 0.00024610318764958566 0.99882473495070978 +//] [neg_binomial_example2_1 end of Quickbook] + +*/ diff --git a/src/boost/libs/math/example/neumann_zeros_example_1.cpp b/src/boost/libs/math/example/neumann_zeros_example_1.cpp new file mode 100644 index 000000000..b8042d96a --- /dev/null +++ b/src/boost/libs/math/example/neumann_zeros_example_1.cpp @@ -0,0 +1,85 @@ + +// Copyright Christopher Kormanyos 2013. +// Copyright Paul A. Bristow 2013. +// Copyright John Maddock 2013. + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http://www.boost.org/LICENSE_1_0.txt). + +#ifdef _MSC_VER +# pragma warning (disable : 4512) // assignment operator could not be generated. +# pragma warning (disable : 4996) // assignment operator could not be generated. +#endif + +#include <iostream> +#include <limits> +#include <vector> +#include <algorithm> +#include <iomanip> +#include <iterator> + +//[neumann_zeros_example_1 + +/*`[h5 Calculating zeros of the Neumann function.] +This example also shows how Boost.Math and Boost.Multiprecision can be combined to provide +a many decimal digit precision. For 50 decimal digit precision we need to include +*/ + + #include <boost/multiprecision/cpp_dec_float.hpp> + +/*`and a `typedef` for `float_type` may be convenient +(allowing a quick switch to re-compute at built-in `double` or other precision) +*/ + typedef boost::multiprecision::cpp_dec_float_50 float_type; + +//`To use the functions for finding zeros of the `cyl_neumann` function we need: + + #include <boost/math/special_functions/bessel.hpp> +//] [/neumann_zerso_example_1] + +int main() +{ + try + { + { +//[neumann_zeros_example_2 +/*`The Neumann (Bessel Y) function zeros are evaluated very similarly: +*/ + using boost::math::cyl_neumann_zero; + double zn = cyl_neumann_zero(2., 1); + std::cout << "cyl_neumann_zero(2., 1) = " << zn << std::endl; + + std::vector<float> nzeros(3); // Space for 3 zeros. + cyl_neumann_zero<float>(2.F, 1, nzeros.size(), nzeros.begin()); + + std::cout << "cyl_neumann_zero<float>(2.F, 1, "; + // Print the zeros to the output stream. + std::copy(nzeros.begin(), nzeros.end(), + std::ostream_iterator<float>(std::cout, ", ")); + + std::cout << "\n""cyl_neumann_zero(static_cast<float_type>(220)/100, 1) = " + << cyl_neumann_zero(static_cast<float_type>(220)/100, 1) << std::endl; + // 3.6154383428745996706772556069431792744372398748422 + +//] //[/neumann_zeros_example_2] + } + } + catch (std::exception const& ex) + { + std::cout << "Thrown exception " << ex.what() << std::endl; + } +} // int main() + +/* + Output: + +cyl_neumann_zero(2., 1) = 3.38424 +cyl_neumann_zero<float>(2.F, 1, +3.38424 +6.79381 +10.0235 +3.61544 +*/ + + diff --git a/src/boost/libs/math/example/nonfinite_facet_simple.cpp b/src/boost/libs/math/example/nonfinite_facet_simple.cpp new file mode 100644 index 000000000..730228161 --- /dev/null +++ b/src/boost/libs/math/example/nonfinite_facet_simple.cpp @@ -0,0 +1,269 @@ +/** nonfinite_num_facet.cpp +* +* Copyright (c) 2011 Paul A. Bristow +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt +* or copy at http://www.boost.org/LICENSE_1_0.txt) +* +* This very simple program illustrates how to use the +* `boost/math/nonfinite_num_facets.hpp' to obtain C99 +* representation of infinity and NaN. +* (from the original +* Floating Point Utilities contribution by Johan Rade. +* Floating Point Utility library has been accepted into Boost, +* but the utilities are incorporated into Boost.Math library. +* +\file + +\brief A very simple example of using non_finite_num facet for +C99 standard output of infinity and NaN. + +\detail Provided infinity and nan are supported, +this example shows how to create a C99 non-finite locale, +and imbue input and output streams with the non_finite_num put and get facets. +This allow output and input of infinity and NaN in a Standard portable way, +This permits 'loop-back' of output back into input (and portably across different system too). +This is particularly useful when used with Boost.Serialization so that non-finite NaNs and infinity +values in text and xml archives can be handled correctly and portably. + +*/ + +#ifdef _MSC_VER +# pragma warning (disable : 4127) // conditional expression is constant. +#endif + +#include <iostream> +using std::cout; +using std::endl; +using std::cerr; + +#include <iomanip> +using std::setw; +using std::left; +using std::right; +using std::internal; + +#include <string> +using std::string; + +#include <sstream> +using std::istringstream; + +#include <limits> +using std::numeric_limits; + +#include <locale> +using std::locale; + +#include <boost/math/special_functions/nonfinite_num_facets.hpp> +// from Johan Rade Floating Point Utilities. + +int main () +{ + std::cout << "Nonfinite_num_facet very simple example." << std::endl; + + if((std::numeric_limits<double>::has_infinity == 0) || (std::numeric_limits<double>::infinity() == 0)) + { + std::cout << "Infinity not supported on this platform." << std::endl; + return 0; + } + + if((std::numeric_limits<double>::has_quiet_NaN == 0) || (std::numeric_limits<double>::quiet_NaN() == 0)) + { + std::cout << "NaN not supported on this platform." << std::endl; + return 0; + } + + std::locale default_locale (std::locale::classic ()); // Note the current (default C) locale. + + // Create plus and minus infinity. + double plus_infinity = +std::numeric_limits<double>::infinity(); + double minus_infinity = -std::numeric_limits<double>::infinity(); + + // and create a NaN (NotANumber) + double NaN = +std::numeric_limits<double>::quiet_NaN (); + + double negated_NaN = (boost::math::changesign)(std::numeric_limits<double>::quiet_NaN ()); + + + // Output the nonfinite values using the current (default C) locale. + // The default representations differ from system to system, + // for example, using Microsoft compilers, 1.#INF, -1.#INF, and 1.#QNAN, + // Linux "inf", "-inf", "nan" + cout << "Using C locale" << endl; + cout << "+std::numeric_limits<double>::infinity() = " << plus_infinity << endl; + cout << "-std::numeric_limits<double>::infinity() = " << minus_infinity << endl; + cout << "+std::numeric_limits<double>::quiet_NaN () = " << NaN << endl; + + // Display negated NaN. + cout << "negated NaN " << negated_NaN << endl; // "-1.IND" or "-nan". + + // Create a new output locale, and add the nonfinite_num_put facet + std::locale C99_out_locale (default_locale, new boost::math::nonfinite_num_put<char>); + // and imbue the cout stream with the new locale. + cout.imbue (C99_out_locale); + + // Or for the same effect more concisely: + cout.imbue (locale(locale(), new boost::math::nonfinite_num_put<char>)); + + // Output using the new locale: + cout << "Using C99_out_locale " << endl; + cout << "+std::numeric_limits<double>::infinity() = " << plus_infinity << endl; + cout << "-std::numeric_limits<double>::infinity() = " << minus_infinity << endl; + cout << "+std::numeric_limits<double>::quiet_NaN () = " << NaN << endl; + // Expect "inf", "-inf", "nan". + + // Display negated NaN. + cout << "negated NaN " << negated_NaN << endl; // Expect "-nan". + + // Create a string with the expected C99 representation of plus infinity. + std::string inf = "inf"; + { // Try to read an infinity value using the default C locale. + // Create an input stream which will provide "inf" + std::istringstream iss (inf); + + // Create a double ready to take the input, + double infinity; + // and read "inf" from the stringstream: + iss >> infinity; + + // This will not work on all platforms! (Intel-Linux-13.0.1 fails EXIT STATUS: 139) + if (! iss) + { // Reading infinity went wrong! + std::cerr << "C locale input format error!" << std::endl; + } + } // Using default C locale. + + { // Now retry using C99 facets. + // Create a new input locale and add the nonfinite_num_get facet. + std::locale C99_in_locale (default_locale, new boost::math::nonfinite_num_get<char>); + + // Create an input stream which will provide "inf". + std::istringstream iss (inf); + // Imbue the stream with the C99 input locale. + iss.imbue (C99_in_locale); + + // Create a double ready to take the input, + double infinity; + // and read from the stringstream: + iss >> infinity; + + if (! iss) + { // Reading infinity went wrong! + std::cout << "C99 input format error!" << std::endl; + } + // Expect to get an infinity, which will display still using the C99 locale as "inf" + cout << "infinity in C99 representation is " << infinity << endl; + + // To check, we can switch back to the default C locale. + cout.imbue (default_locale); + cout << "infinity in default C representation is " << infinity << endl; + } // using C99 locale. + + { + // A 'loop-back example, output to a stringstream, and reading it back in. + // Create C99 input and output locales. + std::locale C99_out_locale (default_locale, new boost::math::nonfinite_num_put<char>); + std::locale C99_in_locale (default_locale, new boost::math::nonfinite_num_get<char>); + + std::ostringstream oss; + oss.imbue(C99_out_locale); + oss << plus_infinity; + + std::istringstream iss(oss.str()); // So stream contains "inf". + iss.imbue (C99_in_locale); + + std::string s; + + iss >> s; + + cout.imbue(C99_out_locale); + if (oss.str() != s) + { + cout << plus_infinity << " != " << s << " loopback failed!" << endl; + } + else + { + cout << plus_infinity << " == " << s << " as expected." << endl; + } + } + + + // Example varying the width and position of the nonfinite representations. + // With the nonfinite_num_put and _get facets, the width of the output is constant. + + #ifdef BOOST_NO_CXX11_NUMERIC_LIMITS + cout << "BOOST_NO_CXX11_NUMERIC_LIMITS is defined, so no max_digits10 available." << endl; + std::streamsize max_digits10 = 2 + std::numeric_limits<double>::digits * 30103UL / 100000UL; +#else + // Can use new C++0X max_digits10 (the maximum potentially significant digits). + std::streamsize max_digits10 = std::numeric_limits<double>::max_digits10; +#endif + cout << "std::numeric_limits<double>::max_digits10 is " << max_digits10 << endl; + cout.precision(max_digits10); + + double pi = 3.141592653589793238462643383279502884197169399375105820974944; + // Expect 17 (probably) decimal digits (regardless of locale). + // cout has the default locale. + cout << "pi = " << pi << endl; // pi = 3.1415926535897931 + cout.imbue (C99_out_locale); // Use cout with the C99 locale + // (expect the same output for a double). + cout << "pi = " << pi << endl; // pi = 3.1415926535897931 + + cout << "infinity in C99 representation is " << plus_infinity << endl; + + //int width = 2; // Check effect if width too small is OK. + // (There was a disturbed layout on older MSVC?). + int width = 20; + + // Similarly if we can switch back to the default C locale. + cout.imbue (default_locale); + cout << "infinity in default C representation is " << plus_infinity << endl; + cout << "infinity in default C representation (setw(" << width << ") is |" << setw(width) << plus_infinity <<'|' << endl; + cout << "infinity in default C representation (setw(" << width << ") is |" << left << setw(width) << plus_infinity <<'|' << endl; + cout << "infinity in default C representation (setw(" << width << ") is |" << internal << setw(width) << plus_infinity <<'|' << endl; + + cout.imbue (C99_out_locale); + cout << "infinity in C99 representation (setw(" << width << ") is |" << right << setw(width) << plus_infinity <<'|'<< endl; + cout << "infinity in C99 representation (setw(" << width << ") is |" << left << setw(width) << plus_infinity <<'|'<< endl; + cout << "infinity in C99 representation (setw(" << width << ") is |" << internal << setw(width) << plus_infinity <<'|'<< endl; + + return 0; +} // int main() + +// end of test_nonfinite_num_facets.cpp + +/* + +Output: + +simple_nonfinite_facet.vcxproj -> J:\Cpp\MathToolkit\test\Math_test\Release\nonfinite_facet_simple.exe + Nonfinite_num_facet very simple example. + Using C locale + +std::numeric_limits<double>::infinity() = 1.#INF + -std::numeric_limits<double>::infinity() = -1.#INF + +std::numeric_limits<double>::quiet_NaN () = 1.#QNAN + Using C99_out_locale + +std::numeric_limits<double>::infinity() = inf + -std::numeric_limits<double>::infinity() = -inf + +std::numeric_limits<double>::quiet_NaN () = nan + infinity in C99 representation is inf + infinity in default C representation is 1.#INF + 3 + 3 + inf == inf as expected. + std::numeric_limits<double>::max_digits10 is 17 + pi = 3.1415926535897931 + C locale input format error! + pi = 3.1415926535897931 + infinity in C99 representation is inf + infinity in default C representation is 1.#INF + infinity in default C representation (setw(20) is 1.#INF| + infinity in default C representation (setw(20) is 1.#INF | + infinity in default C representation (setw(20) is 1.#INF| + infinity in C99 representation (setw(20) is inf| + infinity in C99 representation (setw(20) is inf | + infinity in C99 representation (setw(20) is inf| + +*/ diff --git a/src/boost/libs/math/example/nonfinite_facet_sstream.cpp b/src/boost/libs/math/example/nonfinite_facet_sstream.cpp new file mode 100644 index 000000000..4408e4d4a --- /dev/null +++ b/src/boost/libs/math/example/nonfinite_facet_sstream.cpp @@ -0,0 +1,132 @@ +// nonfinite_facet_sstream.cpp + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Copyright (c) 2006 Johan Rade +// Copyright (c) 2011 Paul A. Bristow + +/*! +\file +\brief Examples of nonfinite with output and input facets and stringstreams. + +\detail Construct a new locale with the nonfinite_num_put and nonfinite_num_get +facets and imbue istringstream, ostringstream and stringstreams, +showing output and input (and loopback for the stringstream). + +*/ + +#include <boost/math/special_functions/nonfinite_num_facets.hpp> +using boost::math::nonfinite_num_put; +using boost::math::nonfinite_num_get; + +using boost::math::legacy; + +#include <iostream> +using std::cout; +using std::endl; +#include <locale> +using std::locale; + +#include <sstream> +using std::stringstream; +using std::istringstream; +using std::ostringstream; + +#include <limits> +using std::numeric_limits; + +#include <assert.h> + +int main() +{ + //[nonfinite_facets_sstream_1 + locale old_locale; + locale tmp_locale(old_locale, new nonfinite_num_put<char>); + locale new_locale(tmp_locale, new nonfinite_num_get<char>); + //] [/nonfinite_facets_sstream_1] + + // Note that to add two facets, nonfinite_num_put and nonfinite_num_get, + // you have to add one at a time, using a temporary locale. + + { + ostringstream oss; + oss.imbue(new_locale); + double inf = numeric_limits<double>::infinity(); + oss << inf; // Write out. + cout << "infinity output was " << oss.str() << endl; + BOOST_ASSERT(oss.str() == "inf"); + } + { + istringstream iss; + iss.str("inf"); + iss.imbue(new_locale); + double inf; + iss >> inf; // Read from "inf" + cout << "Infinity input was " << iss.str() << endl; + BOOST_ASSERT(inf == numeric_limits<double>::infinity()); + } + + { + //[nonfinite_facets_sstream_2 + stringstream ss; + ss.imbue(new_locale); + double inf = numeric_limits<double>::infinity(); + ss << inf; // Write out. + BOOST_ASSERT(ss.str() == "inf"); + double r; + ss >> r; // Read back in. + BOOST_ASSERT(inf == r); // Confirms that the double values really are identical. + + cout << "infinity output was " << ss.str() << endl; + cout << "infinity input was " << r << endl; + // But the string representation of r displayed will be the native type + // because, when it was constructed, cout had NOT been imbued + // with the new locale containing the nonfinite_numput facet. + // So the cout output will be "1.#INF on MS platforms + // and may be "inf" or other string representation on other platforms. + + //] [/nonfinite_facets_sstream_2] + } + + { + stringstream ss; + ss.imbue(new_locale); + + double nan = numeric_limits<double>::quiet_NaN(); + ss << nan; // Write out. + BOOST_ASSERT(ss.str() == "nan"); + + double v; + ss >> v; // Read back in. + + cout << "NaN output was " << ss.str() << endl; + cout << "NaN input was " << v << endl; + + // assert(nan == v); // Always fails because NaN == NaN fails! + // assert(nan == numeric_limits<double>::quiet_NaN()); asserts! + + // And the string representation will be the native type + // because cout has NOT been imbued with a locale containing + // the nonfinite_numput facet. + // So the output will be "1.#QNAN on MS platforms + // and may be "nan" or other string representation on other platforms. + } + +} // int main() + + +/* +//[nonfinite_facet_sstream_output + +infinity output was inf +Infinity input was inf +infinity output was inf +infinity input was 1.#INF +NaN output was nan +NaN input was 1.#QNAN + +//] [nonfinite_facet_sstream_output] +*/ + diff --git a/src/boost/libs/math/example/nonfinite_legacy.cpp b/src/boost/libs/math/example/nonfinite_legacy.cpp new file mode 100644 index 000000000..2e73fc2fc --- /dev/null +++ b/src/boost/libs/math/example/nonfinite_legacy.cpp @@ -0,0 +1,94 @@ +// nonfinite_legacy.cpp + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Copyright (c) 2006 Johan Rade +// Copyright (c) 2011 Paul A. Bristow + +/*! +\file +\brief Basic tests of nonfinite loopback with output and input facet. + +\detail Basic loopback test outputs using the so-called 'legacy' facets, +"1.#INF" and "1.#QNAN". + +and reads back in using nonfinite input 'legacy' facet, and +(if possible) checks if loopback OK. + +*/ + +#include <boost/math/special_functions/nonfinite_num_facets.hpp> +using boost::math::nonfinite_num_put; +using boost::math::nonfinite_num_get; + +using boost::math::legacy; + +#include <iostream> +using std::cout; +using std::endl; + +#include <iomanip> +using std::setfill; +using std::setw; + +#include <locale> +using std::locale; + +#include <sstream> +using std::stringstream; +#include <limits> +using std::numeric_limits; + +#include <assert.h> + +int main() +{ + // Create a new locale with both the nonfinite facets. + std::locale new_locale(std::locale(std::locale(), + new boost::math::nonfinite_num_put<char>), + new boost::math::nonfinite_num_get<char>); + + { + stringstream ss; + ss.imbue(new_locale); + double inf = numeric_limits<double>::infinity(); + ss << inf; // Write out. + double r; + ss >> r; // Read back in. + + cout << "infinity output was " << inf << endl; + cout << "infinity input was " << r << endl; + + BOOST_ASSERT(inf == r); + } + { + stringstream ss; + ss.imbue(new_locale); + + double nan = numeric_limits<double>::quiet_NaN(); + ss << nan; // Write out. + double v; + ss >> v; // Read back in. + + cout << "NaN output was " << nan << endl; + cout << "NaN input was " << v << endl; + + // BOOST_ASSERT(nan == v); // Always fails because NaN == NaN fails! + // BOOST_ASSERT(nan == numeric_limits<double>::quiet_NaN()); asserts! + } + +} // int main() + +/* + +Output: + +infinity output was 1.#INF +infinity input was 1.#INF +NaN output was 1.#QNAN +NaN input was 1.#QNAN + +*/ + diff --git a/src/boost/libs/math/example/nonfinite_loopback_ok.cpp b/src/boost/libs/math/example/nonfinite_loopback_ok.cpp new file mode 100644 index 000000000..70ccd24b9 --- /dev/null +++ b/src/boost/libs/math/example/nonfinite_loopback_ok.cpp @@ -0,0 +1,89 @@ +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Copyright (c) 2006 Johan Rade +// Copyright (c) 2011 Paul A. Bristow + +/*! +\file +\brief Basic tests of nonfinite loopback. + +\detail Basic loopback test outputs using nonfinite facets +(output and input) and reads back in, and checks if loopback OK. + +Expected to work portably on all platforms. + +*/ + +#ifdef _MSC_VER +# pragma warning(disable : 4702) +# pragma warning(disable : 4127) // conditional expression is constant. +#endif + +#include <boost/math/special_functions/nonfinite_num_facets.hpp> +using boost::math::nonfinite_num_get; +using boost::math::nonfinite_num_put; + +#include <iostream> +using std::cout; +using std::endl; + +#include <locale> +using std::locale; + +#include <sstream> +using std::stringstream; +#include <limits> +using std::numeric_limits; + +#include <assert.h> + +int main() +{ + + if((std::numeric_limits<double>::has_infinity == false) || (std::numeric_limits<double>::infinity() == 0)) + { + std::cout << "Infinity not supported on this platform." << std::endl; + return 0; + } + + if((std::numeric_limits<double>::has_quiet_NaN == false) || (std::numeric_limits<double>::quiet_NaN() == 0)) + { + std::cout << "NaN not supported on this platform." << std::endl; + return 0; + } + //locale old_locale; // Current global locale. + // Create tmp_locale and store the output nonfinite_num_put facet in it. + //locale tmp_locale(old_locale, new nonfinite_num_put<char>); + // Create new_locale and store the input nonfinite_num_get facet in it. + //locale new_locale(tmp_locale, new nonfinite_num_get<char>); + // Can only add one facet at a time, hence need a tmp_locale, + // unless we write: + + std::locale new_locale(std::locale(std::locale(std::locale(), + new boost::math::nonfinite_num_put<char>), + new boost::math::nonfinite_num_get<char>)); + + stringstream ss; // Both input and output, so need both get and put facets. + + ss.imbue(new_locale); + + double inf = numeric_limits<double>::infinity(); + ss << inf; // Write out. + double r; + ss >> r; // Read back in. + + BOOST_ASSERT(inf == r); // OK MSVC <= 10.0! + +} // int main() + +/* + +Output: + +nonfinite_loopback_ok.vcxproj -> J:\Cpp\fp_facet\fp_facet\Debug\nonfinite_loopback_ok.exe + +*/ + + diff --git a/src/boost/libs/math/example/nonfinite_num_facet.cpp b/src/boost/libs/math/example/nonfinite_num_facet.cpp new file mode 100644 index 000000000..80e4e8140 --- /dev/null +++ b/src/boost/libs/math/example/nonfinite_num_facet.cpp @@ -0,0 +1,291 @@ +/** nonfinite_num_facet.cpp + * + * Copyright (c) 2011 Francois Mauger + * Copyright (c) 2011 Paul A. Bristow + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt + * or copy at http://www.boost.org/LICENSE_1_0.txt) + * + * This simple program illustrates how to use the + * `boost/math/nonfinite_num_facets.hpp' material from the original + * Floating Point Utilities contribution by Johan Rade. + * Floating Point Utility library has been accepted into Boost, + * but the utilities have been/will be incorporated into Boost.Math library. + * +\file + +\brief A fairly simple example of using non_finite_num facet for +C99 standard output of infinity and NaN. + +\detail This program illustrates how to use the + `boost/math/nonfinite_num_facets.hpp' material from the original + Floating Point Utilities contribution by Johan Rade. + Floating Point Utility library has been accepted into Boost, + but the utilities have been/will be incorporated into Boost.Math library. + + Based on an example from Francois Mauger. + + Double and float variables are assigned ordinary finite values (pi), + and nonfinite like infinity and NaN. + + These values are then output and read back in, and then redisplayed. + +*/ + +#ifdef _MSC_VER +# pragma warning(disable : 4127) // conditional expression is constant. +#endif + +#include <iostream> +#include <iomanip> +using std::cout; +using std::endl; + +#include <limits> // numeric_limits +using std::numeric_limits; + +#include <boost/cstdint.hpp> + +#include <boost/math/special_functions/nonfinite_num_facets.hpp> + +static const char sep = ','; // Separator of bracketed float and double values. + +// Use max_digits10 (or equivalent) to obtain +// all potentially significant decimal digits for the floating-point types. + +#ifdef BOOST_NO_CXX11_NUMERIC_LIMITS + std::streamsize max_digits10_float = 2 + std::numeric_limits<float>::digits * 30103UL / 100000UL; + std::streamsize max_digits10_double = 2 + std::numeric_limits<double>::digits * 30103UL / 100000UL; +#else + // Can use new C++0X max_digits10 (the maximum potentially significant digits). + std::streamsize max_digits10_float = std::numeric_limits<float>::max_digits10; + std::streamsize max_digits10_double = std::numeric_limits<double>::max_digits10; +#endif + + +/* A class with a float and a double */ +struct foo +{ + foo () : fvalue (3.1415927F), dvalue (3.1415926535897931) + { + } + // Set both the values to -infinity : + void minus_infinity () + { + fvalue = -std::numeric_limits<float>::infinity (); + dvalue = -std::numeric_limits<double>::infinity (); + return; + } + // Set the values to +infinity : + void plus_infinity () + { + fvalue = +std::numeric_limits<float>::infinity (); + dvalue = +std::numeric_limits<double>::infinity (); + return; + } + // Set the values to NaN : + void nan () + { + fvalue = +std::numeric_limits<float>::quiet_NaN (); + dvalue = +std::numeric_limits<double>::quiet_NaN (); + return; + } + // Print a foo: + void print (std::ostream & a_out, const std::string & a_title) + { + if (a_title.empty ()) a_out << "foo"; + else a_out << a_title; + a_out << " : " << std::endl; + a_out << "|-- " << "fvalue = "; + + a_out.precision (max_digits10_float); + a_out << fvalue << std::endl; + a_out << "`-- " << "dvalue = "; + a_out.precision (max_digits10_double); + a_out << dvalue << std::endl; + return; + } + + // I/O operators for a foo structure of a float and a double : + friend std::ostream & operator<< (std::ostream & a_out, const foo & a_foo); + friend std::istream & operator>> (std::istream & a_in, foo & a_foo); + + // Attributes : + float fvalue; // Single precision floating number. + double dvalue; // Double precision floating number. +}; + +std::ostream & operator<< (std::ostream & a_out, const foo & a_foo) +{ // Output bracketed FPs, for example "(3.1415927,3.1415926535897931)" + a_out.precision (max_digits10_float); + a_out << "(" << a_foo.fvalue << sep ; + a_out.precision (max_digits10_double); + a_out << a_foo.dvalue << ")"; + return a_out; +} + +std::istream & operator>> (std::istream & a_in, foo & a_foo) +{ // Input bracketed floating-point values into a foo structure, + // for example from "(3.1415927,3.1415926535897931)" + char c = 0; + a_in.get (c); + if (c != '(') + { + std::cerr << "ERROR: operator>> No ( " << std::endl; + a_in.setstate(std::ios::failbit); + return a_in; + } + float f; + a_in >> std::ws >> f; + if (! a_in) + { + return a_in; + } + a_in >> std::ws; + a_in.get (c); + if (c != sep) + { + std::cerr << "ERROR: operator>> c='" << c << "'" << std::endl; + std::cerr << "ERROR: operator>> No '" << sep << "'" << std::endl; + a_in.setstate(std::ios::failbit); + return a_in; + } + double d; + a_in >> std::ws >> d; + if (! a_in) + { + return a_in; + } + a_in >> std::ws; + a_in.get (c); + if (c != ')') + { + std::cerr << "ERROR: operator>> No ) " << std::endl; + a_in.setstate(std::ios::failbit); + return a_in; + } + a_foo.fvalue = f; + a_foo.dvalue = d; + return a_in; +} // std::istream & operator>> (std::istream & a_in, foo & a_foo) + +int main () +{ + std::cout << "nonfinite_num_facet simple example." << std::endl; + + if((std::numeric_limits<double>::has_infinity == false) || (std::numeric_limits<double>::infinity() == 0)) + { + std::cout << "Infinity not supported on this platform." << std::endl; + return 0; + } + + if((std::numeric_limits<double>::has_quiet_NaN == false) || (std::numeric_limits<double>::quiet_NaN() == 0)) + { + std::cout << "NaN not supported on this platform." << std::endl; + return 0; + } + +#ifdef BOOST_NO_CXX11_NUMERIC_LIMITS + cout << "BOOST_NO_CXX11_NUMERIC_LIMITS is defined, so no max_digits10 available either:" + "\n we'll have to calculate our own version." << endl; +#endif + std::cout << "std::numeric_limits<float>::max_digits10 is " << max_digits10_float << endl; + std::cout << "std::numeric_limits<double>::max_digits10 is " << max_digits10_double << endl; + + std::locale the_default_locale (std::locale::classic ()); + + { + std::cout << "Write to a string buffer (using default locale) :" << std::endl; + foo f0; // pi + foo f1; f1.minus_infinity (); + foo f2; f2.plus_infinity (); + foo f3; f3.nan (); + + f0.print (std::cout, "f0"); // pi + f1.print (std::cout, "f1"); // +inf + f2.print (std::cout, "f2"); // -inf + f3.print (std::cout, "f3"); // NaN + + std::ostringstream oss; + std::locale C99_out_locale (the_default_locale, new boost::math::nonfinite_num_put<char>); + oss.imbue (C99_out_locale); + oss.precision (15); + oss << f0 << f1 << f2 << f3; + std::cout << "Output in C99 format is: \"" << oss.str () << "\"" << std::endl; + std::cout << "Output done." << std::endl; + } + + { + std::string the_string = "(3.1415927,3.1415926535897931)(-inf,-inf)(inf,inf)(nan,nan)"; // C99 format + // Must have correct separator! + std::cout << "Read C99 format from a string buffer containing \"" << the_string << "\""<< std::endl; + + std::locale C99_in_locale (the_default_locale, new boost::math::nonfinite_num_get<char>); + std::istringstream iss (the_string); + iss.imbue (C99_in_locale); + + foo f0, f1, f2, f3; + iss >> f0 >> f1 >> f2 >> f3; + if (! iss) + { + std::cerr << "Input Format error !" << std::endl; + } + else + { + std::cerr << "Input OK." << std::endl; + cout << "Display in default locale format " << endl; + f0.print (std::cout, "f0"); + f1.print (std::cout, "f1"); + f2.print (std::cout, "f2"); + f3.print (std::cout, "f3"); + } + std::cout << "Input done." << std::endl; + } + + std::cout << "End nonfinite_num_facet.cpp" << std::endl; + return 0; +} // int main() + + // end of test_nonfinite_num_facets.cpp + +/* + +Output: + +nonfinite_num_facet simple example. + std::numeric_limits<float>::max_digits10 is 8 + std::numeric_limits<double>::max_digits10 is 17 + Write to a string buffer (using default locale) : + f0 : + |-- fvalue = 3.1415927 + `-- dvalue = 3.1415926535897931 + f1 : + |-- fvalue = -1.#INF + `-- dvalue = -1.#INF + f2 : + |-- fvalue = 1.#INF + `-- dvalue = 1.#INF + f3 : + |-- fvalue = 1.#QNAN + `-- dvalue = 1.#QNAN + Output in C99 format is: "(3.1415927,3.1415926535897931)(-inf,-inf)(inf,inf)(nan,nan)" + Output done. + Read C99 format from a string buffer containing "(3.1415927,3.1415926535897931)(-inf,-inf)(inf,inf)(nan,nan)" + Display in default locale format + f0 : + |-- fvalue = 3.1415927 + `-- dvalue = 3.1415926535897931 + f1 : + |-- fvalue = -1.#INF + `-- dvalue = -1.#INF + f2 : + |-- fvalue = 1.#INF + `-- dvalue = 1.#INF + f3 : + |-- fvalue = 1.#QNAN + `-- dvalue = 1.#QNAN + Input done. + End nonfinite_num_facet.cpp + +*/ diff --git a/src/boost/libs/math/example/nonfinite_num_facet_serialization.cpp b/src/boost/libs/math/example/nonfinite_num_facet_serialization.cpp new file mode 100644 index 000000000..e2972a10f --- /dev/null +++ b/src/boost/libs/math/example/nonfinite_num_facet_serialization.cpp @@ -0,0 +1,433 @@ +/** nonfinite_num_facet_serialization.cpp + * + * Copyright (c) 2011 Francois Mauger + * Copyright (c) 2011 Paul A. Bristow + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt + * or copy at http://www.boost.org/LICENSE_1_0.txt) + * + * This sample program by Francois Mauger illustrates how to use the + * `boost/math/nonfinite_num_facets.hpp' material from the original + * Floating Point Utilities contribution by Johan Rade. Here it is + * shown how non finite floating number can be serialized and + * deserialized from I/O streams and/or Boost text/XML archives. It + * produces two archives stored in `test.txt' and `test.xml' files. + * + * Tested with Boost 1.44, gcc 4.4.1, Linux/i686 (32bits). + * Tested with Boost.1.46.1 MSVC 10.0 32 bit. + */ + +#ifdef _MSC_VER +# pragma warning(push) +//# pragma warning(disable : 4100) // unreferenced formal parameter. +#endif + +#include <iostream> +#include <sstream> +#include <fstream> +#include <limits> + +#include <boost/cstdint.hpp> +#include <boost/serialization/nvp.hpp> +#include <boost/archive/text_oarchive.hpp> +#include <boost/archive/text_iarchive.hpp> +#include <boost/archive/xml_oarchive.hpp> +#include <boost/archive/xml_iarchive.hpp> +#include <boost/archive/codecvt_null.hpp> + +// from the Floating Point Utilities : +#include <boost/math/special_functions/nonfinite_num_facets.hpp> + +static const char sep = ','; // Separator of bracketed float and double values. + +// Use max_digits10 (or equivalent) to obtain +// all potentially significant decimal digits for the floating-point types. + +#ifdef BOOST_NO_CXX11_NUMERIC_LIMITS + std::streamsize max_digits10_float = 2 + std::numeric_limits<float>::digits * 30103UL / 100000UL; + std::streamsize max_digits10_double = 2 + std::numeric_limits<double>::digits * 30103UL / 100000UL; +#else + // Can use new C++0X max_digits10 (the maximum potentially significant digits). + std::streamsize max_digits10_float = std::numeric_limits<float>::max_digits10; + std::streamsize max_digits10_double = std::numeric_limits<double>::max_digits10; +#endif + + +/* A class with a float and a double */ +struct foo +{ + foo () : fvalue (3.1415927F), dvalue (3.1415926535897931) + { // Construct using 32 and 64-bit max_digits10 decimal digits value of pi. + } + // Set the values at -infinity : + void minus_infinity () + { + fvalue = -std::numeric_limits<float>::infinity (); + dvalue = -std::numeric_limits<double>::infinity (); + return; + } + // Set the values at +infinity : + void plus_infinity () + { + fvalue = +std::numeric_limits<float>::infinity (); + dvalue = +std::numeric_limits<double>::infinity (); + return; + } + // Set the values at NaN : + void nan () + { + fvalue = +std::numeric_limits<float>::quiet_NaN (); + dvalue = +std::numeric_limits<double>::quiet_NaN (); + return; + } + // Print : + void print (std::ostream & a_out, const std::string & a_title) + { + if (a_title.empty ()) a_out << "foo"; + else a_out << a_title; + a_out << " : " << std::endl; + a_out << "|-- " << "fvalue = "; + a_out.precision (7); + a_out << fvalue << std::endl; + a_out << "`-- " << "dvalue = "; + a_out.precision (15); + a_out << dvalue << std::endl; + return; + } + + // I/O operators : + friend std::ostream & operator<< (std::ostream & a_out, const foo & a_foo); + friend std::istream & operator>> (std::istream & a_in, foo & a_foo); + + // Boost serialization : + template <class Archive> + void serialize (Archive & ar, int /*version*/) + { + ar & BOOST_SERIALIZATION_NVP (fvalue); + ar & BOOST_SERIALIZATION_NVP (dvalue); + return; + } + + // Attributes : + float fvalue; // Single precision floating-point number. + double dvalue; // Double precision floating-point number. +}; + +std::ostream & operator<< (std::ostream & a_out, const foo & a_foo) +{ // Output bracketed FPs, for example "(3.1415927,3.1415926535897931)" + a_out.precision (max_digits10_float); + a_out << "(" << a_foo.fvalue << sep ; + a_out.precision (max_digits10_double); + a_out << a_foo.dvalue << ")"; + return a_out; +} + +std::istream & operator>> (std::istream & a_in, foo & a_foo) +{ // Input bracketed floating-point values into a foo structure, + // for example from "(3.1415927,3.1415926535897931)" + char c = 0; + a_in.get (c); + if (c != '(') + { + std::cerr << "ERROR: operator>> No ( " << std::endl; + a_in.setstate(std::ios::failbit); + return a_in; + } + float f; + a_in >> std::ws >> f; + if (! a_in) + { + return a_in; + } + a_in >> std::ws; + a_in.get (c); + if (c != sep) + { + std::cerr << "ERROR: operator>> c='" << c << "'" << std::endl; + std::cerr << "ERROR: operator>> No '" << sep << "'" << std::endl; + a_in.setstate(std::ios::failbit); + return a_in; + } + double d; + a_in >> std::ws >> d; + if (! a_in) + { + return a_in; + } + a_in >> std::ws; + a_in.get (c); + if (c != ')') + { + std::cerr << "ERROR: operator>> No ) " << std::endl; + a_in.setstate(std::ios::failbit); + return a_in; + } + a_foo.fvalue = f; + a_foo.dvalue = d; + return a_in; +} + +int main (void) +{ + std::clog << std::endl + << "Nonfinite_serialization.cpp' example program." << std::endl; + +#ifdef BOOST_NO_CXX11_NUMERIC_LIMITS + std::cout << "BOOST_NO_CXX11_NUMERIC_LIMITS is defined, so no max_digits10 available either," + "using our own version instead." << std::endl; +#endif + std::cout << "std::numeric_limits<float>::max_digits10 is " << max_digits10_float << std::endl; + std::cout << "std::numeric_limits<double>::max_digits10 is " << max_digits10_double << std::endl; + + std::locale the_default_locale (std::locale::classic (), + new boost::archive::codecvt_null<char>); + + // Demonstrate use of nonfinite facets with stringstreams. + { + std::clog << "Construct some foo structures with a finite and nonfinites." << std::endl; + foo f0; + foo f1; f1.minus_infinity (); + foo f2; f2.plus_infinity (); + foo f3; f3.nan (); + // Display them. + f0.print (std::clog, "f0"); + f1.print (std::clog, "f1"); + f2.print (std::clog, "f2"); + f3.print (std::clog, "f3"); + std::clog << " Write to a string buffer." << std::endl; + + std::ostringstream oss; + std::locale the_out_locale (the_default_locale, new boost::math::nonfinite_num_put<char>); + oss.imbue (the_out_locale); + oss.precision (max_digits10_double); + oss << f0 << f1 << f2 << f3; + std::clog << "Output is: `" << oss.str () << "'" << std::endl; + std::clog << "Done output to ostringstream." << std::endl; + } + + { + std::clog << "Read foo structures from a string buffer." << std::endl; + + std::string the_string = "(3.1415927,3.1415926535897931)(-inf,-inf)(inf,inf)(nan,nan)"; + std::clog << "Input is: `" << the_string << "'" << std::endl; + + std::locale the_in_locale (the_default_locale, new boost::math::nonfinite_num_get<char>); + std::istringstream iss (the_string); + iss.imbue (the_in_locale); + + foo f0, f1, f2, f3; + iss >> f0 >> f1 >> f2 >> f3; + if (! iss) + { + std::cerr << "Format error !" << std::endl; + } + else + { + std::cerr << "Read OK." << std::endl; + f0.print (std::clog, "f0"); + f1.print (std::clog, "f1"); + f2.print (std::clog, "f2"); + f3.print (std::clog, "f3"); + } + std::clog << "Done input from istringstream." << std::endl; + } + + { // Demonstrate use of nonfinite facets for Serialization with Boost text archives. + std::clog << "Serialize (using Boost text archive)." << std::endl; + // Construct some foo structures with a finite and nonfinites. + foo f0; + foo f1; f1.minus_infinity (); + foo f2; f2.plus_infinity (); + foo f3; f3.nan (); + // Display them. + f0.print (std::clog, "f0"); + f1.print (std::clog, "f1"); + f2.print (std::clog, "f2"); + f3.print (std::clog, "f3"); + + std::locale the_out_locale (the_default_locale, new boost::math::nonfinite_num_put<char>); + // Use a temporary folder .temps (which contains "boost-no-inspect" so that it will not be inspected, and made 'hidden' too). + std::ofstream fout ("./.temps/nonfinite_archive_test.txt"); + fout.imbue (the_out_locale); + boost::archive::text_oarchive toar (fout, boost::archive::no_codecvt); + // Write to archive. + toar & f0; + toar & f1; + toar & f2; + toar & f3; + std::clog << "Done." << std::endl; + } + + { + std::clog << "Deserialize (Boost text archive)..." << std::endl; + std::locale the_in_locale (the_default_locale, new boost::math::nonfinite_num_get<char>); + // Use a temporary folder .temps (which contains "boost-no-inspect" so that it will not be inspected, and made 'hidden' too). + std::ifstream fin ("./.temps/nonfinite_archive_test.txt"); + fin.imbue (the_in_locale); + boost::archive::text_iarchive tiar (fin, boost::archive::no_codecvt); + foo f0, f1, f2, f3; + // Read from archive. + tiar & f0; + tiar & f1; + tiar & f2; + tiar & f3; + // Display foos. + f0.print (std::clog, "f0"); + f1.print (std::clog, "f1"); + f2.print (std::clog, "f2"); + f3.print (std::clog, "f3"); + + std::clog << "Done." << std::endl; + } + + { // Demonstrate use of nonfinite facets for Serialization with Boost XML Archive. + std::clog << "Serialize (Boost XML archive)..." << std::endl; + // Construct some foo structures with a finite and nonfinites. + foo f0; + foo f1; f1.minus_infinity (); + foo f2; f2.plus_infinity (); + foo f3; f3.nan (); + // Display foos. + f0.print (std::clog, "f0"); + f1.print (std::clog, "f1"); + f2.print (std::clog, "f2"); + f3.print (std::clog, "f3"); + + std::locale the_out_locale (the_default_locale, new boost::math::nonfinite_num_put<char>); + // Use a temporary folder /.temps (which contains "boost-no-inspect" so that it will not be inspected, and made 'hidden' too). + std::ofstream fout ("./.temps/nonfinite_XML_archive_test.txt"); + fout.imbue (the_out_locale); + boost::archive::xml_oarchive xoar (fout, boost::archive::no_codecvt); + + xoar & BOOST_SERIALIZATION_NVP (f0); + xoar & BOOST_SERIALIZATION_NVP (f1); + xoar & BOOST_SERIALIZATION_NVP (f2); + xoar & BOOST_SERIALIZATION_NVP (f3); + std::clog << "Done." << std::endl; + } + + { + std::clog << "Deserialize (Boost XML archive)..." << std::endl; + std::locale the_in_locale (the_default_locale, new boost::math::nonfinite_num_get<char>); + // Use a temporary folder /.temps (which contains "boost-no-inspect" so that it will not be inspected, and made 'hidden' too). + std::ifstream fin ("./.temps/nonfinite_XML_archive_test.txt"); // Previously written above. + fin.imbue (the_in_locale); + boost::archive::xml_iarchive xiar (fin, boost::archive::no_codecvt); + foo f0, f1, f2, f3; + + xiar & BOOST_SERIALIZATION_NVP (f0); + xiar & BOOST_SERIALIZATION_NVP (f1); + xiar & BOOST_SERIALIZATION_NVP (f2); + xiar & BOOST_SERIALIZATION_NVP (f3); + + f0.print (std::clog, "f0"); + f1.print (std::clog, "f1"); + f2.print (std::clog, "f2"); + f3.print (std::clog, "f3"); + + std::clog << "Done." << std::endl; + } + + std::clog << "End nonfinite_serialization.cpp' example program." << std::endl; + return 0; +} + +/* + +Output: + + Nonfinite_serialization.cpp' example program. + std::numeric_limits<float>::max_digits10 is 8 + std::numeric_limits<double>::max_digits10 is 17 + Construct some foo structures with a finite and nonfinites. + f0 : + |-- fvalue = 3.141593 + `-- dvalue = 3.14159265358979 + f1 : + |-- fvalue = -1.#INF + `-- dvalue = -1.#INF + f2 : + |-- fvalue = 1.#INF + `-- dvalue = 1.#INF + f3 : + |-- fvalue = 1.#QNAN + `-- dvalue = 1.#QNAN + Write to a string buffer. + Output is: `(3.1415927,3.1415926535897931)(-inf,-inf)(inf,inf)(nan,nan)' + Done output to ostringstream. + Read foo structures from a string buffer. + Input is: `(3.1415927,3.1415926535897931)(-inf,-inf)(inf,inf)(nan,nan)' + Read OK. + f0 : + |-- fvalue = 3.141593 + `-- dvalue = 3.14159265358979 + f1 : + |-- fvalue = -1.#INF + `-- dvalue = -1.#INF + f2 : + |-- fvalue = 1.#INF + `-- dvalue = 1.#INF + f3 : + |-- fvalue = 1.#QNAN + `-- dvalue = 1.#QNAN + Done input from istringstream. + Serialize (using Boost text archive). + f0 : + |-- fvalue = 3.141593 + `-- dvalue = 3.14159265358979 + f1 : + |-- fvalue = -1.#INF + `-- dvalue = -1.#INF + f2 : + |-- fvalue = 1.#INF + `-- dvalue = 1.#INF + f3 : + |-- fvalue = 1.#QNAN + `-- dvalue = 1.#QNAN + Done. + Deserialize (Boost text archive)... + f0 : + |-- fvalue = 3.141593 + `-- dvalue = 3.14159265358979 + f1 : + |-- fvalue = -1.#INF + `-- dvalue = -1.#INF + f2 : + |-- fvalue = 1.#INF + `-- dvalue = 1.#INF + f3 : + |-- fvalue = 1.#QNAN + `-- dvalue = 1.#QNAN + Done. + Serialize (Boost XML archive)... + f0 : + |-- fvalue = 3.141593 + `-- dvalue = 3.14159265358979 + f1 : + |-- fvalue = -1.#INF + `-- dvalue = -1.#INF + f2 : + |-- fvalue = 1.#INF + `-- dvalue = 1.#INF + f3 : + |-- fvalue = 1.#QNAN + `-- dvalue = 1.#QNAN + Done. + Deserialize (Boost XML archive)... + f0 : + |-- fvalue = 3.141593 + `-- dvalue = 3.14159265358979 + f1 : + |-- fvalue = -1.#INF + `-- dvalue = -1.#INF + f2 : + |-- fvalue = 1.#INF + `-- dvalue = 1.#INF + f3 : + |-- fvalue = 1.#QNAN + `-- dvalue = 1.#QNAN + Done. + End nonfinite_serialization.cpp' example program. + + */ diff --git a/src/boost/libs/math/example/nonfinite_num_facet_trap.cpp b/src/boost/libs/math/example/nonfinite_num_facet_trap.cpp new file mode 100644 index 000000000..9a4b2d58e --- /dev/null +++ b/src/boost/libs/math/example/nonfinite_num_facet_trap.cpp @@ -0,0 +1,115 @@ + +/** nonfinite_num_facet_trap.cpp +* +* Copyright (c) 2012 Paul A. Bristow +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt +* or copy at http://www.boost.org/LICENSE_1_0.txt) +* +* This very simple program illustrates how to use the +* `boost/math/nonfinite_num_facets.hpp` trapping output of infinity and/or NaNs. +* +\file + +\brief A very simple example of using non_finite_num facet for +trapping output of infinity and/or NaNs. + +\note To actually get an exception throw by the iostream library +one must enable exceptions. + `oss.exceptions(std::ios_base::failbit | std::ios_base::badbit);` +\note Which bit is set is implementation dependent, so enable exceptions for both. + +This is a fairly brutal method of catching nonfinites on output, +but may suit some applications. + +*/ + +#ifdef _MSC_VER +# pragma warning(disable : 4127) // conditional expression is constant. +// assumes C++ exceptions enabled /EHsc +#endif + +#include <boost/cstdint.hpp> +#include <boost/math/special_functions/nonfinite_num_facets.hpp> + +#include <iostream> +#include <iomanip> +using std::cout; +using std::endl; +using std::hex; +#include <exception> +#include <limits> // numeric_limits +using std::numeric_limits; + +int main() +{ + using namespace boost::math; + + std::cout << "nonfinite_num_facet_trap.cpp" << std::endl; + + const double inf = +std::numeric_limits<double>::infinity (); + const double nan = +std::numeric_limits<double>::quiet_NaN (); + + { // Output infinity and NaN with default flags (no trapping). + std::ostringstream oss; + std::locale default_locale (std::locale::classic ()); + std::locale C99_out_locale (default_locale, new boost::math::nonfinite_num_put<char>); + oss.imbue (C99_out_locale); + oss.exceptions(std::ios_base::failbit | std::ios_base::badbit); + oss << inf << ' ' << nan; + cout << "oss.rdstate() = " << hex << oss.rdstate() << endl; // 0 + cout << "os.str() = " << oss.str() << endl; // os.str() = inf nan + } + + try + { // // Output infinity with flags set to trap and catch any infinity. + std::ostringstream oss; + std::locale default_locale (std::locale::classic ()); + std::locale C99_out_locale (default_locale, new boost::math::nonfinite_num_put<char>(trap_infinity)); + oss.imbue (C99_out_locale); + oss.exceptions(std::ios_base::failbit | std::ios_base::badbit); + // Note that which bit is set is implementation dependent, so enable exceptions for both. + oss << inf; + cout << "oss.rdstate() = " << hex << oss.rdstate() << endl; + cout << "oss.str() = " << oss.str() << endl; + } + catch(const std::ios_base::failure& e) + { // Expect "Infinity". + std::cout << "\n""Message from thrown exception was: " << e.what() << std::endl; + } + + try + { // // Output NaN with flags set to catch any NaNs. + std::ostringstream oss; + std::locale default_locale (std::locale::classic ()); + std::locale C99_out_locale (default_locale, new boost::math::nonfinite_num_put<char>(trap_nan)); + oss.imbue (C99_out_locale); + oss.exceptions(std::ios_base::failbit | std::ios_base::badbit); + // Note that which bit is set is implementation dependent, so enable exceptions for both. + oss << nan; + cout << "oss.str() = " << oss.str() << endl; + } + catch(const std::ios_base::failure& e) + { // Expect "Infinity". + std::cout << "\n""Message from thrown exception was: " << e.what() << std::endl; + } + + + return 0; // end of nonfinite_num_facet_trap.cpp +} // int main() + + +/* + +Output: + + nonfinite_num_facet_trap.cpp + oss.rdstate() = 0 + os.str() = inf nan + + Message from thrown exception was: Infinity + + Message from thrown exception was: NaN + +*/ diff --git a/src/boost/libs/math/example/nonfinite_serialization_archives.cpp b/src/boost/libs/math/example/nonfinite_serialization_archives.cpp new file mode 100644 index 000000000..0cb53ff0c --- /dev/null +++ b/src/boost/libs/math/example/nonfinite_serialization_archives.cpp @@ -0,0 +1,136 @@ +/** nonfinite_serialization_archives.cpp +* +* Copyright (c) 2011 Paul A. Bristow +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt +* or copy at http://www.boost.org/LICENSE_1_0.txt) +* +* This very simple program illustrates how to use the +* `boost/math/nonfinite_num_facets.hpp' to obtain C99 +* representation of infinity and NaN. +* From the original Floating Point Utilities contribution by Johan Rade. +* Floating Point Utility library has been accepted into Boost, +* but the utilities are incorporated into Boost.Math library. +* +\file + +\brief A simple example of using non_finite_num facet for +C99 standard output of infinity and NaN in serialization archives. + +\detail This example shows how to create a C99 non-finite locale, +and imbue input and output streams with the non_finite_num put and get facets. +This allow output and input of infinity and NaN in a Standard portable way, +This permits 'loop-back' of output back into input (and portably across different system too). +This is particularly useful when used with Boost.Serialization so that non-finite NaNs and infinity +values in text and xml archives can be handled correctly and portably. + +*/ + + +#ifdef _MSC_VER +# pragma warning(disable : 4127) // conditional expression is constant. +#endif + + +#include <boost/archive/text_oarchive.hpp> +using boost::archive::text_oarchive; +#include <boost/archive/codecvt_null.hpp> +using boost::archive::codecvt_null; +using boost::archive::no_codecvt; + +#include <boost/math/special_functions/nonfinite_num_facets.hpp> +using boost::math::nonfinite_num_get; +using boost::math::nonfinite_num_put; + +#include <iostream> +using std::cout; +using std::endl; +using std::cerr; + +#include <iomanip> +using std::setw; +using std::left; +using std::right; +using std::internal; + +#include <string> +using std::string; + +#include <sstream> +using std::istringstream; + +#include <fstream> +using std::ofstream; + +#include <limits> +using std::numeric_limits; + +#include <locale> +using std::locale; + + +/* +Use with serialization archives. + +It is important that the same locale is used +when an archive is saved and when it is loaded. +Otherwise, loading the archive may fail. + +By default, archives are saved and loaded with a classic C locale with a +`boost::archive::codecvt_null` facet added. +Normally you do not have to worry about that. +The constructors for the archive classes, as a side-effect, +imbue the stream with such a locale. + +However, if you want to use the facets `nonfinite_num_put` and `nonfinite_num_get` +with archives,`then you have to manage the locale manually. + +That is done by calling the archive constructor with the flag `boost::archive::no_codecvt`. +Then the archive constructor will not imbue the stream with a new locale. + +The following code shows how to use `nonfinite_num_put` with a `text_oarchive`: + +*/ + +int main() +{ + + if((std::numeric_limits<double>::has_infinity == false) || (std::numeric_limits<double>::infinity() == 0)) + { + std::cout << "Infinity not supported on this platform." << std::endl; + return 0; + } + + if((std::numeric_limits<double>::has_quiet_NaN == false) || (std::numeric_limits<double>::quiet_NaN() == 0)) + { + std::cout << "NaN not supported on this platform." << std::endl; + return 0; + } + + locale default_locale(locale::classic(), new boost::archive::codecvt_null<char>); + // codecvt_null so the archive constructor will not imbue the stream with a new locale. + + locale my_locale(default_locale, new nonfinite_num_put<char>); + // Add nonfinite_num_put facet to locale. + + // Use a temporary folder /.temps (which contains "boost-no-inspect" so that it will not be inspected, and made 'hidden' too). + ofstream ofs("./.temps/test.txt"); + ofs.imbue(my_locale); + + boost::archive::text_oarchive oa(ofs, no_codecvt); + + double x = numeric_limits<double>::infinity(); + oa & x; + +} // int main() + + +/* The same method works with nonfinite_num_get and text_iarchive. + +If you use the trap_infinity and trap_nan flags with a serialization archive, +then you must set the exception mask of the stream. +Serialization archives do not check the stream state. + + +*/ diff --git a/src/boost/libs/math/example/nonfinite_signaling_NaN.cpp b/src/boost/libs/math/example/nonfinite_signaling_NaN.cpp new file mode 100644 index 000000000..98ccdd1d9 --- /dev/null +++ b/src/boost/libs/math/example/nonfinite_signaling_NaN.cpp @@ -0,0 +1,189 @@ +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Copyright (c) 2006 Johan Rade +// Copyright (c) 2011 Paul A. Bristow + +/*! +\file +\brief Tests of nonfinite signaling NaN loopback. + +\detail nonfinite signaling NaN +test outputs using nonfinite facets +(output and input) and reads back in, and checks if loopback OK. + +Not expected to work on all platforms (if any). But shows that on MSVC, +this legacy locale can ensure a consistent quiet NaN input from representations +"1.#QNAN", "1.#SNAN" and "1.#IND" + +*/ + +#ifdef _MSC_VER +# pragma warning(disable : 4702) +#endif + +#include <boost/math/special_functions/nonfinite_num_facets.hpp> +using boost::math::nonfinite_num_get; +using boost::math::nonfinite_num_put; + +#include <iostream> +using std::cout; +using std::endl; + +#include <locale> +using std::locale; + +#include <string> +using std::string; + +#include <sstream> + using std::stringstream; + using std::istringstream; + +#include <limits> +using std::numeric_limits; + +int main() +{ + if((std::numeric_limits<double>::has_infinity == false) || (std::numeric_limits<double>::infinity() == 0)) + { + std::cout << "Infinity not supported on this platform." << std::endl; + return 0; + } + + if((std::numeric_limits<double>::has_quiet_NaN == false) || (std::numeric_limits<double>::quiet_NaN() == 0)) + { + std::cout << "NaN not supported on this platform." << std::endl; + return 0; + } + + locale default_locale; // Current global locale. + // Try to use the default locale first. + // On MSVC this doesn't work. + + { // Try Quiet NaN + stringstream ss; // Both input and output. + ss.imbue(default_locale); // Redundant, of course. + string infs; + if(numeric_limits<double>::has_quiet_NaN) + { // Make sure quiet NaN is specialised for type double. + double qnan = numeric_limits<double>::quiet_NaN(); + ss << qnan; // Output quiet_NaN. + infs = ss.str(); // + } + else + { // Need to provide a suitable string for quiet NaN. + infs = "1.#QNAN"; + ss << infs; + } + double r; + ss >> r; // Read back in. + + cout << "quiet_NaN output was " << infs << endl; // "1.#QNAN" + cout << "quiet_NaN input was " << r << endl; // "1" + } + +#if (!defined __BORLANDC__ && !defined __CODEGEARC__) + // These compilers trap when trying to create a signaling_NaN! + { // Try Signaling NaN + stringstream ss; // Both input and output. + ss.imbue(default_locale); // Redundant, of course. + string infs; + if(numeric_limits<double>::has_signaling_NaN) + { // Make sure signaling NaN is specialised for type double. + double qnan = numeric_limits<double>::signaling_NaN(); + ss << qnan; // Output signaling_NaN. + infs = ss.str(); // + } + else + { // Need to provide a suitable string for signaling NaN. + infs = "1.#SNAN"; + ss << infs; + } + double r; + ss >> r; // Read back in. + + cout << "signaling_NaN output was " << infs << endl; // "1.#QNAN" (or "1.#SNAN"?) + cout << "signaling_NaN input was " << r << endl; // "1" + } +#endif // Not Borland or CodeGear. + + // Create legacy_locale and store the nonfinite_num_get facet (with legacy flag) in it. + locale legacy_locale(default_locale, new nonfinite_num_get<char>(boost::math::legacy)); + // Note that the legacy flag has no effect on the nonfinite_num_put output facet. + + cout << "Use legacy locale." << endl; + + { // Try infinity. + stringstream ss; // Both input and output. + ss.imbue(legacy_locale); + string infs; + if(numeric_limits<double>::has_infinity) + { // Make sure infinity is specialised for type double. + double inf = numeric_limits<double>::infinity(); + ss << inf; // Output infinity. + infs = ss.str(); // + } + else + { // Need to provide a suitable string for infinity. + infs = "1.#INF"; + ss << infs; + } + double r; + ss >> r; // Read back in. + + cout << "infinity output was " << infs << endl; // "1.#INF" + cout << "infinity input was " << r << endl; // "1.#INF" + } + + { // Try input of "1.#SNAN". + //double inf = numeric_limits<double>::signaling_NaN(); // Assigns "1.#QNAN" on MSVC. + // So must use explicit string "1.#SNAN" instead. + stringstream ss; // Both input and output. + ss.imbue(legacy_locale); + string s = "1.#SNAN"; + + ss << s; // Write out. + double r; + + ss >> r; // Read back in. + + cout << "SNAN output was " << s << endl; // "1.#SNAN" + cout << "SNAN input was " << r << endl; // "1.#QNAN" + } + + { // Try input of "1.#IND" . + stringstream ss; // Both input and output. + ss.imbue(legacy_locale); + string s = "1.#IND"; + ss << s; // Write out. + double r; + ss >> r; // Read back in. + + cout << "IND output was " << s << endl; // "1.#IND" + cout << "IND input was " << r << endl; // "1.#QNAN" + } + +} // int main() + +/* + +Output: + nonfinite_signaling_NaN.vcxproj -> J:\Cpp\fp_facet\fp_facet\Debug\nonfinite_signaling_NaN.exe + + quiet_NaN output was 1.#QNAN + quiet_NaN input was 1 + signaling_NaN output was 1.#QNAN + signaling_NaN input was 1 + Use legacy locale. + infinity output was 1.#INF + infinity input was 1.#INF + SNAN output was 1.#SNAN + SNAN input was 1.#QNAN + IND output was 1.#IND + IND input was 1.#QNAN + + +*/ + diff --git a/src/boost/libs/math/example/normal_misc_examples.cpp b/src/boost/libs/math/example/normal_misc_examples.cpp new file mode 100644 index 000000000..3d0f3acff --- /dev/null +++ b/src/boost/libs/math/example/normal_misc_examples.cpp @@ -0,0 +1,509 @@ +// normal_misc_examples.cpp + +// Copyright Paul A. Bristow 2007, 2010. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Example of using normal distribution. + +// Note that this file contains Quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +//[normal_basic1 +/*` +First we need some includes to access the normal distribution +(and some std output of course). +*/ + +#include <boost/math/distributions/normal.hpp> // for normal_distribution + using boost::math::normal; // typedef provides default type is double. + +#include <iostream> + using std::cout; using std::endl; using std::left; using std::showpoint; using std::noshowpoint; +#include <iomanip> + using std::setw; using std::setprecision; +#include <limits> + using std::numeric_limits; + +int main() +{ + cout << "Example: Normal distribution, Miscellaneous Applications."; + + try + { + { // Traditional tables and values. +/*`Let's start by printing some traditional tables. +*/ + double step = 1.; // in z + double range = 4; // min and max z = -range to +range. + int precision = 17; // traditional tables are only computed to much lower precision. + // but std::numeric_limits<double>::max_digits10; on new Standard Libraries gives + // 17, the maximum number of digits that can possibly be significant. + // std::numeric_limits<double>::digits10; == 15 is number of guaranteed digits, + // the other two digits being 'noisy'. + + // Construct a standard normal distribution s + normal s; // (default mean = zero, and standard deviation = unity) + cout << "Standard normal distribution, mean = "<< s.mean() + << ", standard deviation = " << s.standard_deviation() << endl; + +/*` First the probability distribution function (pdf). +*/ + cout << "Probability distribution function values" << endl; + cout << " z " " pdf " << endl; + cout.precision(5); + for (double z = -range; z < range + step; z += step) + { + cout << left << setprecision(3) << setw(6) << z << " " + << setprecision(precision) << setw(12) << pdf(s, z) << endl; + } + cout.precision(6); // default + /*`And the area under the normal curve from -[infin] up to z, + the cumulative distribution function (cdf). +*/ + // For a standard normal distribution + cout << "Standard normal mean = "<< s.mean() + << ", standard deviation = " << s.standard_deviation() << endl; + cout << "Integral (area under the curve) from - infinity up to z " << endl; + cout << " z " " cdf " << endl; + for (double z = -range; z < range + step; z += step) + { + cout << left << setprecision(3) << setw(6) << z << " " + << setprecision(precision) << setw(12) << cdf(s, z) << endl; + } + cout.precision(6); // default + +/*`And all this you can do with a nanoscopic amount of work compared to +the team of *human computers* toiling with Milton Abramovitz and Irene Stegen +at the US National Bureau of Standards (now [@http://www.nist.gov NIST]). +Starting in 1938, their "Handbook of Mathematical Functions with Formulas, Graphs and Mathematical Tables", +was eventually published in 1964, and has been reprinted numerous times since. +(A major replacement is planned at [@http://dlmf.nist.gov Digital Library of Mathematical Functions]). + +Pretty-printing a traditional 2-dimensional table is left as an exercise for the student, +but why bother now that the Math Toolkit lets you write +*/ + double z = 2.; + cout << "Area for z = " << z << " is " << cdf(s, z) << endl; // to get the area for z. +/*` +Correspondingly, we can obtain the traditional 'critical' values for significance levels. +For the 95% confidence level, the significance level usually called alpha, +is 0.05 = 1 - 0.95 (for a one-sided test), so we can write +*/ + cout << "95% of area has a z below " << quantile(s, 0.95) << endl; + // 95% of area has a z below 1.64485 +/*`and a two-sided test (a comparison between two levels, rather than a one-sided test) + +*/ + cout << "95% of area has a z between " << quantile(s, 0.975) + << " and " << -quantile(s, 0.975) << endl; + // 95% of area has a z between 1.95996 and -1.95996 +/*` + +First, define a table of significance levels: these are the probabilities +that the true occurrence frequency lies outside the calculated interval. + +It is convenient to have an alpha level for the probability that z lies outside just one standard deviation. +This will not be some nice neat number like 0.05, but we can easily calculate it, +*/ + double alpha1 = cdf(s, -1) * 2; // 0.3173105078629142 + cout << setprecision(17) << "Significance level for z == 1 is " << alpha1 << endl; +/*` + and place in our array of favorite alpha values. +*/ + double alpha[] = {0.3173105078629142, // z for 1 standard deviation. + 0.20, 0.1, 0.05, 0.01, 0.001, 0.0001, 0.00001 }; +/*` + +Confidence value as % is (1 - alpha) * 100 (so alpha 0.05 == 95% confidence) +that the true occurrence frequency lies *inside* the calculated interval. + +*/ + cout << "level of significance (alpha)" << setprecision(4) << endl; + cout << "2-sided 1 -sided z(alpha) " << endl; + for (unsigned i = 0; i < sizeof(alpha)/sizeof(alpha[0]); ++i) + { + cout << setw(15) << alpha[i] << setw(15) << alpha[i] /2 << setw(10) << quantile(complement(s, alpha[i]/2)) << endl; + // Use quantile(complement(s, alpha[i]/2)) to avoid potential loss of accuracy from quantile(s, 1 - alpha[i]/2) + } + cout << endl; + +/*`Notice the distinction between one-sided (also called one-tailed) +where we are using a > *or* < test (and not both) +and considering the area of the tail (integral) from z up to +[infin], +and a two-sided test where we are using two > *and* < tests, and thus considering two tails, +from -[infin] up to z low and z high up to +[infin]. + +So the 2-sided values alpha[i] are calculated using alpha[i]/2. + +If we consider a simple example of alpha = 0.05, then for a two-sided test, +the lower tail area from -[infin] up to -1.96 is 0.025 (alpha/2) +and the upper tail area from +z up to +1.96 is also 0.025 (alpha/2), +and the area between -1.96 up to 12.96 is alpha = 0.95. +and the sum of the two tails is 0.025 + 0.025 = 0.05, + +*/ +//] [/[normal_basic1] + +//[normal_basic2 + +/*`Armed with the cumulative distribution function, we can easily calculate the +easy to remember proportion of values that lie within 1, 2 and 3 standard deviations from the mean. + +*/ + cout.precision(3); + cout << showpoint << "cdf(s, s.standard_deviation()) = " + << cdf(s, s.standard_deviation()) << endl; // from -infinity to 1 sd + cout << "cdf(complement(s, s.standard_deviation())) = " + << cdf(complement(s, s.standard_deviation())) << endl; + cout << "Fraction 1 standard deviation within either side of mean is " + << 1 - cdf(complement(s, s.standard_deviation())) * 2 << endl; + cout << "Fraction 2 standard deviations within either side of mean is " + << 1 - cdf(complement(s, 2 * s.standard_deviation())) * 2 << endl; + cout << "Fraction 3 standard deviations within either side of mean is " + << 1 - cdf(complement(s, 3 * s.standard_deviation())) * 2 << endl; + +/*` +To a useful precision, the 1, 2 & 3 percentages are 68, 95 and 99.7, +and these are worth memorising as useful 'rules of thumb', as, for example, in +[@http://en.wikipedia.org/wiki/Standard_deviation standard deviation]: + +[pre +Fraction 1 standard deviation within either side of mean is 0.683 +Fraction 2 standard deviations within either side of mean is 0.954 +Fraction 3 standard deviations within either side of mean is 0.997 +] + +We could of course get some really accurate values for these +[@http://en.wikipedia.org/wiki/Confidence_interval confidence intervals] +by using cout.precision(15); + +[pre +Fraction 1 standard deviation within either side of mean is 0.682689492137086 +Fraction 2 standard deviations within either side of mean is 0.954499736103642 +Fraction 3 standard deviations within either side of mean is 0.997300203936740 +] + +But before you get too excited about this impressive precision, +don't forget that the *confidence intervals of the standard deviation* are surprisingly wide, +especially if you have estimated the standard deviation from only a few measurements. +*/ +//] [/[normal_basic2] + + +//[normal_bulbs_example1 +/*` +Examples from K. Krishnamoorthy, Handbook of Statistical Distributions with Applications, +ISBN 1 58488 635 8, page 125... implemented using the Math Toolkit library. + +A few very simple examples are shown here: +*/ +// K. Krishnamoorthy, Handbook of Statistical Distributions with Applications, + // ISBN 1 58488 635 8, page 125, example 10.3.5 +/*`Mean lifespan of 100 W bulbs is 1100 h with standard deviation of 100 h. +Assuming, perhaps with little evidence and much faith, that the distribution is normal, +we construct a normal distribution called /bulbs/ with these values: +*/ + double mean_life = 1100.; + double life_standard_deviation = 100.; + normal bulbs(mean_life, life_standard_deviation); + double expected_life = 1000.; + +/*`The we can use the Cumulative distribution function to predict fractions +(or percentages, if * 100) that will last various lifetimes. +*/ + cout << "Fraction of bulbs that will last at best (<=) " // P(X <= 1000) + << expected_life << " is "<< cdf(bulbs, expected_life) << endl; + cout << "Fraction of bulbs that will last at least (>) " // P(X > 1000) + << expected_life << " is "<< cdf(complement(bulbs, expected_life)) << endl; + double min_life = 900; + double max_life = 1200; + cout << "Fraction of bulbs that will last between " + << min_life << " and " << max_life << " is " + << cdf(bulbs, max_life) // P(X <= 1200) + - cdf(bulbs, min_life) << endl; // P(X <= 900) +/*` +[note Real-life failures are often very ab-normal, +with a significant number that 'dead-on-arrival' or suffer failure very early in their life: +the lifetime of the survivors of 'early mortality' may be well described by the normal distribution.] +*/ +//] [/normal_bulbs_example1 Quickbook end] + } + { + // K. Krishnamoorthy, Handbook of Statistical Distributions with Applications, + // ISBN 1 58488 635 8, page 125, Example 10.3.6 + +//[normal_bulbs_example3 +/*`Weekly demand for 5 lb sacks of onions at a store is normally distributed with mean 140 sacks and standard deviation 10. +*/ + double mean = 140.; // sacks per week. + double standard_deviation = 10; + normal sacks(mean, standard_deviation); + + double stock = 160.; // per week. + cout << "Percentage of weeks overstocked " + << cdf(sacks, stock) * 100. << endl; // P(X <=160) + // Percentage of weeks overstocked 97.7 + +/*`So there will be lots of mouldy onions! +So we should be able to say what stock level will meet demand 95% of the weeks. +*/ + double stock_95 = quantile(sacks, 0.95); + cout << "Store should stock " << int(stock_95) << " sacks to meet 95% of demands." << endl; +/*`And it is easy to estimate how to meet 80% of demand, and waste even less. +*/ + double stock_80 = quantile(sacks, 0.80); + cout << "Store should stock " << int(stock_80) << " sacks to meet 8 out of 10 demands." << endl; +//] [/normal_bulbs_example3 Quickbook end] + } + { // K. Krishnamoorthy, Handbook of Statistical Distributions with Applications, + // ISBN 1 58488 635 8, page 125, Example 10.3.7 + +//[normal_bulbs_example4 + +/*`A machine is set to pack 3 kg of ground beef per pack. +Over a long period of time it is found that the average packed was 3 kg +with a standard deviation of 0.1 kg. +Assuming the packing is normally distributed, +we can find the fraction (or %) of packages that weigh more than 3.1 kg. +*/ + +double mean = 3.; // kg +double standard_deviation = 0.1; // kg +normal packs(mean, standard_deviation); + +double max_weight = 3.1; // kg +cout << "Percentage of packs > " << max_weight << " is " +<< cdf(complement(packs, max_weight)) << endl; // P(X > 3.1) + +double under_weight = 2.9; +cout <<"fraction of packs <= " << under_weight << " with a mean of " << mean + << " is " << cdf(complement(packs, under_weight)) << endl; +// fraction of packs <= 2.9 with a mean of 3 is 0.841345 +// This is 0.84 - more than the target 0.95 +// Want 95% to be over this weight, so what should we set the mean weight to be? +// KK StatCalc says: +double over_mean = 3.0664; +normal xpacks(over_mean, standard_deviation); +cout << "fraction of packs >= " << under_weight +<< " with a mean of " << xpacks.mean() + << " is " << cdf(complement(xpacks, under_weight)) << endl; +// fraction of packs >= 2.9 with a mean of 3.06449 is 0.950005 +double under_fraction = 0.05; // so 95% are above the minimum weight mean - sd = 2.9 +double low_limit = standard_deviation; +double offset = mean - low_limit - quantile(packs, under_fraction); +double nominal_mean = mean + offset; + +normal nominal_packs(nominal_mean, standard_deviation); +cout << "Setting the packer to " << nominal_mean << " will mean that " + << "fraction of packs >= " << under_weight + << " is " << cdf(complement(nominal_packs, under_weight)) << endl; + +/*` +Setting the packer to 3.06449 will mean that fraction of packs >= 2.9 is 0.95. + +Setting the packer to 3.13263 will mean that fraction of packs >= 2.9 is 0.99, +but will more than double the mean loss from 0.0644 to 0.133. + +Alternatively, we could invest in a better (more precise) packer with a lower standard deviation. + +To estimate how much better (how much smaller standard deviation) it would have to be, +we need to get the 5% quantile to be located at the under_weight limit, 2.9 +*/ +double p = 0.05; // wanted p th quantile. +cout << "Quantile of " << p << " = " << quantile(packs, p) + << ", mean = " << packs.mean() << ", sd = " << packs.standard_deviation() << endl; // +/*` +Quantile of 0.05 = 2.83551, mean = 3, sd = 0.1 + +With the current packer (mean = 3, sd = 0.1), the 5% quantile is at 2.8551 kg, +a little below our target of 2.9 kg. +So we know that the standard deviation is going to have to be smaller. + +Let's start by guessing that it (now 0.1) needs to be halved, to a standard deviation of 0.05 +*/ +normal pack05(mean, 0.05); +cout << "Quantile of " << p << " = " << quantile(pack05, p) + << ", mean = " << pack05.mean() << ", sd = " << pack05.standard_deviation() << endl; + +cout <<"Fraction of packs >= " << under_weight << " with a mean of " << mean + << " and standard deviation of " << pack05.standard_deviation() + << " is " << cdf(complement(pack05, under_weight)) << endl; +// +/*` +Fraction of packs >= 2.9 with a mean of 3 and standard deviation of 0.05 is 0.9772 + +So 0.05 was quite a good guess, but we are a little over the 2.9 target, +so the standard deviation could be a tiny bit more. So we could do some +more guessing to get closer, say by increasing to 0.06 +*/ + +normal pack06(mean, 0.06); +cout << "Quantile of " << p << " = " << quantile(pack06, p) + << ", mean = " << pack06.mean() << ", sd = " << pack06.standard_deviation() << endl; + +cout <<"Fraction of packs >= " << under_weight << " with a mean of " << mean + << " and standard deviation of " << pack06.standard_deviation() + << " is " << cdf(complement(pack06, under_weight)) << endl; +/*` +Fraction of packs >= 2.9 with a mean of 3 and standard deviation of 0.06 is 0.9522 + +Now we are getting really close, but to do the job properly, +we could use root finding method, for example the tools provided, and used elsewhere, +in the Math Toolkit, see __root_finding_without_derivatives. + +But in this normal distribution case, we could be even smarter and make a direct calculation. +*/ + +normal s; // For standard normal distribution, +double sd = 0.1; +double x = 2.9; // Our required limit. +// then probability p = N((x - mean) / sd) +// So if we want to find the standard deviation that would be required to meet this limit, +// so that the p th quantile is located at x, +// in this case the 0.95 (95%) quantile at 2.9 kg pack weight, when the mean is 3 kg. + +double prob = pdf(s, (x - mean) / sd); +double qp = quantile(s, 0.95); +cout << "prob = " << prob << ", quantile(p) " << qp << endl; // p = 0.241971, quantile(p) 1.64485 +// Rearranging, we can directly calculate the required standard deviation: +double sd95 = std::abs((x - mean)) / qp; + +cout << "If we want the "<< p << " th quantile to be located at " + << x << ", would need a standard deviation of " << sd95 << endl; + +normal pack95(mean, sd95); // Distribution of the 'ideal better' packer. +cout <<"Fraction of packs >= " << under_weight << " with a mean of " << mean + << " and standard deviation of " << pack95.standard_deviation() + << " is " << cdf(complement(pack95, under_weight)) << endl; + +// Fraction of packs >= 2.9 with a mean of 3 and standard deviation of 0.0608 is 0.95 + +/*`Notice that these two deceptively simple questions +(do we over-fill or measure better) are actually very common. +The weight of beef might be replaced by a measurement of more or less anything. +But the calculations rely on the accuracy of the standard deviation - something +that is almost always less good than we might wish, +especially if based on a few measurements. +*/ + +//] [/normal_bulbs_example4 Quickbook end] + } + + { // K. Krishnamoorthy, Handbook of Statistical Distributions with Applications, + // ISBN 1 58488 635 8, page 125, example 10.3.8 +//[normal_bulbs_example5 +/*`A bolt is usable if between 3.9 and 4.1 long. +From a large batch of bolts, a sample of 50 show a +mean length of 3.95 with standard deviation 0.1. +Assuming a normal distribution, what proportion is usable? +The true sample mean is unknown, +but we can use the sample mean and standard deviation to find approximate solutions. +*/ + + normal bolts(3.95, 0.1); + double top = 4.1; + double bottom = 3.9; + +cout << "Fraction long enough [ P(X <= " << top << ") ] is " << cdf(bolts, top) << endl; +cout << "Fraction too short [ P(X <= " << bottom << ") ] is " << cdf(bolts, bottom) << endl; +cout << "Fraction OK -between " << bottom << " and " << top + << "[ P(X <= " << top << ") - P(X<= " << bottom << " ) ] is " + << cdf(bolts, top) - cdf(bolts, bottom) << endl; + +cout << "Fraction too long [ P(X > " << top << ") ] is " + << cdf(complement(bolts, top)) << endl; + +cout << "95% of bolts are shorter than " << quantile(bolts, 0.95) << endl; + +//] [/normal_bulbs_example5 Quickbook end] + } + } + catch(const std::exception& e) + { // Always useful to include try & catch blocks because default policies + // are to throw exceptions on arguments that cause errors like underflow, overflow. + // Lacking try & catch blocks, the program will abort without a message below, + // which may give some helpful clues as to the cause of the exception. + std::cout << + "\n""Message from thrown exception was:\n " << e.what() << std::endl; + } + return 0; +} // int main() + + +/* + +Output is: + +Autorun "i:\boost-06-05-03-1300\libs\math\test\Math_test\debug\normal_misc_examples.exe" +Example: Normal distribution, Miscellaneous Applications.Standard normal distribution, mean = 0, standard deviation = 1 +Probability distribution function values + z pdf +-4 0.00013383022576488537 +-3 0.0044318484119380075 +-2 0.053990966513188063 +-1 0.24197072451914337 +0 0.3989422804014327 +1 0.24197072451914337 +2 0.053990966513188063 +3 0.0044318484119380075 +4 0.00013383022576488537 +Standard normal mean = 0, standard deviation = 1 +Integral (area under the curve) from - infinity up to z + z cdf +-4 3.1671241833119979e-005 +-3 0.0013498980316300959 +-2 0.022750131948179219 +-1 0.1586552539314571 +0 0.5 +1 0.84134474606854293 +2 0.97724986805182079 +3 0.9986501019683699 +4 0.99996832875816688 +Area for z = 2 is 0.97725 +95% of area has a z below 1.64485 +95% of area has a z between 1.95996 and -1.95996 +Significance level for z == 1 is 0.3173105078629142 +level of significance (alpha) +2-sided 1 -sided z(alpha) +0.3173 0.1587 1 +0.2 0.1 1.282 +0.1 0.05 1.645 +0.05 0.025 1.96 +0.01 0.005 2.576 +0.001 0.0005 3.291 +0.0001 5e-005 3.891 +1e-005 5e-006 4.417 +cdf(s, s.standard_deviation()) = 0.841 +cdf(complement(s, s.standard_deviation())) = 0.159 +Fraction 1 standard deviation within either side of mean is 0.683 +Fraction 2 standard deviations within either side of mean is 0.954 +Fraction 3 standard deviations within either side of mean is 0.997 +Fraction of bulbs that will last at best (<=) 1.00e+003 is 0.159 +Fraction of bulbs that will last at least (>) 1.00e+003 is 0.841 +Fraction of bulbs that will last between 900. and 1.20e+003 is 0.819 +Percentage of weeks overstocked 97.7 +Store should stock 156 sacks to meet 95% of demands. +Store should stock 148 sacks to meet 8 out of 10 demands. +Percentage of packs > 3.10 is 0.159 +fraction of packs <= 2.90 with a mean of 3.00 is 0.841 +fraction of packs >= 2.90 with a mean of 3.07 is 0.952 +Setting the packer to 3.06 will mean that fraction of packs >= 2.90 is 0.950 +Quantile of 0.0500 = 2.84, mean = 3.00, sd = 0.100 +Quantile of 0.0500 = 2.92, mean = 3.00, sd = 0.0500 +Fraction of packs >= 2.90 with a mean of 3.00 and standard deviation of 0.0500 is 0.977 +Quantile of 0.0500 = 2.90, mean = 3.00, sd = 0.0600 +Fraction of packs >= 2.90 with a mean of 3.00 and standard deviation of 0.0600 is 0.952 +prob = 0.242, quantile(p) 1.64 +If we want the 0.0500 th quantile to be located at 2.90, would need a standard deviation of 0.0608 +Fraction of packs >= 2.90 with a mean of 3.00 and standard deviation of 0.0608 is 0.950 +Fraction long enough [ P(X <= 4.10) ] is 0.933 +Fraction too short [ P(X <= 3.90) ] is 0.309 +Fraction OK -between 3.90 and 4.10[ P(X <= 4.10) - P(X<= 3.90 ) ] is 0.625 +Fraction too long [ P(X > 4.10) ] is 0.0668 +95% of bolts are shorter than 4.11 + +*/ diff --git a/src/boost/libs/math/example/normal_tables.cpp b/src/boost/libs/math/example/normal_tables.cpp new file mode 100644 index 000000000..e130f5fd4 --- /dev/null +++ b/src/boost/libs/math/example/normal_tables.cpp @@ -0,0 +1,566 @@ + +// normal_misc_examples.cpp + +// Copyright Paul A. Bristow 2007, 2010, 2014, 2016. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Example of using normal distribution. + +// Note that this file contains Quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +/*` +First we need some includes to access the normal distribution +(and some std output of course). +*/ + +#include <boost/cstdfloat.hpp> // MUST be first include!!! +// See Implementation of Float128 type, Overloading template functions with float128_t. + +#include <boost/math/distributions/normal.hpp> // for normal_distribution. + using boost::math::normal; // typedef provides default type of double. + +#include <iostream> + //using std::cout; using std::endl; + //using std::left; using std::showpoint; using std::noshowpoint; +#include <iomanip> + //using std::setw; using std::setprecision; +#include <limits> + //using std::numeric_limits; + + /*! +Function max_digits10 +Returns maximum number of possibly significant decimal digits for a floating-point type FPT, +even for older compilers/standard libraries that +lack support for std::std::numeric_limits<FPT>::max_digits10, +when the Kahan formula 2 + binary_digits * 0.3010 is used instead. +Also provides the correct result for Visual Studio 2010 where the max_digits10 provided for float is wrong. +*/ +namespace boost +{ +namespace math +{ +template <typename FPT> +int max_digits10() +{ +// Since max_digits10 is not defined (or wrong) on older systems, define a local max_digits10. + + // Usage: int m = max_digits10<boost::float64_t>(); + const int m = +#if (defined BOOST_NO_CXX11_NUMERIC_LIMITS) || (_MSC_VER == 1600) // is wrongly 8 not 9 for VS2010. + 2 + std::numeric_limits<FPT>::digits * 3010/10000; +#else + std::numeric_limits<FPT>::max_digits10; +#endif + return m; +} +} // namespace math +} // namespace boost + +template <typename FPT> +void normal_table() +{ + using namespace boost::math; + + FPT step = static_cast<FPT>(1.); // step in z. + FPT range = static_cast<FPT>(10.); // min and max z = -range to +range. + + // Traditional tables are only computed to much lower precision. + // but @c std::std::numeric_limits<double>::max_digits10; + // on new Standard Libraries gives 17, + // the maximum number of digits from 64-bit double that can possibly be significant. + // @c std::std::numeric_limits<double>::digits10; == 15 + // is number of @b guaranteed digits, the other two digits being 'noisy'. + // Here we use a custom version of max_digits10 which deals with those platforms + // where @c std::numeric_limits is not specialized, + // or @c std::numeric_limits<>::max_digits10 not implemented, or wrong. + int precision = boost::math::max_digits10<FPT>(); + +// std::cout << typeid(FPT).name() << std::endl; +// demo_normal.cpp:85: undefined reference to `typeinfo for __float128' +// [@http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43622 GCC 43622] +// typeinfo for __float128 was missing GCC 4.9 Mar 2014, but OK for GCC 6.1.1. + + // Construct a standard normal distribution s, with + // (default mean = zero, and standard deviation = unity) + normal s; + std::cout << "\nStandard normal distribution, mean = "<< s.mean() + << ", standard deviation = " << s.standard_deviation() << std::endl; + + std::cout << "maxdigits_10 is " << precision + << ", digits10 is " << std::numeric_limits<FPT>::digits10 << std::endl; + + std::cout << "Probability distribution function values" << std::endl; + + std::cout << " z " " PDF " << std::endl; + for (FPT z = -range; z < range + step; z += step) + { + std::cout << std::left << std::setprecision(3) << std::setw(6) << z << " " + << std::setprecision(precision) << std::setw(12) << pdf(s, z) << std::endl; + } + std::cout.precision(6); // Restore to default precision. + +/*`And the area under the normal curve from -[infin] up to z, + the cumulative distribution function (CDF). +*/ + // For a standard normal distribution: + std::cout << "Standard normal mean = "<< s.mean() + << ", standard deviation = " << s.standard_deviation() << std::endl; + std::cout << "Integral (area under the curve) from - infinity up to z." << std::endl; + std::cout << " z " " CDF " << std::endl; + for (FPT z = -range; z < range + step; z += step) + { + std::cout << std::left << std::setprecision(3) << std::setw(6) << z << " " + << std::setprecision(precision) << std::setw(12) << cdf(s, z) << std::endl; + } + std::cout.precision(6); // Reset to default precision. +} // template <typename FPT> void normal_table() + +int main() +{ + std::cout << "\nExample: Normal distribution tables." << std::endl; + + using namespace boost::math; + + try + {// Tip - always use try'n'catch blocks to ensure that messages from thrown exceptions are shown. + +//[normal_table_1 +#ifdef BOOST_FLOAT32_C + normal_table<boost::float32_t>(); // Usually type float +#endif + normal_table<boost::float64_t>(); // Usually type double. Assume that float64_t is always available. +#ifdef BOOST_FLOAT80_C + normal_table<boost::float80_t>(); // Type long double on some X86 platforms. +#endif +#ifdef BOOST_FLOAT128_C + normal_table<boost::float128_t>(); // Type _Quad on some Intel and __float128 on some GCC platforms. +#endif + normal_table<boost::floatmax_t>(); +//] [/normal_table_1 ] + } + catch(std::exception ex) + { + std::cout << "exception thrown " << ex.what() << std::endl; + } + + return 0; +} // int main() + + +/* + +GCC 4.8.1 with quadmath + +Example: Normal distribution tables. + +Standard normal distribution, mean = 0, standard deviation = 1 +maxdigits_10 is 9, digits10 is 6 +Probability distribution function values + z PDF +-10 7.69459863e-023 +-9 1.02797736e-018 +-8 5.05227108e-015 +-7 9.13472041e-012 +-6 6.07588285e-009 +-5 1.48671951e-006 +-4 0.000133830226 +-3 0.00443184841 +-2 0.0539909665 +-1 0.241970725 +0 0.39894228 +1 0.241970725 +2 0.0539909665 +3 0.00443184841 +4 0.000133830226 +5 1.48671951e-006 +6 6.07588285e-009 +7 9.13472041e-012 +8 5.05227108e-015 +9 1.02797736e-018 +10 7.69459863e-023 +Standard normal mean = 0, standard deviation = 1 +Integral (area under the curve) from - infinity up to z. + z CDF +-10 7.61985302e-024 +-9 1.12858841e-019 +-8 6.22096057e-016 +-7 1.27981254e-012 +-6 9.86587645e-010 +-5 2.86651572e-007 +-4 3.16712418e-005 +-3 0.00134989803 +-2 0.0227501319 +-1 0.158655254 +0 0.5 +1 0.841344746 +2 0.977249868 +3 0.998650102 +4 0.999968329 +5 0.999999713 +6 0.999999999 +7 1 +8 1 +9 1 +10 1 + +Standard normal distribution, mean = 0, standard deviation = 1 +maxdigits_10 is 17, digits10 is 15 +Probability distribution function values + z PDF +-10 7.6945986267064199e-023 +-9 1.0279773571668917e-018 +-8 5.0522710835368927e-015 +-7 9.1347204083645953e-012 +-6 6.0758828498232861e-009 +-5 1.4867195147342979e-006 +-4 0.00013383022576488537 +-3 0.0044318484119380075 +-2 0.053990966513188063 +-1 0.24197072451914337 +0 0.3989422804014327 +1 0.24197072451914337 +2 0.053990966513188063 +3 0.0044318484119380075 +4 0.00013383022576488537 +5 1.4867195147342979e-006 +6 6.0758828498232861e-009 +7 9.1347204083645953e-012 +8 5.0522710835368927e-015 +9 1.0279773571668917e-018 +10 7.6945986267064199e-023 +Standard normal mean = 0, standard deviation = 1 +Integral (area under the curve) from - infinity up to z. + z CDF +-10 7.6198530241605945e-024 +-9 1.1285884059538422e-019 +-8 6.2209605742718204e-016 +-7 1.279812543885835e-012 +-6 9.865876450377014e-010 +-5 2.8665157187919455e-007 +-4 3.1671241833119972e-005 +-3 0.0013498980316300957 +-2 0.022750131948179216 +-1 0.15865525393145705 +0 0.5 +1 0.84134474606854293 +2 0.97724986805182079 +3 0.9986501019683699 +4 0.99996832875816688 +5 0.99999971334842808 +6 0.9999999990134123 +7 0.99999999999872013 +8 0.99999999999999933 +9 1 +10 1 + +Standard normal distribution, mean = 0, standard deviation = 1 +maxdigits_10 is 21, digits10 is 18 +Probability distribution function values + z PDF +-10 7.69459862670641993759e-023 +-9 1.0279773571668916523e-018 +-8 5.05227108353689273243e-015 +-7 9.13472040836459525705e-012 +-6 6.07588284982328608733e-009 +-5 1.48671951473429788965e-006 +-4 0.00013383022576488536764 +-3 0.00443184841193800752729 +-2 0.0539909665131880628364 +-1 0.241970724519143365328 +0 0.398942280401432702863 +1 0.241970724519143365328 +2 0.0539909665131880628364 +3 0.00443184841193800752729 +4 0.00013383022576488536764 +5 1.48671951473429788965e-006 +6 6.07588284982328608733e-009 +7 9.13472040836459525705e-012 +8 5.05227108353689273243e-015 +9 1.0279773571668916523e-018 +10 7.69459862670641993759e-023 +Standard normal mean = 0, standard deviation = 1 +Integral (area under the curve) from - infinity up to z. + z CDF +-10 7.61985302416059451083e-024 +-9 1.12858840595384222719e-019 +-8 6.22096057427182035917e-016 +-7 1.279812543885834962e-012 +-6 9.86587645037701399241e-010 +-5 2.86651571879194547129e-007 +-4 3.16712418331199717608e-005 +-3 0.00134989803163009566139 +-2 0.0227501319481792155242 +-1 0.158655253931457046468 +0 0.5 +1 0.841344746068542925777 +2 0.977249868051820791415 +3 0.998650101968369896532 +4 0.999968328758166880021 +5 0.999999713348428076465 +6 0.999999999013412299576 +7 0.999999999998720134897 +8 0.999999999999999333866 +9 1 +10 1 + +Standard normal distribution, mean = 0, standard deviation = 1 +maxdigits_10 is 36, digits10 is 34 +Probability distribution function values + z PDF +-10 7.69459862670641993759264402330435296e-023 +-9 1.02797735716689165230378750485667109e-018 +-8 5.0522710835368927324337437844893081e-015 +-7 9.13472040836459525705208369548147081e-012 +-6 6.07588284982328608733411870229841611e-009 +-5 1.48671951473429788965346931561839483e-006 +-4 0.00013383022576488536764006964663309418 +-3 0.00443184841193800752728870762098267733 +-2 0.0539909665131880628363703067407186609 +-1 0.241970724519143365327522587904240936 +0 0.398942280401432702863218082711682655 +1 0.241970724519143365327522587904240936 +2 0.0539909665131880628363703067407186609 +3 0.00443184841193800752728870762098267733 +4 0.00013383022576488536764006964663309418 +5 1.48671951473429788965346931561839483e-006 +6 6.07588284982328608733411870229841611e-009 +7 9.13472040836459525705208369548147081e-012 +8 5.0522710835368927324337437844893081e-015 +9 1.02797735716689165230378750485667109e-018 +10 7.69459862670641993759264402330435296e-023 +Standard normal mean = 0, standard deviation = 1 +Integral (area under the curve) from - infinity up to z. + z CDF +-10 7.61985302416059451083278826816793623e-024 +-9 1.1285884059538422271881384555435713e-019 +-8 6.22096057427182035917417257601387863e-016 +-7 1.27981254388583496200054074948511201e-012 +-6 9.86587645037701399241244820583623953e-010 +-5 2.86651571879194547128505464808623238e-007 +-4 3.16712418331199717608064048146587766e-005 +-3 0.001349898031630095661392854111682027 +-2 0.0227501319481792155241528519127314212 +-1 0.158655253931457046467912164189328905 +0 0.5 +1 0.841344746068542925776512220181757584 +2 0.977249868051820791414741051994496956 +3 0.998650101968369896532351503992686048 +4 0.999968328758166880021462930017150939 +5 0.999999713348428076464813329948810861 +6 0.999999999013412299575520592043176293 +7 0.999999999998720134897212119540199637 +8 0.999999999999999333866185224906075746 +9 1 +10 1 + +Standard normal distribution, mean = 0, standard deviation = 1 +maxdigits_10 is 36, digits10 is 34 +Probability distribution function values + z PDF +-10 7.69459862670641993759264402330435296e-023 +-9 1.02797735716689165230378750485667109e-018 +-8 5.0522710835368927324337437844893081e-015 +-7 9.13472040836459525705208369548147081e-012 +-6 6.07588284982328608733411870229841611e-009 +-5 1.48671951473429788965346931561839483e-006 +-4 0.00013383022576488536764006964663309418 +-3 0.00443184841193800752728870762098267733 +-2 0.0539909665131880628363703067407186609 +-1 0.241970724519143365327522587904240936 +0 0.398942280401432702863218082711682655 +1 0.241970724519143365327522587904240936 +2 0.0539909665131880628363703067407186609 +3 0.00443184841193800752728870762098267733 +4 0.00013383022576488536764006964663309418 +5 1.48671951473429788965346931561839483e-006 +6 6.07588284982328608733411870229841611e-009 +7 9.13472040836459525705208369548147081e-012 +8 5.0522710835368927324337437844893081e-015 +9 1.02797735716689165230378750485667109e-018 +10 7.69459862670641993759264402330435296e-023 +Standard normal mean = 0, standard deviation = 1 +Integral (area under the curve) from - infinity up to z. + z CDF +-10 7.61985302416059451083278826816793623e-024 +-9 1.1285884059538422271881384555435713e-019 +-8 6.22096057427182035917417257601387863e-016 +-7 1.27981254388583496200054074948511201e-012 +-6 9.86587645037701399241244820583623953e-010 +-5 2.86651571879194547128505464808623238e-007 +-4 3.16712418331199717608064048146587766e-005 +-3 0.001349898031630095661392854111682027 +-2 0.0227501319481792155241528519127314212 +-1 0.158655253931457046467912164189328905 +0 0.5 +1 0.841344746068542925776512220181757584 +2 0.977249868051820791414741051994496956 +3 0.998650101968369896532351503992686048 +4 0.999968328758166880021462930017150939 +5 0.999999713348428076464813329948810861 +6 0.999999999013412299575520592043176293 +7 0.999999999998720134897212119540199637 +8 0.999999999999999333866185224906075746 +9 1 +10 1 + +MSVC 2013 64-bit +1> +1> Example: Normal distribution tables. +1> +1> Standard normal distribution, mean = 0, standard deviation = 1 +1> maxdigits_10 is 9, digits10 is 6 +1> Probability distribution function values +1> z PDF +1> -10 7.69459863e-023 +1> -9 1.02797736e-018 +1> -8 5.05227108e-015 +1> -7 9.13472041e-012 +1> -6 6.07588285e-009 +1> -5 1.48671951e-006 +1> -4 0.000133830226 +1> -3 0.00443184841 +1> -2 0.0539909665 +1> -1 0.241970725 +1> 0 0.39894228 +1> 1 0.241970725 +1> 2 0.0539909665 +1> 3 0.00443184841 +1> 4 0.000133830226 +1> 5 1.48671951e-006 +1> 6 6.07588285e-009 +1> 7 9.13472041e-012 +1> 8 5.05227108e-015 +1> 9 1.02797736e-018 +1> 10 7.69459863e-023 +1> Standard normal mean = 0, standard deviation = 1 +1> Integral (area under the curve) from - infinity up to z. +1> z CDF +1> -10 7.61985302e-024 +1> -9 1.12858841e-019 +1> -8 6.22096057e-016 +1> -7 1.27981254e-012 +1> -6 9.86587645e-010 +1> -5 2.86651572e-007 +1> -4 3.16712418e-005 +1> -3 0.00134989803 +1> -2 0.0227501319 +1> -1 0.158655254 +1> 0 0.5 +1> 1 0.841344746 +1> 2 0.977249868 +1> 3 0.998650102 +1> 4 0.999968329 +1> 5 0.999999713 +1> 6 0.999999999 +1> 7 1 +1> 8 1 +1> 9 1 +1> 10 1 +1> +1> Standard normal distribution, mean = 0, standard deviation = 1 +1> maxdigits_10 is 17, digits10 is 15 +1> Probability distribution function values +1> z PDF +1> -10 7.6945986267064199e-023 +1> -9 1.0279773571668917e-018 +1> -8 5.0522710835368927e-015 +1> -7 9.1347204083645953e-012 +1> -6 6.0758828498232861e-009 +1> -5 1.4867195147342979e-006 +1> -4 0.00013383022576488537 +1> -3 0.0044318484119380075 +1> -2 0.053990966513188063 +1> -1 0.24197072451914337 +1> 0 0.3989422804014327 +1> 1 0.24197072451914337 +1> 2 0.053990966513188063 +1> 3 0.0044318484119380075 +1> 4 0.00013383022576488537 +1> 5 1.4867195147342979e-006 +1> 6 6.0758828498232861e-009 +1> 7 9.1347204083645953e-012 +1> 8 5.0522710835368927e-015 +1> 9 1.0279773571668917e-018 +1> 10 7.6945986267064199e-023 +1> Standard normal mean = 0, standard deviation = 1 +1> Integral (area under the curve) from - infinity up to z. +1> z CDF +1> -10 7.6198530241605813e-024 +1> -9 1.1285884059538408e-019 +1> -8 6.2209605742718292e-016 +1> -7 1.2798125438858352e-012 +1> -6 9.8658764503770161e-010 +1> -5 2.8665157187919439e-007 +1> -4 3.1671241833119979e-005 +1> -3 0.0013498980316300957 +1> -2 0.022750131948179219 +1> -1 0.15865525393145707 +1> 0 0.5 +1> 1 0.84134474606854293 +1> 2 0.97724986805182079 +1> 3 0.9986501019683699 +1> 4 0.99996832875816688 +1> 5 0.99999971334842808 +1> 6 0.9999999990134123 +1> 7 0.99999999999872013 +1> 8 0.99999999999999933 +1> 9 1 +1> 10 1 +1> +1> Standard normal distribution, mean = 0, standard deviation = 1 +1> maxdigits_10 is 17, digits10 is 15 +1> Probability distribution function values +1> z PDF +1> -10 7.6945986267064199e-023 +1> -9 1.0279773571668917e-018 +1> -8 5.0522710835368927e-015 +1> -7 9.1347204083645953e-012 +1> -6 6.0758828498232861e-009 +1> -5 1.4867195147342979e-006 +1> -4 0.00013383022576488537 +1> -3 0.0044318484119380075 +1> -2 0.053990966513188063 +1> -1 0.24197072451914337 +1> 0 0.3989422804014327 +1> 1 0.24197072451914337 +1> 2 0.053990966513188063 +1> 3 0.0044318484119380075 +1> 4 0.00013383022576488537 +1> 5 1.4867195147342979e-006 +1> 6 6.0758828498232861e-009 +1> 7 9.1347204083645953e-012 +1> 8 5.0522710835368927e-015 +1> 9 1.0279773571668917e-018 +1> 10 7.6945986267064199e-023 +1> Standard normal mean = 0, standard deviation = 1 +1> Integral (area under the curve) from - infinity up to z. +1> z CDF +1> -10 7.6198530241605813e-024 +1> -9 1.1285884059538408e-019 +1> -8 6.2209605742718292e-016 +1> -7 1.2798125438858352e-012 +1> -6 9.8658764503770161e-010 +1> -5 2.8665157187919439e-007 +1> -4 3.1671241833119979e-005 +1> -3 0.0013498980316300957 +1> -2 0.022750131948179219 +1> -1 0.15865525393145707 +1> 0 0.5 +1> 1 0.84134474606854293 +1> 2 0.97724986805182079 +1> 3 0.9986501019683699 +1> 4 0.99996832875816688 +1> 5 0.99999971334842808 +1> 6 0.9999999990134123 +1> 7 0.99999999999872013 +1> 8 0.99999999999999933 +1> 9 1 +1> 10 1 + + +*/ diff --git a/src/boost/libs/math/example/numerical_derivative_example.cpp b/src/boost/libs/math/example/numerical_derivative_example.cpp new file mode 100644 index 000000000..214ed498e --- /dev/null +++ b/src/boost/libs/math/example/numerical_derivative_example.cpp @@ -0,0 +1,209 @@ +// Copyright Christopher Kormanyos 2013. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http://www.boost.org/LICENSE_1_0.txt). + +#ifdef _MSC_VER +# pragma warning (disable : 4996) // assignment operator could not be generated. +#endif + +# include <iostream> +# include <iomanip> +# include <limits> +# include <cmath> + +#include <boost/static_assert.hpp> +#include <boost/type_traits/is_floating_point.hpp> +#include <boost/math/special_functions/next.hpp> // for float_distance + +//[numeric_derivative_example +/*`The following example shows how multiprecision calculations can be used to +obtain full precision in a numerical derivative calculation that suffers from precision loss. + +Consider some well-known central difference rules for numerically +computing the 1st derivative of a function [f'(x)] with [/x] real. + +Need a reference here? Introduction to Partial Differential Equations, Peter J. Olver + December 16, 2012 + +Here, the implementation uses a C++ template that can be instantiated with various +floating-point types such as `float`, `double`, `long double`, or even +a user-defined floating-point type like __multiprecision. + +We will now use the derivative template with the built-in type `double` in +order to numerically compute the derivative of a function, and then repeat +with a 5 decimal digit higher precision user-defined floating-point type. + +Consider the function shown below. +!! +(3) +We will now take the derivative of this function with respect to x evaluated +at x = 3= 2. In other words, + +(4) + +The expected result is + + 0:74535 59924 99929 89880 . (5) +The program below uses the derivative template in order to perform +the numerical calculation of this derivative. The program also compares the +numerically-obtained result with the expected result and reports the absolute +relative error scaled to a deviation that can easily be related to the number of +bits of lost precision. + +*/ + +/*` [note Requires the C++11 feature of +[@http://en.wikipedia.org/wiki/Anonymous_function#C.2B.2B anonymous functions] +for the derivative function calls like `[]( const double & x_) -> double`. +*/ + + + +template <typename value_type, typename function_type> +value_type derivative (const value_type x, const value_type dx, function_type function) +{ + /*! \brief Compute the derivative of function using a 3-point central difference rule of O(dx^6). + \tparam value_type, floating-point type, for example: `double` or `cpp_dec_float_50` + \tparam function_type + + \param x Value at which to evaluate derivative. + \param dx Incremental step-size. + \param function Function whose derivative is to computed. + + \return derivative at x. + */ + + BOOST_STATIC_ASSERT_MSG(false == std::numeric_limits<value_type>::is_integer, "value_type must be a floating-point type!"); + + const value_type dx2(dx * 2U); + const value_type dx3(dx * 3U); + // Difference terms. + const value_type m1 ((function (x + dx) - function(x - dx)) / 2U); + const value_type m2 ((function (x + dx2) - function(x - dx2)) / 4U); + const value_type m3 ((function (x + dx3) - function(x - dx3)) / 6U); + const value_type fifteen_m1 (m1 * 15U); + const value_type six_m2 (m2 * 6U); + const value_type ten_dx (dx * 10U); + return ((fifteen_m1 - six_m2) + m3) / ten_dx; // Derivative. +} // + +#include <boost/multiprecision/cpp_dec_float.hpp> + using boost::multiprecision::number; + using boost::multiprecision::cpp_dec_float; + +// Re-compute using 5 extra decimal digits precision (22) than double (17). +#define MP_DIGITS10 unsigned (std::numeric_limits<double>::max_digits10 + 5) + +typedef cpp_dec_float<MP_DIGITS10> mp_backend; +typedef number<mp_backend> mp_type; + + +int main() +{ + { + const double d = + derivative + ( 1.5, // x = 3.2 + std::ldexp (1., -9), // step size 2^-9 = see below for choice. + [](const double & x)->double // Function f(x). + { + return std::sqrt((x * x) - 1.) - std::acos(1. / x); + } + ); + + // The 'exactly right' result is [sqrt]5 / 3 = 0.74535599249992989880. + const double rel_error = (d - 0.74535599249992989880) / 0.74535599249992989880; + const double bit_error = std::abs(rel_error) / std::numeric_limits<double>::epsilon(); + std::cout.precision (std::numeric_limits<double>::digits10); // Show all guaranteed decimal digits. + std::cout << std::showpoint ; // Ensure that any trailing zeros are shown too. + + std::cout << " derivative : " << d << std::endl; + std::cout << " expected : " << 0.74535599249992989880 << std::endl; + // Can compute an 'exact' value using multiprecision type. + std::cout << " expected : " << sqrt(static_cast<mp_type>(5))/3U << std::endl; + std::cout << " bit_error : " << static_cast<unsigned long>(bit_error) << std::endl; + + std::cout.precision(6); + std::cout << "float_distance = " << boost::math::float_distance(0.74535599249992989880, d) << std::endl; + + } + + { // Compute using multiprecision type with an extra 5 decimal digits of precision. + const mp_type mp = + derivative(mp_type(mp_type(3) / 2U), // x = 3/2 + mp_type(mp_type(1) / 10000000U), // Step size 10^7. + [](const mp_type & x)->mp_type + { + return sqrt((x * x) - 1.) - acos (1. / x); // Function + } + ); + + const double d = mp.convert_to<double>(); // Convert to closest double. + const double rel_error = (d - 0.74535599249992989880) / 0.74535599249992989880; + const double bit_error = std::abs (rel_error) / std::numeric_limits<double>::epsilon(); + std::cout.precision (std::numeric_limits <double>::digits10); // All guaranteed decimal digits. + std::cout << std::showpoint ; // Ensure that any trailing zeros are shown too. + std::cout << " derivative : " << d << std::endl; + // Can compute an 'exact' value using multiprecision type. + std::cout << " expected : " << sqrt(static_cast<mp_type>(5))/3U << std::endl; + std::cout << " expected : " << 0.74535599249992989880 + << std::endl; + std::cout << " bit_error : " << static_cast<unsigned long>(bit_error) << std::endl; + + std::cout.precision(6); + std::cout << "float_distance = " << boost::math::float_distance(0.74535599249992989880, d) << std::endl; + + + } + + +} // int main() + +/*` +The result of this program on a system with an eight-byte, 64-bit IEEE-754 +conforming floating-point representation for `double` is: + + derivative : 0.745355992499951 + + derivative : 0.745355992499943 + expected : 0.74535599249993 + bit_error : 78 + + derivative : 0.745355992499930 + expected : 0.745355992499930 + bit_error : 0 + +The resulting bit error is 0. This means that the result of the derivative +calculation is bit-identical with the double representation of the expected result, +and this is the best result possible for the built-in type. + +The derivative in this example has a known closed form. There are, however, +countless situations in numerical analysis (and not only for numerical deriva- +tives) for which the calculation at hand does not have a known closed-form +solution or for which the closed-form solution is highly inconvenient to use. In +such cases, this technique may be useful. + +This example has shown how multiprecision can be used to add extra digits +to an ill-conditioned calculation that suffers from precision loss. When the result +of the multiprecision calculation is converted to a built-in type such as double, +the entire precision of the result in double is preserved. + + */ + +/* + + Description: Autorun "J:\Cpp\big_number\Debug\numerical_derivative_example.exe" + derivative : 0.745355992499943 + expected : 0.745355992499930 + expected : 0.745355992499930 + bit_error : 78 + float_distance = 117.000 + derivative : 0.745355992499930 + expected : 0.745355992499930 + expected : 0.745355992499930 + bit_error : 0 + float_distance = 0.000000 + + */ + diff --git a/src/boost/libs/math/example/ooura_fourier_integrals_cosine_example.cpp b/src/boost/libs/math/example/ooura_fourier_integrals_cosine_example.cpp new file mode 100644 index 000000000..2269202d3 --- /dev/null +++ b/src/boost/libs/math/example/ooura_fourier_integrals_cosine_example.cpp @@ -0,0 +1,83 @@ +// Copyright Paul A. Bristow, 2019 +// Copyright Nick Thompson, 2019 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +//#define BOOST_MATH_INSTRUMENT_OOURA // or -DBOOST_MATH_INSTRUMENT_OOURA etc for diagnostic output. + +#include <boost/math/quadrature/ooura_fourier_integrals.hpp> // For ooura_fourier_cos +#include <boost/math/constants/constants.hpp> // For pi (including for multiprecision types, if used.) + +#include <cmath> +#include <iostream> +#include <limits> +#include <iostream> + +int main() +{ + try + { + std::cout.precision(std::numeric_limits<double>::max_digits10); // Show all potentially significant digits. + + using boost::math::quadrature::ooura_fourier_cos; + using boost::math::constants::half_pi; + using boost::math::constants::e; + + //[ooura_fourier_integrals_cosine_example_1 + auto integrator = ooura_fourier_cos<double>(); + // Use the default tolerance root_epsilon and eight levels for type double. + + auto f = [](double x) + { // More complex example function. + return 1 / (x * x + 1); + }; + + double omega = 1; + + auto [result, relative_error] = integrator.integrate(f, omega); + std::cout << "Integral = " << result << ", relative error estimate " << relative_error << std::endl; + + //] [/ooura_fourier_integrals_cosine_example_1] + + //[ooura_fourier_integrals_cosine_example_2 + + constexpr double expected = half_pi<double>() / e<double>(); + std::cout << "pi/(2e) = " << expected << ", difference " << result - expected << std::endl; + //] [/ooura_fourier_integrals_cosine_example_2] + } + catch (std::exception const & ex) + { + // Lacking try&catch blocks, the program will abort after any throw, whereas the + // message below from the thrown exception will give some helpful clues as to the cause of the problem. + std::cout << "\n""Message from thrown exception was:\n " << ex.what() << std::endl; + } + +} // int main() + +/* + +//[ooura_fourier_integrals_example_cosine_output_1 +`` +Integral = 0.57786367489546109, relative error estimate 6.4177395404415149e-09 +pi/(2e) = 0.57786367489546087, difference 2.2204460492503131e-16 +`` +//] [/ooura_fourier_integrals_example_cosine_output_1] + + +//[ooura_fourier_integrals_example_cosine_diagnostic_output_1 +`` +ooura_fourier_cos with relative error goal 1.4901161193847656e-08 & 8 levels. +epsilon for type = 2.2204460492503131e-16 +h = 1.000000000000000, I_h = 0.588268622591776 = 0x1.2d318b7e96dbe00p-1, absolute error estimate = nan +h = 0.500000000000000, I_h = 0.577871642184837 = 0x1.27decab8f07b200p-1, absolute error estimate = 1.039698040693926e-02 +h = 0.250000000000000, I_h = 0.577863671186883 = 0x1.27ddbf42969be00p-1, absolute error estimate = 7.970997954576120e-06 +h = 0.125000000000000, I_h = 0.577863674895461 = 0x1.27ddbf6271dc000p-1, absolute error estimate = 3.708578555361441e-09 +Integral = 5.778636748954611e-01, relative error estimate 6.417739540441515e-09 +pi/(2e) = 5.778636748954609e-01, difference 2.220446049250313e-16 +`` +//] [/ooura_fourier_integrals_example_cosine_diagnostic_output_1] + +*/ diff --git a/src/boost/libs/math/example/ooura_fourier_integrals_example.cpp b/src/boost/libs/math/example/ooura_fourier_integrals_example.cpp new file mode 100644 index 000000000..22a9d015a --- /dev/null +++ b/src/boost/libs/math/example/ooura_fourier_integrals_example.cpp @@ -0,0 +1,83 @@ +// Copyright Paul A. Bristow, 2019 +// Copyright Nick Thompson, 2019 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifdef BOOST_NO_CXX11_LAMBDAS +# error "This example requires a C++11 compiler that supports lambdas. Try C++11 or later." +#endif + +//#define BOOST_MATH_INSTRUMENT_OOURA // or -DBOOST_MATH_INSTRUMENT_OOURA etc for diagnostics. + +#include <boost/math/quadrature/ooura_fourier_integrals.hpp> +#include <boost/math/constants/constants.hpp> // For pi (including for multiprecision types, if used.) + +#include <cmath> +#include <iostream> +#include <limits> +#include <iostream> + +int main() +{ + try + { + std::cout.precision(std::numeric_limits<double>::max_digits10); // Show all potentially significant digits. + + using boost::math::quadrature::ooura_fourier_sin; + using boost::math::constants::half_pi; + +//[ooura_fourier_integrals_example_1 + ooura_fourier_sin<double>integrator = ooura_fourier_sin<double>(); + // Use the default tolerance root_epsilon and eight levels for type double. + + auto f = [](double x) + { // Simple reciprocal function for sinc. + return 1 / x; + }; + + double omega = 1; + std::pair<double, double> result = integrator.integrate(f, omega); + std::cout << "Integral = " << result.first << ", relative error estimate " << result.second << std::endl; + +//] [/ooura_fourier_integrals_example_1] + +//[ooura_fourier_integrals_example_2 + + constexpr double expected = half_pi<double>(); + std::cout << "pi/2 = " << expected << ", difference " << result.first - expected << std::endl; +//] [/ooura_fourier_integrals_example_2] + } + catch (std::exception const & ex) + { + // Lacking try&catch blocks, the program will abort after any throw, whereas the + // message below from the thrown exception will give some helpful clues as to the cause of the problem. + std::cout << "\n""Message from thrown exception was:\n " << ex.what() << std::endl; + } +} // int main() + +/* + +//[ooura_fourier_integrals_example_output_1 + +integral = 1.5707963267948966, relative error estimate 1.2655356398390254e-11 +pi/2 = 1.5707963267948966, difference 0 + +//] [/ooura_fourier_integrals_example_output_1] + + +//[ooura_fourier_integrals_example_diagnostic_output_1 + +ooura_fourier_sin with relative error goal 1.4901161193847656e-08 & 8 levels. +h = 1.000000000000000, I_h = 1.571890732004545 = 0x1.92676e56d853500p+0, absolute error estimate = nan +h = 0.500000000000000, I_h = 1.570793292491940 = 0x1.921f825c076f600p+0, absolute error estimate = 1.097439512605325e-03 +h = 0.250000000000000, I_h = 1.570796326814776 = 0x1.921fb54458acf00p+0, absolute error estimate = 3.034322835882008e-06 +h = 0.125000000000000, I_h = 1.570796326794897 = 0x1.921fb54442d1800p+0, absolute error estimate = 1.987898734512328e-11 +Integral = 1.570796326794897e+00, relative error estimate 1.265535639839025e-11 +pi/2 = 1.570796326794897e+00, difference 0.000000000000000e+00 + +//] [/ooura_fourier_integrals_example_diagnostic_output_1] + +*/ diff --git a/src/boost/libs/math/example/ooura_fourier_integrals_multiprecision_example.cpp b/src/boost/libs/math/example/ooura_fourier_integrals_multiprecision_example.cpp new file mode 100644 index 000000000..f2ac13194 --- /dev/null +++ b/src/boost/libs/math/example/ooura_fourier_integrals_multiprecision_example.cpp @@ -0,0 +1,98 @@ +// Copyright Paul A. Bristow, 2019 +// Copyright Nick Thompson, 2019 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(__cpp_structured_bindings) || (__cpp_structured_bindings < 201606L) +# error "This example requires a C++17 compiler that supports 'structured bindings'. Try /std:c++17 or -std=c++17 or later." +#endif + +//#define BOOST_MATH_INSTRUMENT_OOURA // or -DBOOST_MATH_INSTRUMENT_OOURA etc for diagnostic output. + +#include <boost/math/quadrature/ooura_fourier_integrals.hpp> +#include <boost/multiprecision/cpp_bin_float.hpp> // for cpp_bin_float_quad, cpp_bin_float_50... +#include <boost/math/constants/constants.hpp> // For pi (including for multiprecision types, if used.) + +#include <cmath> +#include <iostream> +#include <limits> +#include <iostream> +#include <exception> + +int main() +{ + try + { + typedef boost::multiprecision::cpp_bin_float_quad Real; + + std::cout.precision(std::numeric_limits<Real>::max_digits10); // Show all potentially significant digits. + + using boost::math::quadrature::ooura_fourier_cos; + using boost::math::constants::half_pi; + using boost::math::constants::e; + + //[ooura_fourier_integrals_multiprecision_example_1 + + // Use the default parameters for tolerance root_epsilon and eight levels for a type of 8 bytes. + //auto integrator = ooura_fourier_cos<Real>(); + // Decide on a (tight) tolerance. + const Real tol = 2 * std::numeric_limits<Real>::epsilon(); + auto integrator = ooura_fourier_cos<Real>(tol, 8); // Loops or gets worse for more than 8. + + auto f = [](Real x) + { // More complex example function. + return 1 / (x * x + 1); + }; + + double omega = 1; + auto [result, relative_error] = integrator.integrate(f, omega); + + //] [/ooura_fourier_integrals_multiprecision_example_1] + + //[ooura_fourier_integrals_multiprecision_example_2 + std::cout << "Integral = " << result << ", relative error estimate " << relative_error << std::endl; + + const Real expected = half_pi<Real>() / e<Real>(); // Expect integral = 1/(2e) + std::cout << "pi/(2e) = " << expected << ", difference " << result - expected << std::endl; + //] [/ooura_fourier_integrals_multiprecision_example_2] + } + catch (std::exception const & ex) + { + // Lacking try&catch blocks, the program will abort after any throw, whereas the + // message below from the thrown exception will give some helpful clues as to the cause of the problem. + std::cout << "\n""Message from thrown exception was:\n " << ex.what() << std::endl; + } +} // int main() + +/* + +//[ooura_fourier_integrals_example_multiprecision_output_1 +`` +Integral = 0.5778636748954608589550465916563501587, relative error estimate 4.609814684522163895264277312610830278e-17 +pi/(2e) = 0.5778636748954608659545328919193707407, difference -6.999486300263020581921171645255733758e-18 +`` +//] [/ooura_fourier_integrals_example_multiprecision_output_1] + + +//[ooura_fourier_integrals_example_multiprecision_diagnostic_output_1 +`` +ooura_fourier_cos with relative error goal 3.851859888774471706111955885169854637e-34 & 15 levels. +epsilon for type = 1.925929944387235853055977942584927319e-34 +h = 1.000000000000000000000000000000000, I_h = 0.588268622591776615359568690603776 = 0.5882686225917766153595686906037760, absolute error estimate = nan +h = 0.500000000000000000000000000000000, I_h = 0.577871642184837461311756940493259 = 0.5778716421848374613117569404932595, absolute error estimate = 1.039698040693915404781175011051656e-02 +h = 0.250000000000000000000000000000000, I_h = 0.577863671186882539559996800783122 = 0.5778636711868825395599968007831220, absolute error estimate = 7.970997954921751760139710137450075e-06 +h = 0.125000000000000000000000000000000, I_h = 0.577863674895460885593491133506723 = 0.5778636748954608855934911335067232, absolute error estimate = 3.708578346033494332723601147051768e-09 +h = 0.062500000000000000000000000000000, I_h = 0.577863674895460858955046591656350 = 0.5778636748954608589550465916563502, absolute error estimate = 2.663844454185037302771663314961535e-17 +h = 0.031250000000000000000000000000000, I_h = 0.577863674895460858955046591656348 = 0.5778636748954608589550465916563484, absolute error estimate = 1.733336949948512267750380148326435e-33 +h = 0.015625000000000000000000000000000, I_h = 0.577863674895460858955046591656348 = 0.5778636748954608589550465916563479, absolute error estimate = 4.814824860968089632639944856462318e-34 +h = 0.007812500000000000000000000000000, I_h = 0.577863674895460858955046591656347 = 0.5778636748954608589550465916563473, absolute error estimate = 6.740754805355325485695922799047246e-34 +h = 0.003906250000000000000000000000000, I_h = 0.577863674895460858955046591656347 = 0.5778636748954608589550465916563475, absolute error estimate = 1.925929944387235853055977942584927e-34 +Integral = 5.778636748954608589550465916563475e-01, relative error estimate 3.332844800697411177051445985473052e-34 +pi/(2e) = 5.778636748954608589550465916563481e-01, difference -6.740754805355325485695922799047246e-34 +`` +//] [/ooura_fourier_integrals_example_multiprecision_diagnostic_output_1] + +*/ diff --git a/src/boost/libs/math/example/owens_t_example.cpp b/src/boost/libs/math/example/owens_t_example.cpp new file mode 100644 index 000000000..6c6d20417 --- /dev/null +++ b/src/boost/libs/math/example/owens_t_example.cpp @@ -0,0 +1,113 @@ +// Copyright Benjamin Sobotta 2012 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifdef _MSC_VER +# pragma warning(disable : 4127) // conditional expression is constant. +#endif + +#include <boost/math/special_functions/owens_t.hpp> +#include <iostream> + +int main() +{ + double h = 0.0,a; + std::cout << std::setprecision(20); + + static const double a_vec[] = { + 0.5000000000000000E+00, + 0.1000000000000000E+01, + 0.2000000000000000E+01, + 0.3000000000000000E+01, + 0.5000000000000000E+00, + 0.1000000000000000E+01, + 0.2000000000000000E+01, + 0.3000000000000000E+01, + 0.5000000000000000E+00, + 0.1000000000000000E+01, + 0.2000000000000000E+01, + 0.3000000000000000E+01, + 0.5000000000000000E+00, + 0.1000000000000000E+01, + 0.2000000000000000E+01, + 0.3000000000000000E+01, + 0.5000000000000000E+00, + 0.1000000000000000E+01, + 0.2000000000000000E+01, + 0.3000000000000000E+01, + 0.1000000000000000E+02, + 0.1000000000000000E+03 }; + + static const double h_vec[] = { + 0.1000000000000000E+01, + 0.1000000000000000E+01, + 0.1000000000000000E+01, + 0.1000000000000000E+01, + 0.5000000000000000E+00, + 0.5000000000000000E+00, + 0.5000000000000000E+00, + 0.5000000000000000E+00, + 0.2500000000000000E+00, + 0.2500000000000000E+00, + 0.2500000000000000E+00, + 0.2500000000000000E+00, + 0.1250000000000000E+00, + 0.1250000000000000E+00, + 0.1250000000000000E+00, + 0.1250000000000000E+00, + 0.7812500000000000E-02, + 0.7812500000000000E-02, + 0.7812500000000000E-02, + 0.7812500000000000E-02, + 0.7812500000000000E-02, + 0.7812500000000000E-02 }; + + static const double t_vec[] = { + 0.4306469112078537E-01, + 0.6674188216570097E-01, + 0.7846818699308410E-01, + 0.7929950474887259E-01, + 0.6448860284750376E-01, + 0.1066710629614485E+00, + 0.1415806036539784E+00, + 0.1510840430760184E+00, + 0.7134663382271778E-01, + 0.1201285306350883E+00, + 0.1666128410939293E+00, + 0.1847501847929859E+00, + 0.7317273327500385E-01, + 0.1237630544953746E+00, + 0.1737438887583106E+00, + 0.1951190307092811E+00, + 0.7378938035365546E-01, + 0.1249951430754052E+00, + 0.1761984774738108E+00, + 0.1987772386442824E+00, + 0.2340886964802671E+00, + 0.2479460829231492E+00 }; + + for(unsigned i = 0; i != 22; ++i) + { + h = h_vec[i]; + a = a_vec[i]; + const double t = boost::math::owens_t(h, a); + std::cout << "h=" << h << "\ta=" << a << "\tcomp=" + << t << "\ttab=" << t_vec[i] + << "\tdiff=" << std::fabs(t_vec[i]-t) << std::endl;; + } + + return 0; +} + + +// EOF + + + + + + + + diff --git a/src/boost/libs/math/example/policy_eg_1.cpp b/src/boost/libs/math/example/policy_eg_1.cpp new file mode 100644 index 000000000..7f8d9fbb4 --- /dev/null +++ b/src/boost/libs/math/example/policy_eg_1.cpp @@ -0,0 +1,70 @@ +// Copyright John Maddock 2007. +// Copyright Paul A> Bristow 2010 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <iostream> +using std::cout; using std::endl; +#include <cerrno> // for ::errno + +//[policy_eg_1 + +#include <boost/math/special_functions/gamma.hpp> +using boost::math::tgamma; + +// Define the policy to use: +using namespace boost::math::policies; // may be convenient, or + +using boost::math::policies::policy; +// Types of error whose action can be altered by policies:. +using boost::math::policies::evaluation_error; +using boost::math::policies::domain_error; +using boost::math::policies::overflow_error; +using boost::math::policies::domain_error; +using boost::math::policies::pole_error; +// Actions on error (in enum error_policy_type): +using boost::math::policies::errno_on_error; +using boost::math::policies::ignore_error; +using boost::math::policies::throw_on_error; +using boost::math::policies::user_error; + +typedef policy< + domain_error<errno_on_error>, + pole_error<errno_on_error>, + overflow_error<errno_on_error>, + evaluation_error<errno_on_error> +> c_policy; +// +// Now use the policy when calling tgamma: + +// http://msdn.microsoft.com/en-us/library/t3ayayh1.aspx +// Microsoft errno declared in STDLIB.H as "extern int errno;" + +int main() +{ + errno = 0; // Reset. + cout << "Result of tgamma(30000) is: " + << tgamma(30000, c_policy()) << endl; // Too big parameter + cout << "errno = " << errno << endl; // errno 34 Numerical result out of range. + cout << "Result of tgamma(-10) is: " + << boost::math::tgamma(-10, c_policy()) << endl; // Negative parameter. + cout << "errno = " << errno << endl; // error 33 Numerical argument out of domain. +} // int main() + +//] + +/* Output + +policy_eg_1.cpp + Generating code + Finished generating code + policy_eg_1.vcxproj -> J:\Cpp\MathToolkit\test\Math_test\Release\policy_eg_1.exe + Result of tgamma(30000) is: 1.#INF + errno = 34 + Result of tgamma(-10) is: 1.#QNAN + errno = 33 + +*/ + + diff --git a/src/boost/libs/math/example/policy_eg_10.cpp b/src/boost/libs/math/example/policy_eg_10.cpp new file mode 100644 index 000000000..87f84c090 --- /dev/null +++ b/src/boost/libs/math/example/policy_eg_10.cpp @@ -0,0 +1,183 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +//[policy_eg_10 + +/*` + +To understand how the rounding policies for +the discrete distributions can be used, we'll +use the 50-sample binomial distribution with a +success fraction of 0.5 once again, and calculate +all the possible quantiles at 0.05 and 0.95. + +Begin by including the needed headers (and some using statements for conciseness): + +*/ +#include <iostream> +using std::cout; using std::endl; +using std::left; using std::fixed; using std::right; using std::scientific; +#include <iomanip> +using std::setw; +using std::setprecision; + +#include <boost/math/distributions/binomial.hpp> +/*` + +Next we'll bring the needed declarations into scope, and +define distribution types for all the available rounding policies: + +*/ +// Avoid +// using namespace std; // and +// using namespace boost::math; +// to avoid potential ambiguity of names, like binomial. +// using namespace boost::math::policies; is small risk, but +// the necessary items are brought into scope thus: + +using boost::math::binomial_distribution; +using boost::math::policies::policy; +using boost::math::policies::discrete_quantile; + +using boost::math::policies::integer_round_outwards; +using boost::math::policies::integer_round_down; +using boost::math::policies::integer_round_up; +using boost::math::policies::integer_round_nearest; +using boost::math::policies::integer_round_inwards; +using boost::math::policies::real; + +using boost::math::binomial_distribution; // Not std::binomial_distribution. + +typedef binomial_distribution< + double, + policy<discrete_quantile<integer_round_outwards> > > + binom_round_outwards; + +typedef binomial_distribution< + double, + policy<discrete_quantile<integer_round_inwards> > > + binom_round_inwards; + +typedef binomial_distribution< + double, + policy<discrete_quantile<integer_round_down> > > + binom_round_down; + +typedef binomial_distribution< + double, + policy<discrete_quantile<integer_round_up> > > + binom_round_up; + +typedef binomial_distribution< + double, + policy<discrete_quantile<integer_round_nearest> > > + binom_round_nearest; + +typedef binomial_distribution< + double, + policy<discrete_quantile<real> > > + binom_real_quantile; + +/*` +Now let's set to work calling those quantiles: +*/ + +int main() +{ + cout << + "Testing rounding policies for a 50 sample binomial distribution,\n" + "with a success fraction of 0.5.\n\n" + "Lower quantiles are calculated at p = 0.05\n\n" + "Upper quantiles at p = 0.95.\n\n"; + + cout << setw(25) << right + << "Policy"<< setw(18) << right + << "Lower Quantile" << setw(18) << right + << "Upper Quantile" << endl; + + // Test integer_round_outwards: + cout << setw(25) << right + << "integer_round_outwards" + << setw(18) << right + << quantile(binom_round_outwards(50, 0.5), 0.05) + << setw(18) << right + << quantile(binom_round_outwards(50, 0.5), 0.95) + << endl; + + // Test integer_round_inwards: + cout << setw(25) << right + << "integer_round_inwards" + << setw(18) << right + << quantile(binom_round_inwards(50, 0.5), 0.05) + << setw(18) << right + << quantile(binom_round_inwards(50, 0.5), 0.95) + << endl; + + // Test integer_round_down: + cout << setw(25) << right + << "integer_round_down" + << setw(18) << right + << quantile(binom_round_down(50, 0.5), 0.05) + << setw(18) << right + << quantile(binom_round_down(50, 0.5), 0.95) + << endl; + + // Test integer_round_up: + cout << setw(25) << right + << "integer_round_up" + << setw(18) << right + << quantile(binom_round_up(50, 0.5), 0.05) + << setw(18) << right + << quantile(binom_round_up(50, 0.5), 0.95) + << endl; + + // Test integer_round_nearest: + cout << setw(25) << right + << "integer_round_nearest" + << setw(18) << right + << quantile(binom_round_nearest(50, 0.5), 0.05) + << setw(18) << right + << quantile(binom_round_nearest(50, 0.5), 0.95) + << endl; + + // Test real: + cout << setw(25) << right + << "real" + << setw(18) << right + << quantile(binom_real_quantile(50, 0.5), 0.05) + << setw(18) << right + << quantile(binom_real_quantile(50, 0.5), 0.95) + << endl; +} // int main() + +/*` + +Which produces the program output: + +[pre + policy_eg_10.vcxproj -> J:\Cpp\MathToolkit\test\Math_test\Release\policy_eg_10.exe + Testing rounding policies for a 50 sample binomial distribution, + with a success fraction of 0.5. + + Lower quantiles are calculated at p = 0.05 + + Upper quantiles at p = 0.95. + + Policy Lower Quantile Upper Quantile + integer_round_outwards 18 31 + integer_round_inwards 19 30 + integer_round_down 18 30 + integer_round_up 19 31 + integer_round_nearest 19 30 + real 18.701 30.299 +] + +*/ + +//] //[policy_eg_10] ends quickbook import. diff --git a/src/boost/libs/math/example/policy_eg_2.cpp b/src/boost/libs/math/example/policy_eg_2.cpp new file mode 100644 index 000000000..3ab8312e8 --- /dev/null +++ b/src/boost/libs/math/example/policy_eg_2.cpp @@ -0,0 +1,65 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <iostream> +using std::cout; using std::endl; +#include <cerrno> // for ::errno + +//[policy_eg_2 + +#include <boost/math/special_functions/gamma.hpp> +using boost::math::tgamma; + +int main() +{ + // using namespace boost::math::policies; // or + using boost::math::policies::errno_on_error; + using boost::math::policies::make_policy; + using boost::math::policies::pole_error; + using boost::math::policies::domain_error; + using boost::math::policies::overflow_error; + using boost::math::policies::evaluation_error; + + errno = 0; + std::cout << "Result of tgamma(30000) is: " + << boost::math::tgamma( + 30000, + make_policy( + domain_error<errno_on_error>(), + pole_error<errno_on_error>(), + overflow_error<errno_on_error>(), + evaluation_error<errno_on_error>() + ) + ) << std::endl; + // Check errno was set: + std::cout << "errno = " << errno << std::endl; + // and again with evaluation at a pole: + std::cout << "Result of tgamma(-10) is: " + << boost::math::tgamma( + -10, + make_policy( + domain_error<errno_on_error>(), + pole_error<errno_on_error>(), + overflow_error<errno_on_error>(), + evaluation_error<errno_on_error>() + ) + ) << std::endl; + // Check errno was set: + std::cout << "errno = " << errno << std::endl; +} + +//] //[/policy_eg_2] + +/* + +Output: + + Result of tgamma(30000) is: 1.#INF + errno = 34 + Result of tgamma(-10) is: 1.#QNAN + errno = 33 +*/ + diff --git a/src/boost/libs/math/example/policy_eg_3.cpp b/src/boost/libs/math/example/policy_eg_3.cpp new file mode 100644 index 000000000..adf8c9e44 --- /dev/null +++ b/src/boost/libs/math/example/policy_eg_3.cpp @@ -0,0 +1,55 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2007, 2010. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifdef _MSC_VER +# pragma warning (disable : 4305) // 'initializing' : truncation from 'long double' to 'const eval_type' +# pragma warning (disable : 4244) // conversion from 'long double' to 'const eval_type' +#endif + +#include <iostream> +using std::cout; using std::endl; + +//[policy_eg_3 + +#include <boost/math/distributions/binomial.hpp> +using boost::math::binomial_distribution; + +// Begin by defining a policy type, that gives the behaviour we want: + +//using namespace boost::math::policies; or explicitly +using boost::math::policies::policy; + +using boost::math::policies::promote_float; +using boost::math::policies::discrete_quantile; +using boost::math::policies::integer_round_nearest; + +typedef policy< + promote_float<false>, // Do not promote to double. + discrete_quantile<integer_round_nearest> // Round result to nearest integer. +> mypolicy; +// +// Then define a new distribution that uses it: +typedef boost::math::binomial_distribution<float, mypolicy> mybinom; + +// And now use it to get the quantile: + +int main() +{ + cout << "quantile(mybinom(200, 0.25), 0.05) is: " << + quantile(mybinom(200, 0.25), 0.05) << endl; +} + +//] + +/* + +Output: + + quantile(mybinom(200, 0.25), 0.05) is: 40 + +*/ + diff --git a/src/boost/libs/math/example/policy_eg_4.cpp b/src/boost/libs/math/example/policy_eg_4.cpp new file mode 100644 index 000000000..5cd281618 --- /dev/null +++ b/src/boost/libs/math/example/policy_eg_4.cpp @@ -0,0 +1,107 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +#include <iostream> +using std::cout; using std::endl; +#include <cerrno> // for ::errno + +//[policy_eg_4 + +/*` +Suppose we want `C::foo()` to behave in a C-compatible way and set +`::errno` on error rather than throwing any exceptions. + +We'll begin by including the needed header for our function: +*/ + +#include <boost/math/special_functions.hpp> +//using boost::math::tgamma; // Not needed because using C::tgamma. + +/*` +Open up the "C" namespace that we'll use for our functions, and +define the policy type we want: in this case a C-style one that sets +::errno and returns a standard value, rather than throwing exceptions. + +Any policies we don't specify here will inherit the defaults. +*/ + +namespace C +{ // To hold our C-style policy. + //using namespace boost::math::policies; or explicitly: + using boost::math::policies::policy; + + using boost::math::policies::domain_error; + using boost::math::policies::pole_error; + using boost::math::policies::overflow_error; + using boost::math::policies::evaluation_error; + using boost::math::policies::errno_on_error; + + typedef policy< + domain_error<errno_on_error>, + pole_error<errno_on_error>, + overflow_error<errno_on_error>, + evaluation_error<errno_on_error> + > c_policy; + +/*` +All we need do now is invoke the BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS +macro passing our policy type c_policy as the single argument: +*/ + +BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(c_policy) + +} // close namespace C + +/*` +We now have a set of forwarding functions defined in namespace C +that all look something like this: + +`` +template <class RealType> +inline typename boost::math::tools::promote_args<RT>::type + tgamma(RT z) +{ + return boost::math::tgamma(z, c_policy()); +} +`` + +So that when we call `C::tgamma(z)`, we really end up calling +`boost::math::tgamma(z, C::c_policy())`: +*/ + +int main() +{ + errno = 0; + cout << "Result of tgamma(30000) is: " + << C::tgamma(30000) << endl; // Note using C::tgamma + cout << "errno = " << errno << endl; // errno = 34 + cout << "Result of tgamma(-10) is: " + << C::tgamma(-10) << endl; + cout << "errno = " << errno << endl; // errno = 33, overwriting previous value of 34. +} + +/*` + +Which outputs: + +[pre +Result of C::tgamma(30000) is: 1.#INF +errno = 34 +Result of C::tgamma(-10) is: 1.#QNAN +errno = 33 +] + +This mechanism is particularly useful when we want to define a project-wide policy, +and don't want to modify the Boost source, +or to set project wide build macros (possibly fragile and easy to forget). + +*/ +//] //[/policy_eg_4] + diff --git a/src/boost/libs/math/example/policy_eg_5.cpp b/src/boost/libs/math/example/policy_eg_5.cpp new file mode 100644 index 000000000..d022c9c85 --- /dev/null +++ b/src/boost/libs/math/example/policy_eg_5.cpp @@ -0,0 +1,66 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +#include <iostream> +using std::cout; using std::endl; +#include <cerrno> // for ::errno + +//[policy_eg_5 + +#include <boost/math/special_functions.hpp> +// using boost::math::tgamma; // Would create an ambiguity between +// 'double boost::math::tgamma<int>(T)' and +// 'double 'anonymous-namespace'::tgamma<int>(RT)'. + +namespace mymath +{ // unnamed + +using namespace boost::math::policies; + +typedef policy< + domain_error<errno_on_error>, + pole_error<errno_on_error>, + overflow_error<errno_on_error>, + evaluation_error<errno_on_error> +> c_policy; + +BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(c_policy) + +/*` +So that when we call `mymath::tgamma(z)`, we really end up calling + `boost::math::tgamma(z, anonymous-namespace::c_policy())`. +*/ + +} // close unnamed namespace + +int main() +{ + errno = 0; + cout << "Result of tgamma(30000) is: " + << mymath::tgamma(30000) << endl; + // tgamma in unnamed namespace in this translation unit (file) only. + cout << "errno = " << errno << endl; + cout << "Result of tgamma(-10) is: " + << mymath::tgamma(-10) << endl; + cout << "errno = " << errno << endl; + // Default tgamma policy would throw an exception, and abort. +} + +//] //[/policy_eg_5] + +/* +Output: + + Result of tgamma(30000) is: 1.#INF + errno = 34 + Result of tgamma(-10) is: 1.#QNAN + errno = 33 + + +*/ diff --git a/src/boost/libs/math/example/policy_eg_6.cpp b/src/boost/libs/math/example/policy_eg_6.cpp new file mode 100644 index 000000000..57f92fccc --- /dev/null +++ b/src/boost/libs/math/example/policy_eg_6.cpp @@ -0,0 +1,121 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +#include <iostream> +using std::cout; using std::endl; +#include <cerrno> // for ::errno + +//[policy_eg_6 + +/*` +Suppose we want a set of distributions to behave as follows: + +* Return infinity on overflow, rather than throwing an exception. +* Don't perform any promotion from double to long double internally. +* Return the closest integer result from the quantiles of discrete +distributions. + +We'll begin by including the needed header for all the distributions: +*/ + +#include <boost/math/distributions.hpp> + +/*` + +Open up an appropriate namespace, calling it `my_distributions`, +for our distributions, and define the policy type we want. +Any policies we don't specify here will inherit the defaults: + +*/ + +namespace my_distributions +{ + using namespace boost::math::policies; + // using boost::math::policies::errno_on_error; // etc. + + typedef policy< + // return infinity and set errno rather than throw: + overflow_error<errno_on_error>, + // Don't promote double -> long double internally: + promote_double<false>, + // Return the closest integer result for discrete quantiles: + discrete_quantile<integer_round_nearest> + > my_policy; + +/*` + +All we need do now is invoke the BOOST_MATH_DECLARE_DISTRIBUTIONS +macro passing the floating point type `double` and policy types `my_policy` as arguments: + +*/ + +BOOST_MATH_DECLARE_DISTRIBUTIONS(double, my_policy) + +} // close namespace my_namespace + +/*` + +We now have a set of typedefs defined in namespace my_distributions +that all look something like this: + +`` +typedef boost::math::normal_distribution<double, my_policy> normal; +typedef boost::math::cauchy_distribution<double, my_policy> cauchy; +typedef boost::math::gamma_distribution<double, my_policy> gamma; +// etc +`` + +So that when we use my_distributions::normal we really end up using +`boost::math::normal_distribution<double, my_policy>`: + +*/ + +int main() +{ + // Construct distribution with something we know will overflow + // (using double rather than if promoted to long double): + my_distributions::normal norm(10, 2); + + errno = 0; + cout << "Result of quantile(norm, 0) is: " + << quantile(norm, 0) << endl; // -infinity. + cout << "errno = " << errno << endl; + errno = 0; + cout << "Result of quantile(norm, 1) is: " + << quantile(norm, 1) << endl; // +infinity. + cout << "errno = " << errno << endl; + + // Now try a discrete distribution. + my_distributions::binomial binom(20, 0.25); + cout << "Result of quantile(binom, 0.05) is: " + << quantile(binom, 0.05) << endl; // To check we get integer results. + cout << "Result of quantile(complement(binom, 0.05)) is: " + << quantile(complement(binom, 0.05)) << endl; +} + +/*` + +Which outputs: + +[pre +Result of quantile(norm, 0) is: -1.#INF +errno = 34 +Result of quantile(norm, 1) is: 1.#INF +errno = 34 +Result of quantile(binom, 0.05) is: 1 +Result of quantile(complement(binom, 0.05)) is: 8 +] + +This mechanism is particularly useful when we want to define a +project-wide policy, and don't want to modify the Boost source +or set project wide build macros (possibly fragile and easy to forget). + +*/ +//] //[/policy_eg_6] + diff --git a/src/boost/libs/math/example/policy_eg_7.cpp b/src/boost/libs/math/example/policy_eg_7.cpp new file mode 100644 index 000000000..2865bea36 --- /dev/null +++ b/src/boost/libs/math/example/policy_eg_7.cpp @@ -0,0 +1,73 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +#include <iostream> +using std::cout; using std::endl; +#include <cerrno> // for ::errno + +//[policy_eg_7 + +#include <boost/math/distributions.hpp> // All distributions. +// using boost::math::normal; // Would create an ambiguity between +// boost::math::normal_distribution<RealType> boost::math::normal and +// 'anonymous-namespace'::normal'. + +namespace +{ // anonymous or unnamed (rather than named as in policy_eg_6.cpp). + + using namespace boost::math::policies; + // using boost::math::policies::errno_on_error; // etc. + typedef policy< + // return infinity and set errno rather than throw: + overflow_error<errno_on_error>, + // Don't promote double -> long double internally: + promote_double<false>, + // Return the closest integer result for discrete quantiles: + discrete_quantile<integer_round_nearest> + > my_policy; + + BOOST_MATH_DECLARE_DISTRIBUTIONS(double, my_policy) + +} // close namespace my_namespace + +int main() +{ + // Construct distribution with something we know will overflow. + normal norm(10, 2); // using 'anonymous-namespace'::normal + errno = 0; + cout << "Result of quantile(norm, 0) is: " + << quantile(norm, 0) << endl; + cout << "errno = " << errno << endl; + errno = 0; + cout << "Result of quantile(norm, 1) is: " + << quantile(norm, 1) << endl; + cout << "errno = " << errno << endl; + // + // Now try a discrete distribution: + binomial binom(20, 0.25); + cout << "Result of quantile(binom, 0.05) is: " + << quantile(binom, 0.05) << endl; + cout << "Result of quantile(complement(binom, 0.05)) is: " + << quantile(complement(binom, 0.05)) << endl; +} + +//] //[/policy_eg_7] + +/* + +Output: + + Result of quantile(norm, 0) is: -1.#INF + errno = 34 + Result of quantile(norm, 1) is: 1.#INF + errno = 34 + Result of quantile(binom, 0.05) is: 1 + Result of quantile(complement(binom, 0.05)) is: 8 + +*/ diff --git a/src/boost/libs/math/example/policy_eg_8.cpp b/src/boost/libs/math/example/policy_eg_8.cpp new file mode 100644 index 000000000..775f042e2 --- /dev/null +++ b/src/boost/libs/math/example/policy_eg_8.cpp @@ -0,0 +1,133 @@ +// Copyright John Maddock 2007. +// Copyright Paul a. Bristow 2010 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +#ifdef _MSC_VER +# pragma warning (disable : 4100) // unreferenced formal parameters +#endif + +#include <iostream> +using std::cout; using std::endl; using std::cerr; + +//[policy_eg_8 + +/*` +Suppose we want our own user-defined error handlers rather than the +any of the default ones supplied by the library to be used. +If we set the policy for a specific type of error to `user_error` +then the library will call a user-supplied error handler. +These are forward declared, but not defined in +boost/math/policies/error_handling.hpp like this: + + namespace boost{ namespace math{ namespace policies{ + + template <class T> + T user_domain_error(const char* function, const char* message, const T& val); + template <class T> + T user_pole_error(const char* function, const char* message, const T& val); + template <class T> + T user_overflow_error(const char* function, const char* message, const T& val); + template <class T> + T user_underflow_error(const char* function, const char* message, const T& val); + template <class T> + T user_denorm_error(const char* function, const char* message, const T& val); + template <class T> + T user_evaluation_error(const char* function, const char* message, const T& val); + template <class T, class TargetType> + T user_rounding_error(const char* function, const char* message, const T& val, const TargetType& t); + template <class T> + T user_indeterminate_result_error(const char* function, const char* message, const T& val); + + }}} // namespaces + +So out first job is to include the header we want to use, and then +provide definitions for our user-defined error handlers that we want to use. +We only provide our special domain and pole error handlers; +other errors like overflow and underflow use the default. +*/ + +#include <boost/math/special_functions.hpp> + +namespace boost{ namespace math +{ + namespace policies + { + template <class T> + T user_domain_error(const char* function, const char* message, const T& val) + { // Ignoring function, message and val for this example, perhaps unhelpfully. + cerr << "Domain Error!" << endl; + return std::numeric_limits<T>::quiet_NaN(); + } + + template <class T> + T user_pole_error(const char* function, const char* message, const T& val) + { // Ignoring function, message and val for this example, perhaps unhelpfully. + cerr << "Pole Error!" << endl; + return std::numeric_limits<T>::quiet_NaN(); + } + } // namespace policies +}} // namespace boost{ namespace math + + +/*` +Now we'll need to define a suitable policy that will call these handlers, +and define some forwarding functions that make use of the policy: +*/ + +namespace mymath{ + +using namespace boost::math::policies; + +typedef policy< + domain_error<user_error>, + pole_error<user_error> +> user_error_policy; + +BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(user_error_policy) + +} // close unnamed namespace + +/*` +We now have a set of forwarding functions defined in namespace mymath +that all look something like this: + +`` +template <class RealType> +inline typename boost::math::tools::promote_args<RT>::type + tgamma(RT z) +{ + return boost::math::tgamma(z, user_error_policy()); +} +`` + +So that when we call `mymath::tgamma(z)` we really end up calling +`boost::math::tgamma(z, user_error_policy())`, and any +errors will get directed to our own error handlers. +*/ + +int main() +{ + cout << "Result of erf_inv(-10) is: " + << mymath::erf_inv(-10) << endl; + cout << "Result of tgamma(-10) is: " + << mymath::tgamma(-10) << endl; +} + +/*` + +Which outputs: + +[pre + Domain Error! + Pole Error! + Result of erf_inv(-10) is: 1.#QNAN + Result of tgamma(-10) is: 1.#QNAN +] +*/ + +//] // //[/policy_eg_8] diff --git a/src/boost/libs/math/example/policy_eg_9.cpp b/src/boost/libs/math/example/policy_eg_9.cpp new file mode 100644 index 000000000..dceda875c --- /dev/null +++ b/src/boost/libs/math/example/policy_eg_9.cpp @@ -0,0 +1,313 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +#include <iostream> +#include <boost/format.hpp> +using std::cout; using std::endl; using std::cerr; + +//[policy_eg_9 + +/*` +The previous example was all well and good, but the custom error handlers +didn't really do much of any use. In this example we'll implement all +the custom handlers and show how the information provided to them can be +used to generate nice formatted error messages. + +Each error handler has the general form: + + template <class T> + T user_``['error_type]``( + const char* function, + const char* message, + const T& val); + +and accepts three arguments: + +[variablelist +[[const char* function] + [The name of the function that raised the error, this string + contains one or more %1% format specifiers that should be + replaced by the name of real type T, like float or double.]] +[[const char* message] + [A message associated with the error, normally this + contains a %1% format specifier that should be replaced with + the value of ['value]: however note that overflow and underflow messages + do not contain this %1% specifier (since the value of ['value] is + immaterial in these cases).]] +[[const T& value] + [The value that caused the error: either an argument to the function + if this is a domain or pole error, the tentative result + if this is a denorm or evaluation error, or zero or infinity for + underflow or overflow errors.]] +] + +As before we'll include the headers we need first: + +*/ + +#include <boost/math/special_functions.hpp> + +/*` +Next we'll implement our own error handlers for each type of error, +starting with domain errors: +*/ + +namespace boost{ namespace math{ +namespace policies +{ + +template <class T> +T user_domain_error(const char* function, const char* message, const T& val) +{ + /*` + We'll begin with a bit of defensive programming in case function or message are empty: + */ + if(function == 0) + function = "Unknown function with arguments of type %1%"; + if(message == 0) + message = "Cause unknown with bad argument %1%"; + /*` + Next we'll format the name of the function with the name of type T, perhaps double: + */ + std::string msg("Error in function "); + msg += (boost::format(function) % typeid(T).name()).str(); + /*` + Then likewise format the error message with the value of parameter /val/, + making sure we output all the potentially significant digits of /val/: + */ + msg += ": \n"; + int prec = 2 + (std::numeric_limits<T>::digits * 30103UL) / 100000UL; + // int prec = std::numeric_limits<T>::max_digits10; // For C++0X Standard Library + msg += (boost::format(message) % boost::io::group(std::setprecision(prec), val)).str(); + /*` + Now we just have to do something with the message, we could throw an + exception, but for the purposes of this example we'll just dump the message + to std::cerr: + */ + std::cerr << msg << std::endl; + /*` + Finally the only sensible value we can return from a domain error is a NaN: + */ + return std::numeric_limits<T>::quiet_NaN(); +} + +/*` +Pole errors are essentially a special case of domain errors, +so in this example we'll just return the result of a domain error: +*/ + +template <class T> +T user_pole_error(const char* function, const char* message, const T& val) +{ + return user_domain_error(function, message, val); +} + +/*` +Overflow errors are very similar to domain errors, except that there's +no %1% format specifier in the /message/ parameter: +*/ +template <class T> +T user_overflow_error(const char* function, const char* message, const T& val) +{ + if(function == 0) + function = "Unknown function with arguments of type %1%"; + if(message == 0) + message = "Result of function is too large to represent"; + + std::string msg("Error in function "); + msg += (boost::format(function) % typeid(T).name()).str(); + + msg += ": \n"; + msg += message; + + std::cerr << msg << std::endl; + + // Value passed to the function is an infinity, just return it: + return val; +} + +/*` +Underflow errors are much the same as overflow: +*/ + +template <class T> +T user_underflow_error(const char* function, const char* message, const T& val) +{ + if(function == 0) + function = "Unknown function with arguments of type %1%"; + if(message == 0) + message = "Result of function is too small to represent"; + + std::string msg("Error in function "); + msg += (boost::format(function) % typeid(T).name()).str(); + + msg += ": \n"; + msg += message; + + std::cerr << msg << std::endl; + + // Value passed to the function is zero, just return it: + return val; +} + +/*` +Denormalised results are much the same as underflow: +*/ + +template <class T> +T user_denorm_error(const char* function, const char* message, const T& val) +{ + if(function == 0) + function = "Unknown function with arguments of type %1%"; + if(message == 0) + message = "Result of function is denormalised"; + + std::string msg("Error in function "); + msg += (boost::format(function) % typeid(T).name()).str(); + + msg += ": \n"; + msg += message; + + std::cerr << msg << std::endl; + + // Value passed to the function is denormalised, just return it: + return val; +} + +/*` +Which leaves us with evaluation errors: these occur when an internal +error occurs that prevents the function being fully evaluated. +The parameter /val/ contains the closest approximation to the result +found so far: +*/ + +template <class T> +T user_evaluation_error(const char* function, const char* message, const T& val) +{ + if(function == 0) + function = "Unknown function with arguments of type %1%"; + if(message == 0) + message = "An internal evaluation error occurred with " + "the best value calculated so far of %1%"; + + std::string msg("Error in function "); + msg += (boost::format(function) % typeid(T).name()).str(); + + msg += ": \n"; + int prec = 2 + (std::numeric_limits<T>::digits * 30103UL) / 100000UL; + // int prec = std::numeric_limits<T>::max_digits10; // For C++0X Standard Library + msg += (boost::format(message) % boost::io::group(std::setprecision(prec), val)).str(); + + std::cerr << msg << std::endl; + + // What do we return here? This is generally a fatal error, that should never occur, + // so we just return a NaN for the purposes of the example: + return std::numeric_limits<T>::quiet_NaN(); +} + +} // policies +}} // boost::math + + +/*` +Now we'll need to define a suitable policy that will call these handlers, +and define some forwarding functions that make use of the policy: +*/ + +namespace mymath +{ // unnamed. + +using namespace boost::math::policies; + +typedef policy< + domain_error<user_error>, + pole_error<user_error>, + overflow_error<user_error>, + underflow_error<user_error>, + denorm_error<user_error>, + evaluation_error<user_error> +> user_error_policy; + +BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(user_error_policy) + +} // unnamed namespace + +/*` +We now have a set of forwarding functions, defined in namespace mymath, +that all look something like this: + +`` +template <class RealType> +inline typename boost::math::tools::promote_args<RT>::type + tgamma(RT z) +{ + return boost::math::tgamma(z, user_error_policy()); +} +`` + +So that when we call `mymath::tgamma(z)` we really end up calling +`boost::math::tgamma(z, user_error_policy())`, and any +errors will get directed to our own error handlers: +*/ + +int main() +{ + // Raise a domain error: + cout << "Result of erf_inv(-10) is: " + << mymath::erf_inv(-10) << std::endl << endl; + // Raise a pole error: + cout << "Result of tgamma(-10) is: " + << mymath::tgamma(-10) << std::endl << endl; + // Raise an overflow error: + cout << "Result of tgamma(3000) is: " + << mymath::tgamma(3000) << std::endl << endl; + // Raise an underflow error: + cout << "Result of tgamma(-190.5) is: " + << mymath::tgamma(-190.5) << std::endl << endl; + // Unfortunately we can't predictably raise a denormalised + // result, nor can we raise an evaluation error in this example + // since these should never really occur! +} // int main() + +/*` + +Which outputs: + +[pre +Error in function boost::math::erf_inv<double>(double, double): +Argument outside range \[-1, 1\] in inverse erf function (got p=-10). +Result of erf_inv(-10) is: 1.#QNAN + +Error in function boost::math::tgamma<long double>(long double): +Evaluation of tgamma at a negative integer -10. +Result of tgamma(-10) is: 1.#QNAN + +Error in function boost::math::tgamma<long double>(long double): +Result of tgamma is too large to represent. +Error in function boost::math::tgamma<double>(double): +Result of function is too large to represent +Result of tgamma(3000) is: 1.#INF + +Error in function boost::math::tgamma<long double>(long double): +Result of tgamma is too large to represent. +Error in function boost::math::tgamma<long double>(long double): +Result of tgamma is too small to represent. +Result of tgamma(-190.5) is: 0 +] + +Notice how some of the calls result in an error handler being called more +than once, or for more than one handler to be called: this is an artefact +of the fact that many functions are implemented in terms of one or more +sub-routines each of which may have it's own error handling. For example +`tgamma(-190.5)` is implemented in terms of `tgamma(190.5)` - which overflows - +the reflection formula for `tgamma` then notices that it is dividing by +infinity and so underflows. +*/ + +//] //[/policy_eg_9] diff --git a/src/boost/libs/math/example/policy_ref_snip1.cpp b/src/boost/libs/math/example/policy_ref_snip1.cpp new file mode 100644 index 000000000..217719395 --- /dev/null +++ b/src/boost/libs/math/example/policy_ref_snip1.cpp @@ -0,0 +1,75 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +//[policy_ref_snip1 + +#include <boost/math/special_functions/gamma.hpp> +using boost::math::tgamma; + +//using namespace boost::math::policies; may also be convenient. +using boost::math::policies::policy; +using boost::math::policies::evaluation_error; +using boost::math::policies::domain_error; +using boost::math::policies::overflow_error; +using boost::math::policies::domain_error; +using boost::math::policies::pole_error; +using boost::math::policies::errno_on_error; + +// Define a policy: +typedef policy< + domain_error<errno_on_error>, + pole_error<errno_on_error>, + overflow_error<errno_on_error>, + evaluation_error<errno_on_error> +> my_policy; + +double my_value = 0.; // + +// Call the function applying my_policy: +double t1 = tgamma(my_value, my_policy()); + +// Alternatively (and equivalently) we could use helpful function +// make_policy and define everything at the call site: +double t2 = tgamma(my_value, + make_policy( + domain_error<errno_on_error>(), + pole_error<errno_on_error>(), + overflow_error<errno_on_error>(), + evaluation_error<errno_on_error>() ) + ); +//] + +#include <iostream> +using std::cout; using std::endl; + +int main() +{ + cout << "my_value = " << my_value << endl; + try + { // First with default policy - throw an exception. + cout << "tgamma(my_value) = " << tgamma(my_value) << endl; + } + catch(const std::exception& e) + { + cout <<"\n""Message from thrown exception was:\n " << e.what() << endl; + } + + cout << "tgamma(my_value, my_policy() = " << t1 << endl; + cout << "tgamma(my_value, make_policy(domain_error<errno_on_error>(), pole_error<errno_on_error>(), overflow_error<errno_on_error>(), evaluation_error<errno_on_error>() ) = " << t2 << endl; +} + +/* +Output: + my_value = 0 + + Message from thrown exception was: + Error in function boost::math::tgamma<long double>(long double): Evaluation of tgamma at a negative integer 0. + tgamma(my_value, my_policy() = 1.#QNAN + tgamma(my_value, make_policy(domain_error<errno_on_error>(), pole_error<errno_on_error>(), overflow_error<errno_on_error>(), evaluation_error<errno_on_error>() ) = 1.#QNAN +*/ diff --git a/src/boost/libs/math/example/policy_ref_snip10.cpp b/src/boost/libs/math/example/policy_ref_snip10.cpp new file mode 100644 index 000000000..a4806dc6e --- /dev/null +++ b/src/boost/libs/math/example/policy_ref_snip10.cpp @@ -0,0 +1,40 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +// Setting precision in a single function call using make_policy. + +#include <iostream> +using std::cout; using std::endl; + +//[policy_ref_snip10 + +#include <boost/math/special_functions/gamma.hpp> +using boost::math::tgamma; + +using namespace boost::math::policies; + +double t = tgamma(12, policy<digits10<5> >()); // Concise make_policy. + +//] //[/policy_ref_snip10] + + + +int main() +{ + cout << "tgamma(12, policy<digits10<5> >()) = "<< t << endl; +} + +/* + +Output: + + tgamma(12, policy<digits10<5> >()) = 3.99168e+007 + +*/ + diff --git a/src/boost/libs/math/example/policy_ref_snip11.cpp b/src/boost/libs/math/example/policy_ref_snip11.cpp new file mode 100644 index 000000000..ea7c737c6 --- /dev/null +++ b/src/boost/libs/math/example/policy_ref_snip11.cpp @@ -0,0 +1,45 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +#include <iostream> +using std::cout; using std::endl; + +// Setting (approximate) precision 25 bits in a single function call using make_policy. + +//[policy_ref_snip11 + +#include <boost/math/distributions/normal.hpp> +using boost::math::normal_distribution; + +using namespace boost::math::policies; + +const int bits = 25; // approximate precision. + +double q = quantile( + normal_distribution<double, policy<digits2<bits> > >(), + 0.05); // 5% quantile. + +//] //[/policy_ref_snip11] + +int main() +{ + std::streamsize p = 2 + (bits * 30103UL) / 100000UL; + // Approximate number of significant decimal digits for 25 bits. + cout.precision(p); + cout << bits << " binary bits is approximately equivalent to " << p << " decimal digits " << endl; + cout << "quantile(normal_distribution<double, policy<digits2<25> > >(), 0.05 = " + << q << endl; // -1.64485 +} + +/* +Output: + 25 binary bits is approximately equivalent to 9 decimal digits + quantile(normal_distribution<double, policy<digits2<25> > >(), 0.05 = -1.64485363 + */ + diff --git a/src/boost/libs/math/example/policy_ref_snip12.cpp b/src/boost/libs/math/example/policy_ref_snip12.cpp new file mode 100644 index 000000000..e406ce561 --- /dev/null +++ b/src/boost/libs/math/example/policy_ref_snip12.cpp @@ -0,0 +1,55 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +// Define tgamma function with a no overflow policy +// into a specific namespace-scope. + +#include <iostream> +using std::cout; using std::endl; + +//[policy_ref_snip12 + +#include <boost/math/special_functions/gamma.hpp> +//using boost::math::tgamma; +// Need not declare using boost::math::tgamma here, +// because will define tgamma in myspace using macro below. + +namespace myspace +{ + using namespace boost::math::policies; + + // Define a policy that does not throw on overflow: + typedef policy<overflow_error<errno_on_error> > my_policy; + + // Define the special functions in this scope to use the policy: + BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(my_policy) +} + +// Now we can use myspace::tgamma etc. +// They will automatically use "my_policy": +// +double t = myspace::tgamma(30.0); // Will *not* throw on overflow, +// despite the large value of factorial 30 = 265252859812191058636308480000000 +// unlike default policy boost::math::tgamma; + +//] + +int main() +{ + cout << "myspace::tgamma(30.0) = " << t << endl; +} + +/* + +Output: + +myspace::tgamma(30.0) = 8.84176e+030 + +*/ + diff --git a/src/boost/libs/math/example/policy_ref_snip13.cpp b/src/boost/libs/math/example/policy_ref_snip13.cpp new file mode 100644 index 000000000..ce4b0948c --- /dev/null +++ b/src/boost/libs/math/example/policy_ref_snip13.cpp @@ -0,0 +1,81 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +#include <boost/config.hpp> +#ifdef _MSC_VER +# pragma warning (disable : 4189) // 'd' : local variable is initialized but not referenced +#endif +#ifdef BOOST_GCC +# pragma GCC diagnostic ignored "-Wunused-variable" +#endif + +#include <iostream> +using std::cout; using std::endl; + +#include <stdexcept> +using std::domain_error; + +//[policy_ref_snip13 + +#include <boost/math/distributions/cauchy.hpp> + +namespace myspace +{ // using namespace boost::math::policies; // May be convenient in myspace. + + // Define a policy called my_policy to use. + using boost::math::policies::policy; + +// In this case we want all the distribution accessor functions to compile, +// even if they are mathematically undefined, so +// make the policy assert_undefined. + using boost::math::policies::assert_undefined; + +typedef policy<assert_undefined<false> > my_policy; + +// Finally apply this policy to type double. +BOOST_MATH_DECLARE_DISTRIBUTIONS(double, my_policy) +} // namespace myspace + +// Now we can use myspace::cauchy etc, which will use policy +// myspace::mypolicy: +// +// This compiles but throws a domain error exception at runtime. +// Caution! If you omit the try'n'catch blocks, +// it will just silently terminate, giving no clues as to why! +// So try'n'catch blocks are very strongly recommended. + +void test_cauchy() +{ + try + { + double d = mean(myspace::cauchy()); // Cauchy does not have a mean! + (void) d; + } + catch(const std::domain_error& e) + { + cout << e.what() << endl; + } +} + +//] //[/policy_ref_snip13] + +int main() +{ + test_cauchy(); +} + +/* + +Output: + +policy_snip_13.vcxproj -> J:\Cpp\MathToolkit\test\Math_test\Release\policy_snip_13.exe + Error in function boost::math::mean(cauchy<double>&): The Cauchy distribution does not have a mean: the only possible return value is 1.#QNAN. + + */ + diff --git a/src/boost/libs/math/example/policy_ref_snip2.cpp b/src/boost/libs/math/example/policy_ref_snip2.cpp new file mode 100644 index 000000000..304250d4f --- /dev/null +++ b/src/boost/libs/math/example/policy_ref_snip2.cpp @@ -0,0 +1,47 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +#include <iostream> +using std::cout; using std::endl; + +//[policy_ref_snip2 + +#include <boost/math/distributions/normal.hpp> +using boost::math::normal_distribution; + +using namespace boost::math::policies; + +// Define a specific policy: +typedef policy< + overflow_error<ignore_error> + > my_policy; + +// Define the distribution, using my_policy: +typedef normal_distribution<double, my_policy> my_norm; + +// Construct a my_norm distribution, using default mean and standard deviation, +// and get a 0.05 or 5% quantile: +double q = quantile(my_norm(), 0.05); // = -1.64485 + +//] //[/policy_ref_snip2] + +int main() +{ + my_norm n; // Construct a my_norm distribution, + // using default mean zero and standard deviation unity. + double q = quantile(n, 0.05); // and get a quantile. + cout << "quantile(my_norm(), 0.05) = " << q << endl; +} + +/* + +Output: + + quantile(my_norm(), 0.05) = -1.64485 +*/ diff --git a/src/boost/libs/math/example/policy_ref_snip3.cpp b/src/boost/libs/math/example/policy_ref_snip3.cpp new file mode 100644 index 000000000..b3820ad30 --- /dev/null +++ b/src/boost/libs/math/example/policy_ref_snip3.cpp @@ -0,0 +1,40 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +double some_value = 2.; + +//[policy_ref_snip3 + +#include <boost/math/special_functions/gamma.hpp> + +using namespace boost::math::policies; +using boost::math::tgamma; + +// Define a new policy *not* internally promoting RealType to double: +typedef policy< + promote_double<false> + > my_policy; + +// Call the function, applying the new policy: +double t1 = tgamma(some_value, my_policy()); + +// Alternatively we could use helper function make_policy, +// and concisely define everything at the call site: +double t2 = tgamma(some_value, make_policy(promote_double<false>())); + +//] //[\policy_ref_snip3] + +#include <iostream> +using std::cout; using std::endl; + +int main() +{ + cout << "tgamma(some_value, my_policy()) = " << t1 + << ", tgamma(some_value, make_policy(promote_double<false>()) = " << t2 << endl; +} diff --git a/src/boost/libs/math/example/policy_ref_snip4.cpp b/src/boost/libs/math/example/policy_ref_snip4.cpp new file mode 100644 index 000000000..7df35be1c --- /dev/null +++ b/src/boost/libs/math/example/policy_ref_snip4.cpp @@ -0,0 +1,41 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +#ifdef _MSC_VER +# pragma warning (disable : 4305) // 'initializing' : truncation from 'long double' to 'const eval_type' +# pragma warning (disable : 4244) // 'conversion' : truncation from 'long double' to 'const eval_type' +#endif + +//[policy_ref_snip4 + +#include <boost/math/distributions/normal.hpp> +using boost::math::normal_distribution; + +using namespace boost::math::policies; + +// Define a policy: +typedef policy< + promote_float<false> + > my_policy; + +// Define the new normal distribution using my_policy: +typedef normal_distribution<float, my_policy> my_norm; + +// Get a quantile: +float q = quantile(my_norm(), 0.05f); + +//] [policy_ref_snip4] + +#include <iostream> +using std::cout; using std::endl; + +int main() +{ + cout << " quantile(my_norm(), 0.05f) = " << q << endl; // -1.64485 +} diff --git a/src/boost/libs/math/example/policy_ref_snip5.cpp b/src/boost/libs/math/example/policy_ref_snip5.cpp new file mode 100644 index 000000000..06f270af4 --- /dev/null +++ b/src/boost/libs/math/example/policy_ref_snip5.cpp @@ -0,0 +1,45 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +//[policy_ref_snip5 + +#include <boost/math/distributions/negative_binomial.hpp> +using boost::math::negative_binomial_distribution; + +using namespace boost::math::policies; + +typedef negative_binomial_distribution< + double, + policy<discrete_quantile<real> > + > dist_type; + +// Lower 5% quantile: +double x = quantile(dist_type(20, 0.3), 0.05); +// Upper 95% quantile: +double y = quantile(complement(dist_type(20, 0.3), 0.05)); + +//] //[/policy_ref_snip5] + +#include <iostream> +using std::cout; using std::endl; + +int main() +{ + cout << "quantile(dist_type(20, 0.3), 0.05) = " << x + << "\nquantile(complement(dist_type(20, 0.3), 0.05) = " << y << endl; +} + +/* + +Output: + quantile(dist_type(20, 0.3), 0.05) = 27.3898 + quantile(complement(dist_type(20, 0.3), 0.05) = 68.1584 + + */ + diff --git a/src/boost/libs/math/example/policy_ref_snip6.cpp b/src/boost/libs/math/example/policy_ref_snip6.cpp new file mode 100644 index 000000000..9dc207297 --- /dev/null +++ b/src/boost/libs/math/example/policy_ref_snip6.cpp @@ -0,0 +1,38 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +//[policy_ref_snip6 + +#include <boost/math/distributions/negative_binomial.hpp> +using boost::math::negative_binomial; + +// Use the default rounding policy integer_round_outwards. +// Lower quantile rounded down: +double x = quantile(negative_binomial(20, 0.3), 0.05); // rounded up 27 from 27.3898 +// Upper quantile rounded up: +double y = quantile(complement(negative_binomial(20, 0.3), 0.05)); // rounded down to 69 from 68.1584 + +//] //[/policy_ref_snip6] + +#include <iostream> +using std::cout; using std::endl; + +int main() +{ + cout << "quantile(negative_binomial(20, 0.3), 0.05) = "<< x <<endl + << "quantile(complement(negative_binomial(20, 0.3), 0.05)) = " << y << endl; +} + +/* +Output: + + quantile(negative_binomial(20, 0.3), 0.05) = 27 + quantile(complement(negative_binomial(20, 0.3), 0.05)) = 69 +*/ + diff --git a/src/boost/libs/math/example/policy_ref_snip7.cpp b/src/boost/libs/math/example/policy_ref_snip7.cpp new file mode 100644 index 000000000..004205b01 --- /dev/null +++ b/src/boost/libs/math/example/policy_ref_snip7.cpp @@ -0,0 +1,48 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +//[policy_ref_snip7 + +#include <boost/math/distributions/negative_binomial.hpp> +using boost::math::negative_binomial_distribution; + +using namespace boost::math::policies; + +typedef negative_binomial_distribution< + double, + policy<discrete_quantile<integer_round_inwards> > + > dist_type; + +// Lower quantile rounded up: +double x = quantile(dist_type(20, 0.3), 0.05); // 28 rounded up from 27.3898 +// Upper quantile rounded down: +double y = quantile(complement(dist_type(20, 0.3), 0.05)); // 68 rounded down from 68.1584 + +//] //[/policy_ref_snip7] + +#include <iostream> +using std::cout; using std::endl; + +int main() +{ + cout << "using policy<discrete_quantile<integer_round_inwards> > " << endl + << "quantile(dist_type(20, 0.3), 0.05) = " << x << endl + << "quantile(complement(dist_type(20, 0.3), 0.05)) = " << y << endl; +} + +/* + +Output: + using policy<discrete_quantile<integer_round_inwards> > + quantile(dist_type(20, 0.3), 0.05) = 28 + quantile(complement(dist_type(20, 0.3), 0.05)) = 68 + + +*/ + diff --git a/src/boost/libs/math/example/policy_ref_snip8.cpp b/src/boost/libs/math/example/policy_ref_snip8.cpp new file mode 100644 index 000000000..abc48b9ae --- /dev/null +++ b/src/boost/libs/math/example/policy_ref_snip8.cpp @@ -0,0 +1,47 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +//[policy_ref_snip8 + +#include <boost/math/distributions/negative_binomial.hpp> +using boost::math::negative_binomial_distribution; + +using namespace boost::math::policies; + +typedef negative_binomial_distribution< + double, + policy<discrete_quantile<integer_round_nearest> > + > dist_type; + +// Lower quantile rounded (down) to nearest: +double x = quantile(dist_type(20, 0.3), 0.05); // 27 +// Upper quantile rounded (down) to nearest: +double y = quantile(complement(dist_type(20, 0.3), 0.05)); // 68 + +//] //[/policy_ref_snip8] + +#include <iostream> +using std::cout; using std::endl; + +int main() +{ + cout << "using policy<discrete_quantile<integer_round_nearest> " << endl + << "quantile(dist_type(20, 0.3), 0.05) = " << x << endl + << "quantile(complement(dist_type(20, 0.3), 0.05)) " << y << endl; +} + +/* + +Output: + + using policy<discrete_quantile<integer_round_nearest> + quantile(dist_type(20, 0.3), 0.05) = 27 + quantile(complement(dist_type(20, 0.3), 0.05)) 68 + +*/ diff --git a/src/boost/libs/math/example/policy_ref_snip9.cpp b/src/boost/libs/math/example/policy_ref_snip9.cpp new file mode 100644 index 000000000..ed38d4601 --- /dev/null +++ b/src/boost/libs/math/example/policy_ref_snip9.cpp @@ -0,0 +1,36 @@ +// Copyright John Maddock 2007. +// Copyright Paul A. Bristow 2010 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +#include <iostream> +using std::cout; using std::endl; + +//[policy_ref_snip9 + +#include <boost/math/special_functions/gamma.hpp> +using boost::math::tgamma; +using boost::math::policies::policy; +using boost::math::policies::digits10; + +typedef policy<digits10<5> > my_pol_5; // Define a new, non-default, policy +// to calculate tgamma to accuracy of approximately 5 decimal digits. +//] + +int main() +{ + cout.precision(5); // To only show 5 (hopefully) accurate decimal digits. + double t = tgamma(12, my_pol_5()); // Apply the 5 decimal digits accuracy policy to use of tgamma. + cout << "tgamma(12, my_pol_5() = " << t << endl; +} + +/* + +Output: + tgamma(12, my_pol_5() = 3.9917e+007 +*/ diff --git a/src/boost/libs/math/example/polynomial_arithmetic.cpp b/src/boost/libs/math/example/polynomial_arithmetic.cpp new file mode 100644 index 000000000..78efd06d0 --- /dev/null +++ b/src/boost/libs/math/example/polynomial_arithmetic.cpp @@ -0,0 +1,237 @@ +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Copyright Jeremy W. Murphy 2015. + +// This file is written to be included from a Quickbook .qbk document. +// It can be compiled by the C++ compiler, and run. Any output can +// also be added here as comment or included or pasted in elsewhere. +// Caution: this file contains Quickbook markup as well as code +// and comments: don't change any of the special comment markups! + +//[polynomial_arithmetic_0 +/*`First include the essential polynomial header (and others) to make the example: +*/ +#include <boost/math/tools/polynomial.hpp> +//] [polynomial_arithmetic_0 + +#include <boost/array.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/assert.hpp> + +#include <iostream> +#include <stdexcept> +#include <cmath> +#include <string> +#include <utility> + +//[polynomial_arithmetic_1 +/*`and some using statements are convenient: +*/ + +using std::string; +using std::exception; +using std::cout; +using std::abs; +using std::pair; + +using namespace boost::math; +using namespace boost::math::tools; // for polynomial +using boost::lexical_cast; + +//] [/polynomial_arithmetic_1] + +template <typename T> +string sign_str(T const &x) +{ + return x < 0 ? "-" : "+"; +} + +template <typename T> +string inner_coefficient(T const &x) +{ + string result(" " + sign_str(x) + " "); + if (abs(x) != T(1)) + result += lexical_cast<string>(abs(x)); + return result; +} + +/*! Output in formula format. +For example: from a polynomial in Boost container storage [ 10, -6, -4, 3 ] +show as human-friendly formula notation: 3x^3 - 4x^2 - 6x + 10. +*/ +template <typename T> +string formula_format(polynomial<T> const &a) +{ + string result; + if (a.size() == 0) + result += lexical_cast<string>(T(0)); + else + { + // First one is a special case as it may need unary negate. + unsigned i = a.size() - 1; + if (a[i] < 0) + result += "-"; + if (abs(a[i]) != T(1)) + result += lexical_cast<string>(abs(a[i])); + + if (i > 0) + { + result += "x"; + if (i > 1) + { + result += "^" + lexical_cast<string>(i); + i--; + for (; i != 1; i--) + if (a[i]) + result += inner_coefficient(a[i]) + "x^" + lexical_cast<string>(i); + + if (a[i]) + result += inner_coefficient(a[i]) + "x"; + } + i--; + + if (a[i]) + result += " " + sign_str(a[i]) + " " + lexical_cast<string>(abs(a[i])); + } + } + return result; +} // string formula_format(polynomial<T> const &a) + + +int main() +{ + cout << "Example: Polynomial arithmetic.\n\n"; + + try + { +//[polynomial_arithmetic_2 +/*`Store the coefficients in a convenient way to access them, +then create some polynomials using construction from an iterator range, +and finally output in a 'pretty' formula format. + +[tip Although we might conventionally write a polynomial from left to right +in descending order of degree, Boost.Math stores in [*ascending order of degree].] + + Read/write for humans: 3x^3 - 4x^2 - 6x + 10 + Boost polynomial storage: [ 10, -6, -4, 3 ] +*/ + boost::array<double, 4> const d3a = {{10, -6, -4, 3}}; + polynomial<double> const a(d3a.begin(), d3a.end()); + + // With C++11 and later, you can also use initializer_list construction. + polynomial<double> const b{{-2.0, 1.0}}; + + // formula_format() converts from Boost storage to human notation. + cout << "a = " << formula_format(a) + << "\nb = " << formula_format(b) << "\n\n"; + +//] [/polynomial_arithmetic_2] + +//[polynomial_arithmetic_3 + // Now we can do arithmetic with the usual infix operators: + - * / and %. + polynomial<double> s = a + b; + cout << "a + b = " << formula_format(s) << "\n"; + polynomial<double> d = a - b; + cout << "a - b = " << formula_format(d) << "\n"; + polynomial<double> p = a * b; + cout << "a * b = " << formula_format(p) << "\n"; + polynomial<double> q = a / b; + cout << "a / b = " << formula_format(q) << "\n"; + polynomial<double> r = a % b; + cout << "a % b = " << formula_format(r) << "\n"; +//] [/polynomial_arithmetic_3] + +//[polynomial_arithmetic_4 +/*` +Division is a special case where you can calculate two for the price of one. + +Actually, quotient and remainder are always calculated together due to the nature +of the algorithm: the infix operators return one result and throw the other +away. + +If you are doing a lot of division and want both the quotient and remainder, then +you don't want to do twice the work necessary. + +In that case you can call the underlying function, [^quotient_remainder], +to get both results together as a pair. +*/ + pair< polynomial<double>, polynomial<double> > result; + result = quotient_remainder(a, b); +// Reassure ourselves that the result is the same. + BOOST_ASSERT(result.first == q); + BOOST_ASSERT(result.second == r); +//] [/polynomial_arithmetic_4] +//[polynomial_arithmetic_5 + /* +We can use the right and left shift operators to add and remove a factor of x. +This has the same semantics as left and right shift for integers where it is a +factor of 2. x is the smallest prime factor of a polynomial as is 2 for integers. +*/ + cout << "Right and left shift operators.\n"; + cout << "\n" << formula_format(p) << "\n"; + cout << "... right shift by 1 ...\n"; + p >>= 1; + cout << formula_format(p) << "\n"; + cout << "... left shift by 2 ...\n"; + p <<= 2; + cout << formula_format(p) << "\n"; + +/* +We can also give a meaning to odd and even for a polynomial that is consistent +with these operations: a polynomial is odd if it has a non-zero constant value, +even otherwise. That is: + x^2 + 1 odd + x^2 even + */ + cout << std::boolalpha; + cout << "\nPrint whether a polynomial is odd.\n"; + cout << formula_format(s) << " odd? " << odd(s) << "\n"; + // We cheekily use the internal details to subtract the constant, making it even. + s -= s.data().front(); + cout << formula_format(s) << " odd? " << odd(s) << "\n"; + // And of course you can check if it is even: + cout << formula_format(s) << " even? " << even(s) << "\n"; + + + //] [/polynomial_arithmetic_5] + //[polynomial_arithmetic_6] + /* For performance and convenience, we can test whether a polynomial is zero + * by implicitly converting to bool with the same semantics as int. */ + polynomial<double> zero; // Default construction is 0. + cout << "zero: " << (zero ? "not zero" : "zero") << "\n"; + cout << "r: " << (r ? "not zero" : "zero") << "\n"; + /* We can also set a polynomial to zero without needing a another zero + * polynomial to assign to it. */ + r.set_zero(); + cout << "r: " << (r ? "not zero" : "zero") << "\n"; + //] [/polynomial_arithmetic_6] +} +catch (exception const &e) +{ + cout << "\nMessage from thrown exception was:\n " << e.what() << "\n"; +} +} // int main() + +/* +//[polynomial_output_1 + +a = 3x^3 - 4x^2 - 6x + 10 +b = x - 2 + +//] [/polynomial_output_1] + + +//[polynomial_output_2 + +a + b = 3x^3 - 4x^2 - 5x + 8 +a - b = 3x^3 - 4x^2 - 7x + 12 +a * b = 3x^4 - 10x^3 + 2x^2 + 22x - 20 +a / b = 3x^2 + 2x - 2 +a % b = 6 + +//] [/polynomial_output_2] + +*/ diff --git a/src/boost/libs/math/example/root_elliptic_finding.cpp b/src/boost/libs/math/example/root_elliptic_finding.cpp new file mode 100644 index 000000000..9a7e0c345 --- /dev/null +++ b/src/boost/libs/math/example/root_elliptic_finding.cpp @@ -0,0 +1,878 @@ +// Copyright Paul A. Bristow 2015 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Comparison of finding roots using TOMS748, Newton-Raphson, Halley & Schroder algorithms. +// root_n_finding_algorithms.cpp Generalised for nth root version. + +// http://en.wikipedia.org/wiki/Cube_root + +// Note that this file contains Quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! +// This program also writes files in Quickbook tables mark-up format. + +#include <boost/cstdlib.hpp> +#include <boost/config.hpp> +#include <boost/array.hpp> +#include <boost/type_traits/is_floating_point.hpp> +#include <boost/math/tools/roots.hpp> +#include <boost/math/special_functions/ellint_1.hpp> +#include <boost/math/special_functions/ellint_2.hpp> + +//using boost::math::policies::policy; +//using boost::math::tools::eps_tolerance; // Binary functor for specified number of bits. +//using boost::math::tools::bracket_and_solve_root; +//using boost::math::tools::toms748_solve; +//using boost::math::tools::halley_iterate; +//using boost::math::tools::newton_raphson_iterate; +//using boost::math::tools::schroder_iterate; + +#include <boost/math/special_functions/next.hpp> // For float_distance. + +#include <boost/multiprecision/cpp_bin_float.hpp> // is binary. +using boost::multiprecision::cpp_bin_float_100; +using boost::multiprecision::cpp_bin_float_50; + +#include <boost/timer/timer.hpp> +#include <boost/system/error_code.hpp> +#include <boost/preprocessor/stringize.hpp> + +// STL +#include <iostream> +#include <iomanip> +#include <string> +#include <vector> +#include <limits> +#include <fstream> // std::ofstream +#include <cmath> +#include <typeinfo> // for type name using typid(thingy).name(); + +#ifdef __FILE__ + std::string sourcefilename = __FILE__; +#else + std::string sourcefilename(""); +#endif + + std::string chop_last(std::string s) + { + std::string::size_type pos = s.find_last_of("\\/"); + if(pos != std::string::npos) + s.erase(pos); + else if(s.empty()) + abort(); + else + s.erase(); + return s; + } + + std::string make_root() + { + std::string result; + if(sourcefilename.find_first_of(":") != std::string::npos) + { + result = chop_last(sourcefilename); // lose filename part + result = chop_last(result); // lose /example/ + result = chop_last(result); // lose /math/ + result = chop_last(result); // lose /libs/ + } + else + { + result = chop_last(sourcefilename); // lose filename part + if(result.empty()) + result = "."; + result += "/../../.."; + } + return result; + } + + std::string short_file_name(std::string s) + { + std::string::size_type pos = s.find_last_of("\\/"); + if(pos != std::string::npos) + s.erase(0, pos + 1); + return s; + } + + std::string boost_root = make_root(); + + +std::string fp_hardware; // Any hardware features like SEE or AVX + +const std::string roots_name = "libs/math/doc/roots/"; + +const std::string full_roots_name(boost_root + "/libs/math/doc/roots/"); + +const std::size_t nooftypes = 4; +const std::size_t noofalgos = 4; + +double digits_accuracy = 1.0; // 1 == maximum possible accuracy. + +std::stringstream ss; + +std::ofstream fout; + +std::vector<std::string> algo_names = +{ + "TOMS748", "Newton", "Halley", "Schr'''ö'''der" +}; + +std::vector<std::string> names = +{ + "float", "double", "long double", "cpp_bin_float50" +}; + +uintmax_t iters; // Global as value of iterations is not returned. + +struct root_info +{ // for a floating-point type, float, double ... + std::size_t max_digits10; // for type. + std::string full_typename; // for type from type_id.name(). + std::string short_typename; // for type "float", "double", "cpp_bin_float_50" .... + std::size_t bin_digits; // binary in floating-point type numeric_limits<T>::digits; + int get_digits; // fraction of maximum possible accuracy required. + // = digits * digits_accuracy + // Vector of values (4) for each algorithm, TOMS748, Newton, Halley & Schroder. + //std::vector< boost::int_least64_t> times; converted to int. + std::vector<int> times; // arbitrary units (ticks). + //boost::int_least64_t min_time = std::numeric_limits<boost::int_least64_t>::max(); // Used to normalize times (as int). + std::vector<double> normed_times; + int min_time = (std::numeric_limits<int>::max)(); // Used to normalize times. + std::vector<uintmax_t> iterations; + std::vector<long int> distances; + std::vector<cpp_bin_float_100> full_results; +}; // struct root_info + +std::vector<root_info> root_infos; // One element for each floating-point type used. + +inline std::string build_test_name(const char* type_name, const char* test_name) +{ + std::string result(BOOST_COMPILER); + result += "|"; + result += BOOST_STDLIB; + result += "|"; + result += BOOST_PLATFORM; + result += "|"; + result += type_name; + result += "|"; + result += test_name; +#if defined(_DEBUG) || !defined(NDEBUG) + result += "|"; + result += " debug"; +#else + result += "|"; + result += " release"; +#endif + result += "|"; + return result; +} // std::string build_test_name + +// Algorithms ////////////////////////////////////////////// + +// No derivatives - using TOMS748 internally. +//[elliptic_noderv_func +template <typename T = double> +struct elliptic_root_functor_noderiv +{ // Nth root of x using only function - no derivatives. + elliptic_root_functor_noderiv(T const& arc, T const& radius) : m_arc(arc), m_radius(radius) + { // Constructor just stores value a to find root of. + } + T operator()(T const& x) + { + using std::sqrt; + // return the difference between required arc-length, and the calculated arc-length for an + // ellipse with radii m_radius and x: + T a = (std::max)(m_radius, x); + T b = (std::min)(m_radius, x); + T k = sqrt(1 - b * b / (a * a)); + return 4 * a * boost::math::ellint_2(k) - m_arc; + } +private: + T m_arc; // length of arc. + T m_radius; // one of the two radii of the ellipse +}; // template <class T> struct elliptic_root_functor_noderiv +//] +//[elliptic_root_noderiv +template <class T = double> +T elliptic_root_noderiv(T radius, T arc) +{ // return the other radius of an ellipse, given one radii and the arc-length + using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; // For bracket_and_solve_root. + + T guess = sqrt(arc * arc / 16 - radius * radius); + T factor = 1.2; // How big steps to take when searching. + + const boost::uintmax_t maxit = 50; // Limit to maximum iterations. + boost::uintmax_t it = maxit; // Initially our chosen max iterations, but updated with actual. + bool is_rising = true; // arc-length increases if one radii increases, so function is rising + // Define a termination condition, stop when nearly all digits are correct, but allow for + // the fact that we are returning a range, and must have some inaccuracy in the elliptic integral: + eps_tolerance<T> tol(std::numeric_limits<T>::digits - 2); + // Call bracket_and_solve_root to find the solution, note that this is a rising function: + std::pair<T, T> r = bracket_and_solve_root(elliptic_root_functor_noderiv<T>(arc, radius), guess, factor, is_rising, tol, it); + //<- + iters = it; + //-> + // Result is midway between the endpoints of the range: + return r.first + (r.second - r.first) / 2; +} // template <class T> T elliptic_root_noderiv(T x) +//] +// Using 1st derivative only Newton-Raphson +//[elliptic_1deriv_func +template <class T = double> +struct elliptic_root_functor_1deriv +{ // Functor also returning 1st derivative. + BOOST_STATIC_ASSERT_MSG(boost::is_integral<T>::value == false, "Only floating-point type types can be used!"); + + elliptic_root_functor_1deriv(T const& arc, T const& radius) : m_arc(arc), m_radius(radius) + { // Constructor just stores value a to find root of. + } + std::pair<T, T> operator()(T const& x) + { + using std::sqrt; + // Return the difference between required arc-length, and the calculated arc-length for an + // ellipse with radii m_radius and x, plus it's derivative. + // See http://www.wolframalpha.com/input/?i=d%2Fda+[4+*+a+*+EllipticE%281+-+b^2%2Fa^2%29] + // We require two elliptic integral calls, but from these we can calculate both + // the function and it's derivative: + T a = (std::max)(m_radius, x); + T b = (std::min)(m_radius, x); + T a2 = a * a; + T b2 = b * b; + T k = sqrt(1 - b2 / a2); + T Ek = boost::math::ellint_2(k); + T Kk = boost::math::ellint_1(k); + T fx = 4 * a * Ek - m_arc; + T dfx = 4 * (a2 * Ek - b2 * Kk) / (a2 - b2); + return std::make_pair(fx, dfx); + } +private: + T m_arc; // length of arc. + T m_radius; // one of the two radii of the ellipse +}; // struct elliptic_root__functor_1deriv +//] +//[elliptic_1deriv +template <class T = double> +T elliptic_root_1deriv(T radius, T arc) +{ + using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; // For newton_raphson_iterate. + + BOOST_STATIC_ASSERT_MSG(boost::is_integral<T>::value == false, "Only floating-point type types can be used!"); + + T guess = sqrt(arc * arc / 16 - radius * radius); + T min = 0; // Minimum possible value is zero. + T max = arc; // Maximum possible value is the arc length. + + // Accuracy doubles at each step, so stop when just over half of the digits are + // correct, and rely on that step to polish off the remainder: + int get_digits = static_cast<int>(std::numeric_limits<T>::digits * 0.6); + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + T result = newton_raphson_iterate(elliptic_root_functor_1deriv<T>(arc, radius), guess, min, max, get_digits, it); + //<- + iters = it; + //-> + return result; +} // T elliptic_root_1_deriv Newton-Raphson +//] + +// Using 1st and 2nd derivatives with Halley algorithm. +//[elliptic_2deriv_func +template <class T = double> +struct elliptic_root_functor_2deriv +{ // Functor returning both 1st and 2nd derivatives. + BOOST_STATIC_ASSERT_MSG(boost::is_integral<T>::value == false, "Only floating-point type types can be used!"); + + elliptic_root_functor_2deriv(T const& arc, T const& radius) : m_arc(arc), m_radius(radius) {} + std::tuple<T, T, T> operator()(T const& x) + { + using std::sqrt; + // Return the difference between required arc-length, and the calculated arc-length for an + // ellipse with radii m_radius and x, plus it's derivative. + // See http://www.wolframalpha.com/input/?i=d^2%2Fda^2+[4+*+a+*+EllipticE%281+-+b^2%2Fa^2%29] + // for the second derivative. + T a = (std::max)(m_radius, x); + T b = (std::min)(m_radius, x); + T a2 = a * a; + T b2 = b * b; + T k = sqrt(1 - b2 / a2); + T Ek = boost::math::ellint_2(k); + T Kk = boost::math::ellint_1(k); + T fx = 4 * a * Ek - m_arc; + T dfx = 4 * (a2 * Ek - b2 * Kk) / (a2 - b2); + T dfx2 = 4 * b2 * ((a2 + b2) * Kk - 2 * a2 * Ek) / (a * (a2 - b2) * (a2 - b2)); + return std::make_tuple(fx, dfx, dfx2); + } +private: + T m_arc; // length of arc. + T m_radius; // one of the two radii of the ellipse +}; +//] +//[elliptic_2deriv +template <class T = double> +T elliptic_root_2deriv(T radius, T arc) +{ + using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; // For halley_iterate. + + BOOST_STATIC_ASSERT_MSG(boost::is_integral<T>::value == false, "Only floating-point type types can be used!"); + + T guess = sqrt(arc * arc / 16 - radius * radius); + T min = 0; // Minimum possible value is zero. + T max = arc; // radius can't be larger than the arc length. + + // Accuracy triples at each step, so stop when just over one-third of the digits + // are correct, and the last iteration will polish off the remaining digits: + int get_digits = static_cast<int>(std::numeric_limits<T>::digits * 0.4); + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + T result = halley_iterate(elliptic_root_functor_2deriv<T>(arc, radius), guess, min, max, get_digits, it); + //<- + iters = it; + //-> + return result; +} // nth_2deriv Halley +//] +// Using 1st and 2nd derivatives using Schroder algorithm. + +template <class T = double> +T elliptic_root_2deriv_s(T arc, T radius) +{ // return nth root of x using 1st and 2nd derivatives and Schroder. + + using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; // For schroder_iterate. + + BOOST_STATIC_ASSERT_MSG(boost::is_integral<T>::value == false, "Only floating-point type types can be used!"); + + T guess = sqrt(arc * arc / 16 - radius * radius); + T min = 0; // Minimum possible value is zero. + T max = arc; // radius can't be larger than the arc length. + + int digits = std::numeric_limits<T>::digits; // Maximum possible binary digits accuracy for type T. + int get_digits = static_cast<int>(digits * digits_accuracy); + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + T result = schroder_iterate(elliptic_root_functor_2deriv<T>(arc, radius), guess, min, max, get_digits, it); + iters = it; + + return result; +} // T elliptic_root_2deriv_s Schroder + +//////////////////////////////////////////////////////// end of algorithms - perhaps in a separate .hpp? + +//! Print 4 floating-point types info: max_digits10, digits and required accuracy digits as a Quickbook table. +int table_type_info(double digits_accuracy) +{ + std::string qbk_name = full_roots_name; // Prefix by boost_root file. + + qbk_name += "type_info_table"; + std::stringstream ss; + ss.precision(3); + ss << "_" << digits_accuracy * 100; + qbk_name += ss.str(); + +#ifdef _MSC_VER + qbk_name += "_msvc.qbk"; +#else // assume GCC + qbk_name += "_gcc.qbk"; +#endif + + // Example: type_info_table_100_msvc.qbk + fout.open(qbk_name, std::ios_base::out); + + if (fout.is_open()) + { + std::cout << "Output type table to " << qbk_name << std::endl; + } + else + { // Failed to open. + std::cout << " Open file " << qbk_name << " for output failed!" << std::endl; + std::cout << "errno " << errno << std::endl; + return errno; + } + + fout << + "[/" + << qbk_name + << "\n" + "Copyright 2015 Paul A. Bristow.""\n" + "Copyright 2015 John Maddock.""\n" + "Distributed under the Boost Software License, Version 1.0.""\n" + "(See accompanying file LICENSE_1_0.txt or copy at""\n" + "http://www.boost.org/LICENSE_1_0.txt).""\n" + "]""\n" + << std::endl; + + fout << "[h6 Fraction of maximum possible bits of accuracy required is " << digits_accuracy << ".]\n" << std::endl; + + std::string table_id("type_info"); + table_id += ss.str(); // Fraction digits accuracy. + +#ifdef _MSC_VER + table_id += "_msvc"; +#else // assume GCC + table_id += "_gcc"; +#endif + + fout << "[table:" << table_id << " Digits for float, double, long double and cpp_bin_float_50\n" + << "[[type name] [max_digits10] [binary digits] [required digits]]\n";// header. + + // For all fout types: + + fout << "[[" << "float" << "]" + << "[" << std::numeric_limits<float>::max_digits10 << "]" // max_digits10 + << "[" << std::numeric_limits<float>::digits << "]"// < "Binary digits + << "[" << static_cast<int>(std::numeric_limits<float>::digits * digits_accuracy) << "]]\n"; // Accuracy digits. + + fout << "[[" << "float" << "]" + << "[" << std::numeric_limits<double>::max_digits10 << "]" // max_digits10 + << "[" << std::numeric_limits<double>::digits << "]"// < "Binary digits + << "[" << static_cast<int>(std::numeric_limits<double>::digits * digits_accuracy) << "]]\n"; // Accuracy digits. + + fout << "[[" << "long double" << "]" + << "[" << std::numeric_limits<long double>::max_digits10 << "]" // max_digits10 + << "[" << std::numeric_limits<long double>::digits << "]"// < "Binary digits + << "[" << static_cast<int>(std::numeric_limits<long double>::digits * digits_accuracy) << "]]\n"; // Accuracy digits. + + fout << "[[" << "cpp_bin_float_50" << "]" + << "[" << std::numeric_limits<cpp_bin_float_50>::max_digits10 << "]" // max_digits10 + << "[" << std::numeric_limits<cpp_bin_float_50>::digits << "]"// < "Binary digits + << "[" << static_cast<int>(std::numeric_limits<cpp_bin_float_50>::digits * digits_accuracy) << "]]\n"; // Accuracy digits. + + fout << "] [/table table_id_msvc] \n" << std::endl; // End of table. + + fout.close(); + return 0; +} // type_table + +//! Evaluate root N timing for each algorithm, and for one floating-point type T. +template <typename T> +int test_root(cpp_bin_float_100 big_radius, cpp_bin_float_100 big_arc, cpp_bin_float_100 answer, const char* type_name, std::size_t type_no) +{ + std::size_t max_digits = 2 + std::numeric_limits<T>::digits * 3010 / 10000; + // For new versions use max_digits10 + // std::cout.precision(std::numeric_limits<T>::max_digits10); + std::cout.precision(max_digits); + std::cout << std::showpoint << std::endl; // Show trailing zeros too. + + root_infos.push_back(root_info()); + + root_infos[type_no].max_digits10 = max_digits; + root_infos[type_no].full_typename = typeid(T).name(); // Full typename. + root_infos[type_no].short_typename = type_name; // Short typename. + root_infos[type_no].bin_digits = std::numeric_limits<T>::digits; + root_infos[type_no].get_digits = static_cast<int>(std::numeric_limits<T>::digits * digits_accuracy); + + T radius = static_cast<T>(big_radius); + T arc = static_cast<T>(big_arc); + + T result; // root + T sum = 0; + T ans = static_cast<T>(answer); + + using boost::timer::nanosecond_type; + using boost::timer::cpu_times; + using boost::timer::cpu_timer; + + long eval_count = boost::is_floating_point<T>::value ? 1000000 : 10000; // To give a sufficiently stable timing for the fast built-in types, + // This takes an inconveniently long time for multiprecision cpp_bin_float_50 etc types. + + cpu_times now; // Holds wall, user and system times. + + { // Evaluate times etc for each algorithm. + //algorithm_names.push_back("TOMS748"); // + cpu_timer ti; // Can start, pause, resume and stop, and read elapsed. + ti.start(); + for(long i = eval_count; i >= 0; --i) + { + result = elliptic_root_noderiv(radius, arc); // + sum += result; + } + now = ti.elapsed(); + int time = static_cast<int>(now.user / eval_count); + root_infos[type_no].times.push_back(time); // CPU time taken. + if (time < root_infos[type_no].min_time) + { + root_infos[type_no].min_time = time; + } + ti.stop(); + long int distance = static_cast<int>(boost::math::float_distance<T>(result, ans)); + root_infos[type_no].distances.push_back(distance); + root_infos[type_no].iterations.push_back(iters); // + root_infos[type_no].full_results.push_back(result); + } + { + // algorithm_names.push_back("Newton"); // algorithm + cpu_timer ti; // Can start, pause, resume and stop, and read elapsed. + ti.start(); + for(long i = eval_count; i >= 0; --i) + { + result = elliptic_root_1deriv(radius, arc); // + sum += result; + } + now = ti.elapsed(); + int time = static_cast<int>(now.user / eval_count); + root_infos[type_no].times.push_back(time); // CPU time taken. + if (time < root_infos[type_no].min_time) + { + root_infos[type_no].min_time = time; + } + + ti.stop(); + long int distance = static_cast<int>(boost::math::float_distance<T>(result, ans)); + root_infos[type_no].distances.push_back(distance); + root_infos[type_no].iterations.push_back(iters); // + root_infos[type_no].full_results.push_back(result); + } + { + //algorithm_names.push_back("Halley"); // algorithm + cpu_timer ti; // Can start, pause, resume and stop, and read elapsed. + ti.start(); + for(long i = eval_count; i >= 0; --i) + { + result = elliptic_root_2deriv(radius, arc); // + sum += result; + } + now = ti.elapsed(); + int time = static_cast<int>(now.user / eval_count); + root_infos[type_no].times.push_back(time); // CPU time taken. + ti.stop(); + if (time < root_infos[type_no].min_time) + { + root_infos[type_no].min_time = time; + } + long int distance = static_cast<int>(boost::math::float_distance<T>(result, ans)); + root_infos[type_no].distances.push_back(distance); + root_infos[type_no].iterations.push_back(iters); // + root_infos[type_no].full_results.push_back(result); + } + { + // algorithm_names.push_back("Schr'''ö'''der"); // algorithm + cpu_timer ti; // Can start, pause, resume and stop, and read elapsed. + ti.start(); + for(long i = eval_count; i >= 0; --i) + { + result = elliptic_root_2deriv_s(arc, radius); // + sum += result; + } + now = ti.elapsed(); + int time = static_cast<int>(now.user / eval_count); + root_infos[type_no].times.push_back(time); // CPU time taken. + if (time < root_infos[type_no].min_time) + { + root_infos[type_no].min_time = time; + } + ti.stop(); + long int distance = static_cast<int>(boost::math::float_distance<T>(result, ans)); + root_infos[type_no].distances.push_back(distance); + root_infos[type_no].iterations.push_back(iters); // + root_infos[type_no].full_results.push_back(result); + } + for (size_t i = 0; i != root_infos[type_no].times.size(); i++) // For each time. + { // Normalize times. + root_infos[type_no].normed_times.push_back(static_cast<double>(root_infos[type_no].times[i]) / root_infos[type_no].min_time); + } + + std::cout << "Accumulated result was: " << sum << std::endl; + + return 4; // eval_count of how many algorithms used. +} // test_root + +/*! Fill array of times, iterations, etc for Nth root for all 4 types, + and write a table of results in Quickbook format. + */ +void table_root_info(cpp_bin_float_100 radius, cpp_bin_float_100 arc) +{ + using std::abs; + + std::cout << nooftypes << " floating-point types tested:" << std::endl; +#if defined(_DEBUG) || !defined(NDEBUG) + std::cout << "Compiled in debug mode." << std::endl; +#else + std::cout << "Compiled in optimise mode." << std::endl; +#endif + std::cout << "FP hardware " << fp_hardware << std::endl; + // Compute the 'right' answer for root N at 100 decimal digits. + cpp_bin_float_100 full_answer = elliptic_root_noderiv(radius, arc); + + root_infos.clear(); // Erase any previous data. + // Fill the elements of the array for each floating-point type. + + test_root<float>(radius, arc, full_answer, "float", 0); + test_root<double>(radius, arc, full_answer, "double", 1); + test_root<long double>(radius, arc, full_answer, "long double", 2); + test_root<cpp_bin_float_50>(radius, arc, full_answer, "cpp_bin_float_50", 3); + + // Use info from 4 floating point types to + + // Prepare Quickbook table for a single root + // with columns of times, iterations, distances repeated for various floating-point types, + // and 4 rows for each algorithm. + + std::stringstream table_info; + table_info.precision(3); + table_info << "[table:elliptic root with radius " << radius << " and arc length " << arc << ") for float, double, long double and cpp_bin_float_50 types"; + if (fp_hardware != "") + { + table_info << ", using " << fp_hardware; + } + table_info << std::endl; + + fout << table_info.str() + << "[[][float][][][] [][double][][][] [][long d][][][] [][cpp50][][]]\n" + << "[[Algo ]"; + for (size_t tp = 0; tp != nooftypes; tp++) + { // For all types: + fout << "[Its]" << "[Times]" << "[Norm]" << "[Dis]" << "[ ]"; + } + fout << "]" << std::endl; + + // Row for all algorithms. + for (std::size_t algo = 0; algo != noofalgos; algo++) + { + fout << "[[" << std::left << std::setw(9) << algo_names[algo] << "]"; + for (size_t tp = 0; tp != nooftypes; tp++) + { // For all types: + fout + << "[" << std::right << std::showpoint + << std::setw(3) << std::setprecision(2) << root_infos[tp].iterations[algo] << "][" + << std::setw(5) << std::setprecision(5) << root_infos[tp].times[algo] << "]["; + fout << std::setw(3) << std::setprecision(3); + double normed_time = root_infos[tp].normed_times[algo]; + if (abs(normed_time - 1.00) <= 0.05) + { // At or near the best time, so show as blue. + fout << "[role blue " << normed_time << "]"; + } + else if (abs(normed_time) > 4.) + { // markedly poor so show as red. + fout << "[role red " << normed_time << "]"; + } + else + { // Not the best, so normal black. + fout << normed_time; + } + fout << "][" + << std::setw(3) << std::setprecision(2) << root_infos[tp].distances[algo] << "][ ]"; + } // tp + fout << "]" << std::endl; + } // for algo + fout << "] [/end of table root]\n"; +} // void table_root_info + +/*! Output program header, table of type info, and tables for 4 algorithms and 4 floating-point types, + for Nth root required digits_accuracy. + */ + +int roots_tables(cpp_bin_float_100 radius, cpp_bin_float_100 arc, double digits_accuracy) +{ + ::digits_accuracy = digits_accuracy; + // Save globally so that it is available to root-finding algorithms. Ugly :-( + +#if defined(_DEBUG) || !defined(NDEBUG) + std::string debug_or_optimize("Compiled in debug mode."); +#else + std::string debug_or_optimize("Compiled in optimise mode."); +#endif + + // Create filename for roots_table + std::string qbk_name = full_roots_name; + qbk_name += "elliptic_table"; + + std::stringstream ss; + ss.precision(3); + // ss << "_" << N // now put all the tables in one .qbk file? + ss << "_" << digits_accuracy * 100 + << std::flush; + // Assume only save optimize mode runs, so don't add any _DEBUG info. + qbk_name += ss.str(); + +#ifdef _MSC_VER + qbk_name += "_msvc"; +#else // assume GCC + qbk_name += "_gcc"; +#endif + if (fp_hardware != "") + { + qbk_name += fp_hardware; + } + qbk_name += ".qbk"; + + fout.open(qbk_name, std::ios_base::out); + + if (fout.is_open()) + { + std::cout << "Output root table to " << qbk_name << std::endl; + } + else + { // Failed to open. + std::cout << " Open file " << qbk_name << " for output failed!" << std::endl; + std::cout << "errno " << errno << std::endl; + return errno; + } + + fout << + "[/" + << qbk_name + << "\n" + "Copyright 2015 Paul A. Bristow.""\n" + "Copyright 2015 John Maddock.""\n" + "Distributed under the Boost Software License, Version 1.0.""\n" + "(See accompanying file LICENSE_1_0.txt or copy at""\n" + "http://www.boost.org/LICENSE_1_0.txt).""\n" + "]""\n" + << std::endl; + + // Print out the program/compiler/stdlib/platform names as a Quickbook comment: + fout << "\n[h6 Program [@../../example/" << short_file_name(sourcefilename) << " " << short_file_name(sourcefilename) << "],\n " + << BOOST_COMPILER << ", " + << BOOST_STDLIB << ", " + << BOOST_PLATFORM << "\n" + << debug_or_optimize + << ((fp_hardware != "") ? ", " + fp_hardware : "") + << "]" // [h6 close]. + << std::endl; + + //fout << "Fraction of full accuracy " << digits_accuracy << std::endl; + + table_root_info(radius, arc); + + fout.close(); + + // table_type_info(digits_accuracy); + + return 0; +} // roots_tables + + +int main() +{ + using namespace boost::multiprecision; + using namespace boost::math; + + + try + { + std::cout << "Tests run with " << BOOST_COMPILER << ", " + << BOOST_STDLIB << ", " << BOOST_PLATFORM << ", "; + +// How to: Configure Visual C++ Projects to Target 64-Bit Platforms +// https://msdn.microsoft.com/en-us/library/9yb4317s.aspx + +#ifdef _M_X64 // Defined for compilations that target x64 processors. + std::cout << "X64 " << std::endl; + fp_hardware += "_X64"; +#else +# ifdef _M_IX86 + std::cout << "X32 " << std::endl; + fp_hardware += "_X86"; +# endif +#endif + +#ifdef _M_AMD64 + std::cout << "AMD64 " << std::endl; + // fp_hardware += "_AMD64"; +#endif + +// https://msdn.microsoft.com/en-us/library/7t5yh4fd.aspx +// /arch (x86) options /arch:[IA32|SSE|SSE2|AVX|AVX2] +// default is to use SSE and SSE2 instructions by default. +// https://msdn.microsoft.com/en-us/library/jj620901.aspx +// /arch (x64) options /arch:AVX and /arch:AVX2 + +// MSVC doesn't bother to set these SSE macros! +// http://stackoverflow.com/questions/18563978/sse-sse2-is-enabled-control-in-visual-studio +// https://msdn.microsoft.com/en-us/library/b0084kay.aspx predefined macros. + +// But some of these macros are *not* defined by MSVC, +// unlike AVX (but *are* defined by GCC and Clang). +// So the macro code above does define them. +#if (defined(_M_AMD64) || defined (_M_X64)) +# define _M_X64 +# define __SSE2__ +#else +# ifdef _M_IX86_FP // Expands to an integer literal value indicating which /arch compiler option was used: + std::cout << "Floating-point _M_IX86_FP = " << _M_IX86_FP << std::endl; +# if (_M_IX86_FP == 2) // 2 if /arch:SSE2, /arch:AVX or /arch:AVX2 +# define __SSE2__ // x32 +# elif (_M_IX86_FP == 1) // 1 if /arch:SSE was used. +# define __SSE__ // x32 +# elif (_M_IX86_FP == 0) // 0 if /arch:IA32 was used. +# define _X32 // No special FP instructions. +# endif +# endif +#endif +// Set the fp_hardware that is used in the .qbk filename. +#ifdef __AVX2__ + std::cout << "Floating-point AVX2 " << std::endl; + fp_hardware += "_AVX2"; +# else +# ifdef __AVX__ + std::cout << "Floating-point AVX " << std::endl; + fp_hardware += "_AVX"; +# else +# ifdef __SSE2__ + std::cout << "Floating-point SSE2 " << std::endl; + fp_hardware += "_SSE2"; +# else +# ifdef __SSE__ + std::cout << "Floating-point SSE " << std::endl; + fp_hardware += "_SSE"; +# endif +# endif +# endif +# endif + +#ifdef _M_IX86 + std::cout << "Floating-point X86 _M_IX86 = " << _M_IX86 << std::endl; + // https://msdn.microsoft.com/en-us/library/aa273918%28v=vs.60%29.aspx#_predir_table_1..3 + // 600 = Pentium Pro +#endif + +#ifdef _MSC_FULL_VER + std::cout << "Floating-point _MSC_FULL_VER " << _MSC_FULL_VER << std::endl; +#endif + +#ifdef __MSVC_RUNTIME_CHECKS + std::cout << "Runtime __MSVC_RUNTIME_CHECKS " << std::endl; +#endif + + BOOST_MATH_CONTROL_FP; + + cpp_bin_float_100 radius("28."); + cpp_bin_float_100 arc("300."); + // Compute full answer to more than precision of tests. + //T value = 28.; // integer (exactly representable as floating-point) + // whose cube root is *not* exactly representable. + // Wolfram Alpha command N[28 ^ (1 / 3), 100] computes cube root to 100 decimal digits. + // 3.036588971875662519420809578505669635581453977248111123242141654169177268411884961770250390838097895 + + std::cout.precision(100); + std::cout << "radius 1" << radius << std::endl; + std::cout << "arc length" << arc << std::endl; + // std::cout << ",\n""answer = " << full_answer << std::endl; + std::cout.precision(6); + // cbrt cpp_bin_float_100 full_answer("3.036588971875662519420809578505669635581453977248111123242141654169177268411884961770250390838097895"); + + // Output the table of types, maxdigits10 and digits and required digits for some accuracies. + + // Output tables for some roots at full accuracy. + roots_tables(radius, arc, 1.); + + // Output tables for some roots at less accuracy. + //roots_tables(full_value, 0.75); + + return boost::exit_success; + } + catch (std::exception const& ex) + { + std::cout << "exception thrown: " << ex.what() << std::endl; + return boost::exit_failure; + } +} // int main() + +/* + +*/ diff --git a/src/boost/libs/math/example/root_finding_algorithms.cpp b/src/boost/libs/math/example/root_finding_algorithms.cpp new file mode 100644 index 000000000..df2e68acc --- /dev/null +++ b/src/boost/libs/math/example/root_finding_algorithms.cpp @@ -0,0 +1,907 @@ +// Copyright Paul A. Bristow 2015 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Comparison of finding roots using TOMS748, Newton-Raphson, Schroder & Halley algorithms. + +// Note that this file contains Quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +// root_finding_algorithms.cpp + +#include <boost/cstdlib.hpp> +#include <boost/config.hpp> +#include <boost/array.hpp> +#include <boost/type_traits/is_floating_point.hpp> +#include <boost/type_traits/is_fundamental.hpp> + +#include "table_type.hpp" +// Copy of i:\modular-boost\libs\math\test\table_type.hpp +// #include "handle_test_result.hpp" +// Copy of i:\modular - boost\libs\math\test\handle_test_result.hpp + +#include <boost/math/tools/roots.hpp> +//using boost::math::policies::policy; +//using boost::math::tools::newton_raphson_iterate; +//using boost::math::tools::halley_iterate; // +//using boost::math::tools::eps_tolerance; // Binary functor for specified number of bits. +//using boost::math::tools::bracket_and_solve_root; +//using boost::math::tools::toms748_solve; +//using boost::math::tools::schroder_iterate; + +#include <boost/math/special_functions/next.hpp> // For float_distance. +#include <tuple> // for tuple and make_tuple. +#include <boost/math/special_functions/cbrt.hpp> // For boost::math::cbrt. + +#include <boost/multiprecision/cpp_bin_float.hpp> // is binary. +//#include <boost/multiprecision/cpp_dec_float.hpp> // is decimal. +using boost::multiprecision::cpp_bin_float_100; +using boost::multiprecision::cpp_bin_float_50; + +#include <boost/timer/timer.hpp> +#include <boost/system/error_code.hpp> +#include <boost/multiprecision/cpp_bin_float/io.hpp> +#include <boost/preprocessor/stringize.hpp> + +// STL +#include <iostream> +#include <iomanip> +#include <string> +#include <vector> +#include <limits> +#include <fstream> // std::ofstream +#include <cmath> +#include <typeinfo> // for type name using typid(thingy).name(); + +#ifndef BOOST_ROOT +# define BOOST_ROOT i:/modular-boost/ +#endif +// Need to find this + +#ifdef __FILE__ +std::string sourcefilename = __FILE__; +#endif + +std::string chop_last(std::string s) +{ + std::string::size_type pos = s.find_last_of("\\/"); + if(pos != std::string::npos) + s.erase(pos); + else if(s.empty()) + abort(); + else + s.erase(); + return s; +} + +std::string make_root() +{ + std::string result; + if(sourcefilename.find_first_of(":") != std::string::npos) + { + result = chop_last(sourcefilename); // lose filename part + result = chop_last(result); // lose /example/ + result = chop_last(result); // lose /math/ + result = chop_last(result); // lose /libs/ + } + else + { + result = chop_last(sourcefilename); // lose filename part + if(result.empty()) + result = "."; + result += "/../../.."; + } + return result; +} + +std::string short_file_name(std::string s) +{ + std::string::size_type pos = s.find_last_of("\\/"); + if(pos != std::string::npos) + s.erase(0, pos + 1); + return s; +} + +std::string boost_root = make_root(); + +#ifdef _MSC_VER + std::string filename = boost_root.append("/libs/math/doc/roots/root_comparison_tables_msvc.qbk"); +#else // assume GCC + std::string filename = boost_root.append("/libs/math/doc/roots/root_comparison_tables_gcc.qbk"); +#endif + +std::ofstream fout (filename.c_str(), std::ios_base::out); + +//std::array<std::string, 6> float_type_names = +//{ +// "float", "double", "long double", "cpp_bin_128", "cpp_dec_50", "cpp_dec_100" +//}; + +std::vector<std::string> algo_names = +{ + "cbrt", "TOMS748", "Newton", "Halley", "Schr'''ö'''der" +}; + +std::vector<int> max_digits10s; +std::vector<std::string> typenames; // Full computer generated type name. +std::vector<std::string> names; // short name. + +uintmax_t iters; // Global as iterations is not returned by rooting function. + +const int count = 1000000; // Number of iterations to average. + +struct root_info +{ // for a floating-point type, float, double ... + std::size_t max_digits10; // for type. + std::string full_typename; // for type from type_id.name(). + std::string short_typename; // for type "float", "double", "cpp_bin_float_50" .... + + std::size_t bin_digits; // binary in floating-point type numeric_limits<T>::digits; + int get_digits; // fraction of maximum possible accuracy required. + // = digits * digits_accuracy + // Vector of values for each algorithm, std::cbrt, boost::math::cbrt, TOMS748, Newton, Halley. + //std::vector< boost::int_least64_t> times; converted to int. + std::vector<int> times; + //boost::int_least64_t min_time = std::numeric_limits<boost::int_least64_t>::max(); // Used to normalize times (as int). + std::vector<double> normed_times; + boost::int_least64_t min_time = (std::numeric_limits<boost::int_least64_t>::max)(); // Used to normalize times. + std::vector<uintmax_t> iterations; + std::vector<long int> distances; + std::vector<cpp_bin_float_100> full_results; +}; // struct root_info + +std::vector<root_info> root_infos; // One element for each type used. + +int type_no = -1; // float = 0, double = 1, ... indexing root_infos. + +inline std::string build_test_name(const char* type_name, const char* test_name) +{ + std::string result(BOOST_COMPILER); + result += "|"; + result += BOOST_STDLIB; + result += "|"; + result += BOOST_PLATFORM; + result += "|"; + result += type_name; + result += "|"; + result += test_name; +#if defined(_DEBUG ) || !defined(NDEBUG) + result += "|"; + result += " debug"; +#else + result += "|"; + result += " release"; +#endif + result += "|"; + return result; +} + +// No derivatives - using TOMS748 internally. +template <class T> +struct cbrt_functor_noderiv +{ // cube root of x using only function - no derivatives. + cbrt_functor_noderiv(T const& to_find_root_of) : a(to_find_root_of) + { // Constructor just stores value a to find root of. + } + T operator()(T const& x) + { + T fx = x*x*x - a; // Difference (estimate x^3 - a). + return fx; + } +private: + T a; // to be 'cube_rooted'. +}; // template <class T> struct cbrt_functor_noderiv + +template <class T> +T cbrt_noderiv(T x) +{ // return cube root of x using bracket_and_solve (using NO derivatives). + using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; // For bracket_and_solve_root. + + // Maybe guess should be double, or use enable_if to avoid warning about conversion double to float here? + T guess; + if (boost::is_fundamental<T>::value) + { + int exponent; + frexp(x, &exponent); // Get exponent of z (ignore mantissa). + guess = ldexp((T)1., exponent / 3); // Rough guess is to divide the exponent by three. + } + else + { // (boost::is_class<T>) + double dx = static_cast<double>(x); + guess = boost::math::cbrt<T>(dx); // Get guess using double. + } + + T factor = 2; // How big steps to take when searching. + + const boost::uintmax_t maxit = 50; // Limit to maximum iterations. + boost::uintmax_t it = maxit; // Initially our chosen max iterations, but updated with actual. + bool is_rising = true; // So if result if guess^3 is too low, then try increasing guess. + // Some fraction of digits is used to control how accurate to try to make the result. + int get_digits = static_cast<int>(std::numeric_limits<T>::digits - 2); + + eps_tolerance<T> tol(get_digits); // Set the tolerance. + std::pair<T, T> r = + bracket_and_solve_root(cbrt_functor_noderiv<T>(x), guess, factor, is_rising, tol, it); + iters = it; + T result = r.first + (r.second - r.first) / 2; // Midway between brackets. + return result; +} // template <class T> T cbrt_noderiv(T x) + + +// Using 1st derivative only Newton-Raphson + +template <class T> +struct cbrt_functor_deriv +{ // Functor also returning 1st derivative. + cbrt_functor_deriv(T const& to_find_root_of) : a(to_find_root_of) + { // Constructor stores value a to find root of, + // for example: calling cbrt_functor_deriv<T>(x) to use to get cube root of x. + } + std::pair<T, T> operator()(T const& x) + { // Return both f(x) and f'(x). + T fx = x*x*x - a; // Difference (estimate x^3 - value). + T dx = 3 * x*x; // 1st derivative = 3x^2. + return std::make_pair(fx, dx); // 'return' both fx and dx. + } +private: + T a; // to be 'cube_rooted'. +}; + +template <class T> +T cbrt_deriv(T x) +{ // return cube root of x using 1st derivative and Newton_Raphson. + using namespace boost::math::tools; + int exponent; + T guess; + if(boost::is_fundamental<T>::value) + { + frexp(x, &exponent); // Get exponent of z (ignore mantissa). + guess = ldexp(static_cast<T>(1), exponent / 3); // Rough guess is to divide the exponent by three. + } + else + guess = boost::math::cbrt(static_cast<double>(x)); + T min = guess / 2; // Minimum possible value is half our guess. + T max = 2 * guess; // Maximum possible value is twice our guess. + int get_digits = static_cast<int>(std::numeric_limits<T>::digits * 0.6); + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + T result = newton_raphson_iterate(cbrt_functor_deriv<T>(x), guess, min, max, get_digits, it); + iters = it; + return result; +} + +// Using 1st and 2nd derivatives with Halley algorithm. + +template <class T> +struct cbrt_functor_2deriv +{ // Functor returning both 1st and 2nd derivatives. + cbrt_functor_2deriv(T const& to_find_root_of) : a(to_find_root_of) + { // Constructor stores value a to find root of, for example: + // calling cbrt_functor_2deriv<T>(x) to get cube root of x, + } + std::tuple<T, T, T> operator()(T const& x) + { // Return both f(x) and f'(x) and f''(x). + T fx = x*x*x - a; // Difference (estimate x^3 - value). + T dx = 3 * x*x; // 1st derivative = 3x^2. + T d2x = 6 * x; // 2nd derivative = 6x. + return std::make_tuple(fx, dx, d2x); // 'return' fx, dx and d2x. + } +private: + T a; // to be 'cube_rooted'. +}; + +template <class T> +T cbrt_2deriv(T x) +{ // return cube root of x using 1st and 2nd derivatives and Halley. + //using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; + int exponent; + T guess; + if(boost::is_fundamental<T>::value) + { + frexp(x, &exponent); // Get exponent of z (ignore mantissa). + guess = ldexp(static_cast<T>(1), exponent / 3); // Rough guess is to divide the exponent by three. + } + else + guess = boost::math::cbrt(static_cast<double>(x)); + T min = guess / 2; // Minimum possible value is half our guess. + T max = 2 * guess; // Maximum possible value is twice our guess. + // digits used to control how accurate to try to make the result. + int get_digits = static_cast<int>(std::numeric_limits<T>::digits * 0.4); + boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + T result = halley_iterate(cbrt_functor_2deriv<T>(x), guess, min, max, get_digits, it); + iters = it; + return result; +} + +// Using 1st and 2nd derivatives using Schroder algorithm. + +template <class T> +T cbrt_2deriv_s(T x) +{ // return cube root of x using 1st and 2nd derivatives and Schroder algorithm. + //using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; + int exponent; + T guess; + if(boost::is_fundamental<T>::value) + { + frexp(x, &exponent); // Get exponent of z (ignore mantissa). + guess = ldexp(static_cast<T>(1), exponent / 3); // Rough guess is to divide the exponent by three. + } + else + guess = boost::math::cbrt(static_cast<double>(x)); + T min = guess / 2; // Minimum possible value is half our guess. + T max = 2 * guess; // Maximum possible value is twice our guess. + // digits used to control how accurate to try to make the result. + int get_digits = static_cast<int>(std::numeric_limits<T>::digits * 0.4); + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + T result = schroder_iterate(cbrt_functor_2deriv<T>(x), guess, min, max, get_digits, it); + iters = it; + return result; +} // template <class T> T cbrt_2deriv_s(T x) + + + +template <typename T> +int test_root(cpp_bin_float_100 big_value, cpp_bin_float_100 answer, const char* type_name) +{ + //T value = 28.; // integer (exactly representable as floating-point) + // whose cube root is *not* exactly representable. + // Wolfram Alpha command N[28 ^ (1 / 3), 100] computes cube root to 100 decimal digits. + // 3.036588971875662519420809578505669635581453977248111123242141654169177268411884961770250390838097895 + + std::size_t max_digits = 2 + std::numeric_limits<T>::digits * 3010 / 10000; + // For new versions use max_digits10 + // std::cout.precision(std::numeric_limits<T>::max_digits10); + std::cout.precision(max_digits); + std::cout << std::showpoint << std::endl; // Trailing zeros too. + + root_infos.push_back(root_info()); + type_no++; // Another type. + + root_infos[type_no].max_digits10 = max_digits; + root_infos[type_no].full_typename = typeid(T).name(); // Full typename. + root_infos[type_no].short_typename = type_name; // Short typename. + + root_infos[type_no].bin_digits = std::numeric_limits<T>::digits; + + root_infos[type_no].get_digits = std::numeric_limits<T>::digits; + + T to_root = static_cast<T>(big_value); + T result; // root + T ans = static_cast<T>(answer); + int algo = 0; // Count of algorithms used. + + using boost::timer::nanosecond_type; + using boost::timer::cpu_times; + using boost::timer::cpu_timer; + + cpu_times now; // Holds wall, user and system times. + T sum = 0; + + // std::cbrt is much the fastest, but not useful for this comparison because it only handles fundamental types. + // Using enable_if allows us to avoid a compile fail with multiprecision types, but still distorts the results too much. + + //{ + // algorithm_names.push_back("std::cbrt"); + // cpu_timer ti; // Can start, pause, resume and stop, and read elapsed. + // ti.start(); + // for (long i = 0; i < count; ++i) + // { + // stdcbrt(big_value); + // } + // now = ti.elapsed(); + // int time = static_cast<int>(now.user / count); + // root_infos[type_no].times.push_back(time); // CPU time taken per root. + // if (time < root_infos[type_no].min_time) + // { + // root_infos[type_no].min_time = time; + // } + // ti.stop(); + // long int distance = static_cast<int>(boost::math::float_distance<T>(result, ans)); + // root_infos[type_no].distances.push_back(distance); + // root_infos[type_no].iterations.push_back(0); // Not known. + // root_infos[type_no].full_results.push_back(result); + // algo++; + //} + //{ + // //algorithm_names.push_back("boost::math::cbrt"); // . + // cpu_timer ti; // Can start, pause, resume and stop, and read elapsed. + // ti.start(); + // for (long i = 0; i < count; ++i) + // { + // result = boost::math::cbrt(to_root); // + // } + // now = ti.elapsed(); + // int time = static_cast<int>(now.user / count); + // root_infos[type_no].times.push_back(time); // CPU time taken. + // ti.stop(); + // if (time < root_infos[type_no].min_time) + // { + // root_infos[type_no].min_time = time; + // } + // long int distance = static_cast<int>(boost::math::float_distance<T>(result, ans)); + // root_infos[type_no].distances.push_back(distance); + // root_infos[type_no].iterations.push_back(0); // Iterations not knowable. + // root_infos[type_no].full_results.push_back(result); + //} + + + + { + //algorithm_names.push_back("boost::math::cbrt"); // . + result = 0; + cpu_timer ti; // Can start, pause, resume and stop, and read elapsed. + ti.start(); + for (long i = 0; i < count; ++i) + { + result = boost::math::cbrt(to_root); // + sum += result; + } + now = ti.elapsed(); + + long time = static_cast<long>(now.user/1000); // convert nanoseconds to microseconds (assuming this is resolution). + root_infos[type_no].times.push_back(time); // CPU time taken. + ti.stop(); + if (time < root_infos[type_no].min_time) + { + root_infos[type_no].min_time = time; + } + long int distance = static_cast<int>(boost::math::float_distance<T>(result, ans)); + root_infos[type_no].distances.push_back(distance); + root_infos[type_no].iterations.push_back(0); // Iterations not knowable. + root_infos[type_no].full_results.push_back(result); + } + { + //algorithm_names.push_back("TOMS748"); // + cpu_timer ti; // Can start, pause, resume and stop, and read elapsed. + ti.start(); + for (long i = 0; i < count; ++i) + { + result = cbrt_noderiv<T>(to_root); // + sum += result; + } + now = ti.elapsed(); +// int time = static_cast<int>(now.user / count); + long time = static_cast<long>(now.user/1000); + root_infos[type_no].times.push_back(time); // CPU time taken. + if (time < root_infos[type_no].min_time) + { + root_infos[type_no].min_time = time; + } + ti.stop(); + long int distance = static_cast<int>(boost::math::float_distance<T>(result, ans)); + root_infos[type_no].distances.push_back(distance); + root_infos[type_no].iterations.push_back(iters); // + root_infos[type_no].full_results.push_back(result); + } + { + // algorithm_names.push_back("Newton"); // algorithm + cpu_timer ti; // Can start, pause, resume and stop, and read elapsed. + ti.start(); + for (long i = 0; i < count; ++i) + { + result = cbrt_deriv(to_root); // + sum += result; + } + now = ti.elapsed(); +// int time = static_cast<int>(now.user / count); + long time = static_cast<long>(now.user/1000); + root_infos[type_no].times.push_back(time); // CPU time taken. + if (time < root_infos[type_no].min_time) + { + root_infos[type_no].min_time = time; + } + + ti.stop(); + long int distance = static_cast<int>(boost::math::float_distance<T>(result, ans)); + root_infos[type_no].distances.push_back(distance); + root_infos[type_no].iterations.push_back(iters); // + root_infos[type_no].full_results.push_back(result); + } + { + //algorithm_names.push_back("Halley"); // algorithm + cpu_timer ti; // Can start, pause, resume and stop, and read elapsed. + ti.start(); + for (long i = 0; i < count; ++i) + { + result = cbrt_2deriv(to_root); // + sum += result; + } + now = ti.elapsed(); +// int time = static_cast<int>(now.user / count); + long time = static_cast<long>(now.user/1000); + root_infos[type_no].times.push_back(time); // CPU time taken. + ti.stop(); + if (time < root_infos[type_no].min_time) + { + root_infos[type_no].min_time = time; + } + long int distance = static_cast<int>(boost::math::float_distance<T>(result, ans)); + root_infos[type_no].distances.push_back(distance); + root_infos[type_no].iterations.push_back(iters); // + root_infos[type_no].full_results.push_back(result); + } + + { + // algorithm_names.push_back("Shroeder"); // algorithm + cpu_timer ti; // Can start, pause, resume and stop, and read elapsed. + ti.start(); + for (long i = 0; i < count; ++i) + { + result = cbrt_2deriv_s(to_root); // + sum += result; + } + now = ti.elapsed(); +// int time = static_cast<int>(now.user / count); + long time = static_cast<long>(now.user/1000); + root_infos[type_no].times.push_back(time); // CPU time taken. + if (time < root_infos[type_no].min_time) + { + root_infos[type_no].min_time = time; + } + ti.stop(); + long int distance = static_cast<int>(boost::math::float_distance<T>(result, ans)); + root_infos[type_no].distances.push_back(distance); + root_infos[type_no].iterations.push_back(iters); // + root_infos[type_no].full_results.push_back(result); + } + for (size_t i = 0; i != root_infos[type_no].times.size(); i++) + { // Normalize times. + double normed_time = static_cast<double>(root_infos[type_no].times[i]); + normed_time /= root_infos[type_no].min_time; + root_infos[type_no].normed_times.push_back(normed_time); + } + algo++; + std::cout << "Accumulated sum was " << sum << std::endl; + return algo; // Count of how many algorithms used. +} // test_root + +void table_root_info(cpp_bin_float_100 full_value, cpp_bin_float_100 full_answer) +{ + // Fill the elements. + test_root<float>(full_value, full_answer, "float"); + test_root<double>(full_value, full_answer, "double"); + test_root<long double>(full_value, full_answer, "long double"); + test_root<cpp_bin_float_50>(full_value, full_answer, "cpp_bin_float_50"); + //test_root<cpp_bin_float_100>(full_value, full_answer, "cpp_bin_float_100"); + + std::cout << root_infos.size() << " floating-point types tested:" << std::endl; +#ifndef NDEBUG + std::cout << "Compiled in debug mode." << std::endl; +#else + std::cout << "Compiled in optimise mode." << std::endl; +#endif + + + for (size_t tp = 0; tp != root_infos.size(); tp++) + { // For all types: + + std::cout << std::endl; + + std::cout << "Floating-point type = " << root_infos[tp].short_typename << std::endl; + std::cout << "Floating-point type = " << root_infos[tp].full_typename << std::endl; + std::cout << "Max_digits10 = " << root_infos[tp].max_digits10 << std::endl; + std::cout << "Binary digits = " << root_infos[tp].bin_digits << std::endl; + std::cout << "Accuracy digits = " << root_infos[tp].get_digits - 2 << ", " << static_cast<int>(root_infos[tp].get_digits * 0.6) << ", " << static_cast<int>(root_infos[tp].get_digits * 0.4) << std::endl; + std::cout << "min_time = " << root_infos[tp].min_time << std::endl; + + std::cout << std::setprecision(root_infos[tp].max_digits10 ) << "Roots = "; + std::copy(root_infos[tp].full_results.begin(), root_infos[tp].full_results.end(), std::ostream_iterator<cpp_bin_float_100>(std::cout, " ")); + std::cout << std::endl; + + // Header row. + std::cout << "Algorithm " << "Iterations " << "Times " << "Norm_times " << "Distance" << std::endl; + + // Row for all algorithms. + for (unsigned algo = 0; algo != algo_names.size(); algo++) + { + std::cout + << std::left << std::setw(20) << algo_names[algo] << " " + << std::setw(8) << std::setprecision(2) << root_infos[tp].iterations[algo] << " " + << std::setw(8) << std::setprecision(5) << root_infos[tp].times[algo] << " " + << std::setw(8) << std::setprecision(3) << root_infos[tp].normed_times[algo] << " " + << std::setw(8) << std::setprecision(2) << root_infos[tp].distances[algo] + << std::endl; + } // for algo + } // for tp + + // Print info as Quickbook table. +#if 0 + fout << "[table:cbrt_5 Info for float, double, long double and cpp_bin_float_50\n" + << "[[type name] [max_digits10] [binary digits] [required digits]]\n";// header. + + for (size_t tp = 0; tp != root_infos.size(); tp++) + { // For all types: + fout << "[" + << "[" << root_infos[tp].short_typename << "]" + << "[" << root_infos[tp].max_digits10 << "]" // max_digits10 + << "[" << root_infos[tp].bin_digits << "]"// < "Binary digits + << "[" << root_infos[tp].get_digits << "]]\n"; // Accuracy digits. + } // tp + fout << "] [/table cbrt_5] \n" << std::endl; +#endif + // Prepare Quickbook table of floating-point types. + fout << "[table:cbrt_4 Cube root(28) for float, double, long double and cpp_bin_float_50\n" + << "[[][float][][][] [][double][][][] [][long d][][][] [][cpp50][][]]\n" + << "[[Algorithm]"; + for (size_t tp = 0; tp != root_infos.size(); tp++) + { // For all types: + fout << "[Its]" << "[Times]" << "[Norm]" << "[Dis]" << "[ ]"; + } + fout << "]" << std::endl; + + // Row for all algorithms. + for (size_t algo = 0; algo != algo_names.size(); algo++) + { + fout << "[[" << std::left << std::setw(9) << algo_names[algo] << "]"; + for (size_t tp = 0; tp != root_infos.size(); tp++) + { // For all types: + + fout + << "[" << std::right << std::showpoint + << std::setw(3) << std::setprecision(2) << root_infos[tp].iterations[algo] << "][" + << std::setw(5) << std::setprecision(5) << root_infos[tp].times[algo] << "]["; + if(fabs(root_infos[tp].normed_times[algo]) <= 1.05) + fout << "[role blue " << std::setw(3) << std::setprecision(2) << root_infos[tp].normed_times[algo] << "]"; + else if(fabs(root_infos[tp].normed_times[algo]) > 4) + fout << "[role red " << std::setw(3) << std::setprecision(2) << root_infos[tp].normed_times[algo] << "]"; + else + fout << std::setw(3) << std::setprecision(2) << root_infos[tp].normed_times[algo]; + fout + << "][" + << std::setw(3) << std::setprecision(2) << root_infos[tp].distances[algo] << "][ ]"; + } // tp + fout <<"]" << std::endl; + } // for algo + fout << "] [/end of table cbrt_4]\n"; +} // void table_root_info + +int main() +{ + using namespace boost::multiprecision; + using namespace boost::math; + + try + { + std::cout << "Tests run with " << BOOST_COMPILER << ", " + << BOOST_STDLIB << ", " << BOOST_PLATFORM << ", "; + + if (fout.is_open()) + { + std::cout << "\nOutput to " << filename << std::endl; + } + else + { // Failed to open. + std::cout << " Open file " << filename << " for output failed!" << std::endl; + std::cout << "error" << errno << std::endl; + return boost::exit_failure; + } + + fout << + "[/""\n" + "Copyright 2015 Paul A. Bristow.""\n" + "Copyright 2015 John Maddock.""\n" + "Distributed under the Boost Software License, Version 1.0.""\n" + "(See accompanying file LICENSE_1_0.txt or copy at""\n" + "http://www.boost.org/LICENSE_1_0.txt).""\n" + "]""\n" + << std::endl; + std::string debug_or_optimize; +#ifdef _DEBUG +#if (_DEBUG == 0) + debug_or_optimize = "Compiled in debug mode."; +#else + debug_or_optimize = "Compiled in optimise mode."; +#endif +#endif + + // Print out the program/compiler/stdlib/platform names as a Quickbook comment: + fout << "\n[h5 Program " << short_file_name(sourcefilename) << ", " + << BOOST_COMPILER << ", " + << BOOST_STDLIB << ", " + << BOOST_PLATFORM << (sizeof(void*) == 8 ? ", x64" : ", x86") + << debug_or_optimize << "[br]" + << count << " evaluations of each of " << algo_names.size() << " root_finding algorithms." + << "]" + << std::endl; + + std::cout << count << " evaluations of root_finding." << std::endl; + + BOOST_MATH_CONTROL_FP; + + cpp_bin_float_100 full_value("28"); + + cpp_bin_float_100 full_answer ("3.036588971875662519420809578505669635581453977248111123242141654169177268411884961770250390838097895"); + + std::copy(max_digits10s.begin(), max_digits10s.end(), std::ostream_iterator<int>(std::cout, " ")); + std::cout << std::endl; + + table_root_info(full_value, full_answer); + + + return boost::exit_success; + } + catch (std::exception const& ex) + { + std::cout << "exception thrown: " << ex.what() << std::endl; + return boost::exit_failure; + } +} // int main() + +/* +debug + +1> float, maxdigits10 = 9 +1> 6 algorithms used. +1> Digits required = 24.0000000 +1> find root of 28.0000000, expected answer = 3.03658897 +1> Times 156 312 18750 4375 3437 3906 +1> Iterations: 0 0 8 6 4 5 +1> Distance: 0 0 -1 0 0 0 +1> Roots: 3.03658891 3.03658891 3.03658915 3.03658891 3.03658891 3.03658891 + +release + +1> float, maxdigits10 = 9 +1> 6 algorithms used. +1> Digits required = 24.0000000 +1> find root of 28.0000000, expected answer = 3.03658897 +1> Times 0 312 6875 937 937 937 +1> Iterations: 0 0 8 6 4 5 +1> Distance: 0 0 -1 0 0 0 +1> Roots: 3.03658891 3.03658891 3.03658915 3.03658891 3.03658891 3.03658891 + + +1> +1> 5 algorithms used: +1> 10 algorithms used: +1> boost::math::cbrt TOMS748 Newton Halley Shroeder boost::math::cbrt TOMS748 Newton Halley Shroeder +1> 2 types compared. +1> Precision of full type = 102 decimal digits +1> Find root of 28.000000000000000, +1> Expected answer = 3.0365889718756625 +1> typeid(T).name()float, maxdigits10 = 9 +1> find root of 28.0000000, expected answer = 3.03658897 +1> +1> Iterations: 0 8 6 4 5 +1> Times 468 8437 4375 3593 4062 +1> Min Time 468 +1> Normalized Times 1.00 18.0 9.35 7.68 8.68 +1> Distance: 0 -1 0 0 0 +1> Roots: 3.03658891 3.03658915 3.03658891 3.03658891 3.03658891 +1> ================================================================== +1> typeid(T).name()double, maxdigits10 = 17 +1> find root of 28.000000000000000, expected answer = 3.0365889718756625 +1> +1> Iterations: 0 11 7 5 6 +1> Times 312 15000 4531 3906 4375 +1> Min Time 312 +1> Normalized Times 1.00 48.1 14.5 12.5 14.0 +1> Distance: 1 2 0 0 0 +1> Roots: 3.0365889718756622 3.0365889718756618 3.0365889718756627 3.0365889718756627 3.0365889718756627 +1> ================================================================== + + +Release + +1> 5 algorithms used: +1> 10 algorithms used: +1> boost::math::cbrt TOMS748 Newton Halley Shroeder boost::math::cbrt TOMS748 Newton Halley Shroeder +1> 2 types compared. +1> Precision of full type = 102 decimal digits +1> Find root of 28.000000000000000, +1> Expected answer = 3.0365889718756625 +1> typeid(T).name()float, maxdigits10 = 9 +1> find root of 28.0000000, expected answer = 3.03658897 +1> +1> Iterations: 0 8 6 4 5 +1> Times 312 781 937 937 937 +1> Min Time 312 +1> Normalized Times 1.00 2.50 3.00 3.00 3.00 +1> Distance: 0 -1 0 0 0 +1> Roots: 3.03658891 3.03658915 3.03658891 3.03658891 3.03658891 +1> ================================================================== +1> typeid(T).name()double, maxdigits10 = 17 +1> find root of 28.000000000000000, expected answer = 3.0365889718756625 +1> +1> Iterations: 0 11 7 5 6 +1> Times 312 1093 937 937 937 +1> Min Time 312 +1> Normalized Times 1.00 3.50 3.00 3.00 3.00 +1> Distance: 1 2 0 0 0 +1> Roots: 3.0365889718756622 3.0365889718756618 3.0365889718756627 3.0365889718756627 3.0365889718756627 +1> ================================================================== + + + +1> 5 algorithms used: +1> 15 algorithms used: +1> boost::math::cbrt TOMS748 Newton Halley Shroeder boost::math::cbrt TOMS748 Newton Halley Shroeder boost::math::cbrt TOMS748 Newton Halley Shroeder +1> 3 types compared. +1> Precision of full type = 102 decimal digits +1> Find root of 28.00000000000000000000000000000000000000000000000000, +1> Expected answer = 3.036588971875662519420809578505669635581453977248111 +1> typeid(T).name()float, maxdigits10 = 9 +1> find root of 28.0000000, expected answer = 3.03658897 +1> +1> Iterations: 0 8 6 4 5 +1> Times 156 781 937 1093 937 +1> Min Time 156 +1> Normalized Times 1.00 5.01 6.01 7.01 6.01 +1> Distance: 0 -1 0 0 0 +1> Roots: 3.03658891 3.03658915 3.03658891 3.03658891 3.03658891 +1> ================================================================== +1> typeid(T).name()double, maxdigits10 = 17 +1> find root of 28.000000000000000, expected answer = 3.0365889718756625 +1> +1> Iterations: 0 11 7 5 6 +1> Times 312 1093 937 937 937 +1> Min Time 312 +1> Normalized Times 1.00 3.50 3.00 3.00 3.00 +1> Distance: 1 2 0 0 0 +1> Roots: 3.0365889718756622 3.0365889718756618 3.0365889718756627 3.0365889718756627 3.0365889718756627 +1> ================================================================== +1> typeid(T).name()class boost::multiprecision::number<class boost::multiprecision::backends::cpp_bin_float<50,10,void,int,0,0>,0>, maxdigits10 = 52 +1> find root of 28.00000000000000000000000000000000000000000000000000, expected answer = 3.036588971875662519420809578505669635581453977248111 +1> +1> Iterations: 0 13 9 6 7 +1> Times 8750 177343 30312 52968 58125 +1> Min Time 8750 +1> Normalized Times 1.00 20.3 3.46 6.05 6.64 +1> Distance: 0 0 -1 0 0 +1> Roots: 3.036588971875662519420809578505669635581453977248106 3.036588971875662519420809578505669635581453977248106 3.036588971875662519420809578505669635581453977248117 3.036588971875662519420809578505669635581453977248106 3.036588971875662519420809578505669635581453977248106 +1> ================================================================== + +Reduce accuracy required to 0.5 + +1> 5 algorithms used: +1> 15 algorithms used: +1> boost::math::cbrt TOMS748 Newton Halley Shroeder +1> 3 floating_point types compared. +1> Precision of full type = 102 decimal digits +1> Find root of 28.00000000000000000000000000000000000000000000000000, +1> Expected answer = 3.036588971875662519420809578505669635581453977248111 +1> typeid(T).name() = float, maxdigits10 = 9 +1> Digits accuracy fraction required = 0.500000000 +1> find root of 28.0000000, expected answer = 3.03658897 +1> +1> Iterations: 0 8 5 3 4 +1> Times 156 5937 1406 1250 1250 +1> Min Time 156 +1> Normalized Times 1.0 38. 9.0 8.0 8.0 +1> Distance: 0 -1 0 0 0 +1> Roots: 3.03658891 3.03658915 3.03658891 3.03658891 3.03658891 +1> ================================================================== +1> typeid(T).name() = double, maxdigits10 = 17 +1> Digits accuracy fraction required = 0.50000000000000000 +1> find root of 28.000000000000000, expected answer = 3.0365889718756625 +1> +1> Iterations: 0 8 6 4 5 +1> Times 156 6250 1406 1406 1250 +1> Min Time 156 +1> Normalized Times 1.0 40. 9.0 9.0 8.0 +1> Distance: 1 3695766 0 0 0 +1> Roots: 3.0365889718756622 3.0365889702344129 3.0365889718756627 3.0365889718756627 3.0365889718756627 +1> ================================================================== +1> typeid(T).name() = class boost::multiprecision::number<class boost::multiprecision::backends::cpp_bin_float<50,10,void,int,0,0>,0>, maxdigits10 = 52 +1> Digits accuracy fraction required = 0.5000000000000000000000000000000000000000000000000000 +1> find root of 28.00000000000000000000000000000000000000000000000000, expected answer = 3.036588971875662519420809578505669635581453977248111 +1> +1> Iterations: 0 11 8 5 6 +1> Times 11562 239843 34843 47500 47812 +1> Min Time 11562 +1> Normalized Times 1.0 21. 3.0 4.1 4.1 +1> Distance: 0 0 -1 0 0 +1> Roots: 3.036588971875662519420809578505669635581453977248106 3.036588971875662519420809578505669635581453977248106 3.036588971875662519420809578505669635581453977248117 3.036588971875662519420809578505669635581453977248106 3.036588971875662519420809578505669635581453977248106 +1> ================================================================== + + + +*/ diff --git a/src/boost/libs/math/example/root_finding_example.cpp b/src/boost/libs/math/example/root_finding_example.cpp new file mode 100644 index 000000000..57583b274 --- /dev/null +++ b/src/boost/libs/math/example/root_finding_example.cpp @@ -0,0 +1,547 @@ +// root_finding_example.cpp + +// Copyright Paul A. Bristow 2010, 2015 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Example of finding roots using Newton-Raphson, Halley. + +// Note that this file contains Quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +//#define BOOST_MATH_INSTRUMENT + +/* +This example demonstrates how to use the various tools for root finding +taking the simple cube root function (`cbrt`) as an example. + +It shows how use of derivatives can improve the speed. +(But is only a demonstration and does not try to make the ultimate improvements of 'real-life' +implementation of `boost::math::cbrt`, mainly by using a better computed initial 'guess' +at `<boost/math/special_functions/cbrt.hpp>`). + +Then we show how a higher root (fifth) can be computed, +and in `root_finding_n_example.cpp` a generic method +for the ['n]th root that constructs the derivatives at compile-time, + +These methods should be applicable to other functions that can be differentiated easily. + +First some `#includes` that will be needed. + +[tip For clarity, `using` statements are provided to list what functions are being used in this example: +you can of course partly or fully qualify the names in other ways. +(For your application, you may wish to extract some parts into header files, +but you should never use `using` statements globally in header files).] +*/ + +//[root_finding_include_1 + +#include <boost/math/tools/roots.hpp> +//using boost::math::policies::policy; +//using boost::math::tools::newton_raphson_iterate; +//using boost::math::tools::halley_iterate; // +//using boost::math::tools::eps_tolerance; // Binary functor for specified number of bits. +//using boost::math::tools::bracket_and_solve_root; +//using boost::math::tools::toms748_solve; + +#include <boost/math/special_functions/next.hpp> // For float_distance. +#include <tuple> // for std::tuple and std::make_tuple. +#include <boost/math/special_functions/cbrt.hpp> // For boost::math::cbrt. + +//] [/root_finding_include_1] + +// using boost::math::tuple; +// using boost::math::make_tuple; +// using boost::math::tie; +// which provide convenient aliases for various implementations, +// including std::tr1, depending on what is available. + +#include <iostream> +//using std::cout; using std::endl; +#include <iomanip> +//using std::setw; using std::setprecision; +#include <limits> +//using std::numeric_limits; + +/* + +Let's suppose we want to find the root of a number ['a], and to start, compute the cube root. + +So the equation we want to solve is: + +__spaces ['f](x) = x[cubed] - a + +We will first solve this without using any information +about the slope or curvature of the cube root function. + +We then show how adding what we can know about this function, first just the slope, +the 1st derivation /f'(x)/, will speed homing in on the solution. + +Lastly we show how adding the curvature /f''(x)/ too will speed convergence even more. + +*/ + +//[root_finding_noderiv_1 + +template <class T> +struct cbrt_functor_noderiv +{ + // cube root of x using only function - no derivatives. + cbrt_functor_noderiv(T const& to_find_root_of) : a(to_find_root_of) + { /* Constructor just stores value a to find root of. */ } + T operator()(T const& x) + { + T fx = x*x*x - a; // Difference (estimate x^3 - a). + return fx; + } +private: + T a; // to be 'cube_rooted'. +}; +//] [/root_finding_noderiv_1 + +/* +Implementing the cube root function itself is fairly trivial now: +the hardest part is finding a good approximation to begin with. +In this case we'll just divide the exponent by three. +(There are better but more complex guess algorithms used in 'real-life'.) + +Cube root function is 'Really Well Behaved' in that it is monotonic +and has only one root (we leave negative values 'as an exercise for the student'). +*/ + +//[root_finding_noderiv_2 + +template <class T> +T cbrt_noderiv(T x) +{ + // return cube root of x using bracket_and_solve (no derivatives). + using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; // For bracket_and_solve_root. + + int exponent; + frexp(x, &exponent); // Get exponent of z (ignore mantissa). + T guess = ldexp(1., exponent/3); // Rough guess is to divide the exponent by three. + T factor = 2; // How big steps to take when searching. + + const boost::uintmax_t maxit = 20; // Limit to maximum iterations. + boost::uintmax_t it = maxit; // Initially our chosen max iterations, but updated with actual. + bool is_rising = true; // So if result if guess^3 is too low, then try increasing guess. + int digits = std::numeric_limits<T>::digits; // Maximum possible binary digits accuracy for type T. + // Some fraction of digits is used to control how accurate to try to make the result. + int get_digits = digits - 3; // We have to have a non-zero interval at each step, so + // maximum accuracy is digits - 1. But we also have to + // allow for inaccuracy in f(x), otherwise the last few + // iterations just thrash around. + eps_tolerance<T> tol(get_digits); // Set the tolerance. + std::pair<T, T> r = bracket_and_solve_root(cbrt_functor_noderiv<T>(x), guess, factor, is_rising, tol, it); + return r.first + (r.second - r.first)/2; // Midway between brackets is our result, if necessary we could + // return the result as an interval here. +} + +/*` + +[note The final parameter specifying a maximum number of iterations is optional. +However, it defaults to `boost::uintmax_t maxit = (std::numeric_limits<boost::uintmax_t>::max)();` +which is `18446744073709551615` and is more than anyone would wish to wait for! + +So it may be wise to chose some reasonable estimate of how many iterations may be needed, +In this case the function is so well behaved that we can chose a low value of 20. + +Internally when Boost.Math uses these functions, it sets the maximum iterations to +`policies::get_max_root_iterations<Policy>();`.] + +Should we have wished we can show how many iterations were used in `bracket_and_solve_root` +(this information is lost outside `cbrt_noderiv`), for example with: + + if (it >= maxit) + { + std::cout << "Unable to locate solution in " << maxit << " iterations:" + " Current best guess is between " << r.first << " and " << r.second << std::endl; + } + else + { + std::cout << "Converged after " << it << " (from maximum of " << maxit << " iterations)." << std::endl; + } + +for output like + + Converged after 11 (from maximum of 20 iterations). +*/ +//] [/root_finding_noderiv_2] + + +// Cube root with 1st derivative (slope) + +/* +We now solve the same problem, but using more information about the function, +to show how this can speed up finding the best estimate of the root. + +For the root function, the 1st differential (the slope of the tangent to a curve at any point) is known. + +If you need some reminders then +[@http://en.wikipedia.org/wiki/Derivative#Derivatives_of_elementary_functions Derivatives of elementary functions] +may help. + +Using the rule that the derivative of ['x[super n]] for positive n (actually all nonzero n) is ['n x[super n-1]], +allows us to get the 1st differential as ['3x[super 2]]. + +To see how this extra information is used to find a root, view +[@http://en.wikipedia.org/wiki/Newton%27s_method Newton-Raphson iterations] +and the [@http://en.wikipedia.org/wiki/Newton%27s_method#mediaviewer/File:NewtonIteration_Ani.gif animation]. + +We need to define a different functor `cbrt_functor_deriv` that returns +both the evaluation of the function to solve, along with its first derivative: + +To \'return\' two values, we use a `std::pair` of floating-point values +(though we could equally have used a std::tuple): +*/ + +//[root_finding_1_deriv_1 + +template <class T> +struct cbrt_functor_deriv +{ // Functor also returning 1st derivative. + cbrt_functor_deriv(T const& to_find_root_of) : a(to_find_root_of) + { // Constructor stores value a to find root of, + // for example: calling cbrt_functor_deriv<T>(a) to use to get cube root of a. + } + std::pair<T, T> operator()(T const& x) + { + // Return both f(x) and f'(x). + T fx = x*x*x - a; // Difference (estimate x^3 - value). + T dx = 3 * x*x; // 1st derivative = 3x^2. + return std::make_pair(fx, dx); // 'return' both fx and dx. + } +private: + T a; // Store value to be 'cube_rooted'. +}; + +/*`Our cube root function is now:*/ + +template <class T> +T cbrt_deriv(T x) +{ + // return cube root of x using 1st derivative and Newton_Raphson. + using namespace boost::math::tools; + int exponent; + frexp(x, &exponent); // Get exponent of z (ignore mantissa). + T guess = ldexp(1., exponent/3); // Rough guess is to divide the exponent by three. + T min = ldexp(0.5, exponent/3); // Minimum possible value is half our guess. + T max = ldexp(2., exponent/3); // Maximum possible value is twice our guess. + const int digits = std::numeric_limits<T>::digits; // Maximum possible binary digits accuracy for type T. + int get_digits = static_cast<int>(digits * 0.6); // Accuracy doubles with each step, so stop when we have + // just over half the digits correct. + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + T result = newton_raphson_iterate(cbrt_functor_deriv<T>(x), guess, min, max, get_digits, it); + return result; +} + +//] [/root_finding_1_deriv_1] + + +/* +[h3:cbrt_2_derivatives Cube root with 1st & 2nd derivative (slope & curvature)] + +Finally we define yet another functor `cbrt_functor_2deriv` that returns +both the evaluation of the function to solve, +along with its first *and second* derivatives: + +__spaces[''f](x) = 6x + +To \'return\' three values, we use a `tuple` of three floating-point values: +*/ + +//[root_finding_2deriv_1 + +template <class T> +struct cbrt_functor_2deriv +{ + // Functor returning both 1st and 2nd derivatives. + cbrt_functor_2deriv(T const& to_find_root_of) : a(to_find_root_of) + { // Constructor stores value a to find root of, for example: + // calling cbrt_functor_2deriv<T>(x) to get cube root of x, + } + std::tuple<T, T, T> operator()(T const& x) + { + // Return both f(x) and f'(x) and f''(x). + T fx = x*x*x - a; // Difference (estimate x^3 - value). + T dx = 3 * x*x; // 1st derivative = 3x^2. + T d2x = 6 * x; // 2nd derivative = 6x. + return std::make_tuple(fx, dx, d2x); // 'return' fx, dx and d2x. + } +private: + T a; // to be 'cube_rooted'. +}; + +/*`Our cube root function is now:*/ + +template <class T> +T cbrt_2deriv(T x) +{ + // return cube root of x using 1st and 2nd derivatives and Halley. + //using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; + int exponent; + frexp(x, &exponent); // Get exponent of z (ignore mantissa). + T guess = ldexp(1., exponent/3); // Rough guess is to divide the exponent by three. + T min = ldexp(0.5, exponent/3); // Minimum possible value is half our guess. + T max = ldexp(2., exponent/3); // Maximum possible value is twice our guess. + const int digits = std::numeric_limits<T>::digits; // Maximum possible binary digits accuracy for type T. + // digits used to control how accurate to try to make the result. + int get_digits = static_cast<int>(digits * 0.4); // Accuracy triples with each step, so stop when just + // over one third of the digits are correct. + boost::uintmax_t maxit = 20; + T result = halley_iterate(cbrt_functor_2deriv<T>(x), guess, min, max, get_digits, maxit); + return result; +} + +//] [/root_finding_2deriv_1] + +//[root_finding_2deriv_lambda + +template <class T> +T cbrt_2deriv_lambda(T x) +{ + // return cube root of x using 1st and 2nd derivatives and Halley. + //using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; + int exponent; + frexp(x, &exponent); // Get exponent of z (ignore mantissa). + T guess = ldexp(1., exponent / 3); // Rough guess is to divide the exponent by three. + T min = ldexp(0.5, exponent / 3); // Minimum possible value is half our guess. + T max = ldexp(2., exponent / 3); // Maximum possible value is twice our guess. + const int digits = std::numeric_limits<T>::digits; // Maximum possible binary digits accuracy for type T. + // digits used to control how accurate to try to make the result. + int get_digits = static_cast<int>(digits * 0.4); // Accuracy triples with each step, so stop when just + // over one third of the digits are correct. + boost::uintmax_t maxit = 20; + T result = halley_iterate( + // lambda function: + [x](const T& g){ return std::make_tuple(g * g * g - x, 3 * g * g, 6 * g); }, + guess, min, max, get_digits, maxit); + return result; +} + +//] [/root_finding_2deriv_lambda] +/* + +[h3 Fifth-root function] +Let's now suppose we want to find the [*fifth root] of a number ['a]. + +The equation we want to solve is : + +__spaces['f](x) = x[super 5] - a + +If your differentiation is a little rusty +(or you are faced with an equation whose complexity is daunting), +then you can get help, for example from the invaluable +[@http://www.wolframalpha.com/ WolframAlpha site.] + +For example, entering the command: `differentiate x ^ 5` + +or the Wolfram Language command: ` D[x ^ 5, x]` + +gives the output: `d/dx(x ^ 5) = 5 x ^ 4` + +and to get the second differential, enter: `second differentiate x ^ 5` + +or the Wolfram Language command: `D[x ^ 5, { x, 2 }]` + +to get the output: `d ^ 2 / dx ^ 2(x ^ 5) = 20 x ^ 3` + +To get a reference value, we can enter: [^fifth root 3126] + +or: `N[3126 ^ (1 / 5), 50]` + +to get a result with a precision of 50 decimal digits: + +5.0003199590478625588206333405631053401128722314376 + +(We could also get a reference value using Boost.Multiprecision - see below). + +The 1st and 2nd derivatives of x[super 5] are: + +__spaces['f]\'(x) = 5x[super 4] + +__spaces['f]\'\'(x) = 20x[super 3] + +*/ + +//[root_finding_fifth_1 +//] [/root_finding_fifth_1] + + +//[root_finding_fifth_functor_2deriv + +/*`Using these expressions for the derivatives, the functor is: +*/ + +template <class T> +struct fifth_functor_2deriv +{ + // Functor returning both 1st and 2nd derivatives. + fifth_functor_2deriv(T const& to_find_root_of) : a(to_find_root_of) + { /* Constructor stores value a to find root of, for example: */ } + + std::tuple<T, T, T> operator()(T const& x) + { + // Return both f(x) and f'(x) and f''(x). + T fx = boost::math::pow<5>(x) - a; // Difference (estimate x^3 - value). + T dx = 5 * boost::math::pow<4>(x); // 1st derivative = 5x^4. + T d2x = 20 * boost::math::pow<3>(x); // 2nd derivative = 20 x^3 + return std::make_tuple(fx, dx, d2x); // 'return' fx, dx and d2x. + } +private: + T a; // to be 'fifth_rooted'. +}; // struct fifth_functor_2deriv + +//] [/root_finding_fifth_functor_2deriv] + +//[root_finding_fifth_2deriv + +/*`Our fifth-root function is now: +*/ + +template <class T> +T fifth_2deriv(T x) +{ + // return fifth root of x using 1st and 2nd derivatives and Halley. + using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; // for halley_iterate. + + int exponent; + frexp(x, &exponent); // Get exponent of z (ignore mantissa). + T guess = ldexp(1., exponent / 5); // Rough guess is to divide the exponent by five. + T min = ldexp(0.5, exponent / 5); // Minimum possible value is half our guess. + T max = ldexp(2., exponent / 5); // Maximum possible value is twice our guess. + // Stop when slightly more than one of the digits are correct: + const int digits = static_cast<int>(std::numeric_limits<T>::digits * 0.4); + const boost::uintmax_t maxit = 50; + boost::uintmax_t it = maxit; + T result = halley_iterate(fifth_functor_2deriv<T>(x), guess, min, max, digits, it); + return result; +} + +//] [/root_finding_fifth_2deriv] + + +int main() +{ + std::cout << "Root finding Examples." << std::endl; + std::cout.precision(std::numeric_limits<double>::max_digits10); + // Show all possibly significant decimal digits for double. + // std::cout.precision(std::numeric_limits<double>::digits10); + // Show all guaranteed significant decimal digits for double. + + +//[root_finding_main_1 + try + { + double threecubed = 27.; // Value that has an *exactly representable* integer cube root. + double threecubedp1 = 28.; // Value whose cube root is *not* exactly representable. + + std::cout << "cbrt(28) " << boost::math::cbrt(28.) << std::endl; // boost::math:: version of cbrt. + std::cout << "std::cbrt(28) " << std::cbrt(28.) << std::endl; // std:: version of cbrt. + std::cout <<" cast double " << static_cast<double>(3.0365889718756625194208095785056696355814539772481111) << std::endl; + + // Cube root using bracketing: + double r = cbrt_noderiv(threecubed); + std::cout << "cbrt_noderiv(" << threecubed << ") = " << r << std::endl; + r = cbrt_noderiv(threecubedp1); + std::cout << "cbrt_noderiv(" << threecubedp1 << ") = " << r << std::endl; +//] [/root_finding_main_1] + //[root_finding_main_2 + + // Cube root using 1st differential Newton-Raphson: + r = cbrt_deriv(threecubed); + std::cout << "cbrt_deriv(" << threecubed << ") = " << r << std::endl; + r = cbrt_deriv(threecubedp1); + std::cout << "cbrt_deriv(" << threecubedp1 << ") = " << r << std::endl; + + // Cube root using Halley with 1st and 2nd differentials. + r = cbrt_2deriv(threecubed); + std::cout << "cbrt_2deriv(" << threecubed << ") = " << r << std::endl; + r = cbrt_2deriv(threecubedp1); + std::cout << "cbrt_2deriv(" << threecubedp1 << ") = " << r << std::endl; + + // Cube root using lambda's: + r = cbrt_2deriv_lambda(threecubed); + std::cout << "cbrt_2deriv(" << threecubed << ") = " << r << std::endl; + r = cbrt_2deriv_lambda(threecubedp1); + std::cout << "cbrt_2deriv(" << threecubedp1 << ") = " << r << std::endl; + + // Fifth root. + + double fivepowfive = 3125; // Example of a value that has an exact integer fifth root. + // Exact value of fifth root is exactly 5. + std::cout << "Fifth root of " << fivepowfive << " is " << 5 << std::endl; + + double fivepowfivep1 = fivepowfive + 1; // Example of a value whose fifth root is *not* exactly representable. + // Value of fifth root is 5.0003199590478625588206333405631053401128722314376 (50 decimal digits precision) + // and to std::numeric_limits<double>::max_digits10 double precision (usually 17) is + + double root5v2 = static_cast<double>(5.0003199590478625588206333405631053401128722314376); + std::cout << "Fifth root of " << fivepowfivep1 << " is " << root5v2 << std::endl; + + // Using Halley with 1st and 2nd differentials. + r = fifth_2deriv(fivepowfive); + std::cout << "fifth_2deriv(" << fivepowfive << ") = " << r << std::endl; + r = fifth_2deriv(fivepowfivep1); + std::cout << "fifth_2deriv(" << fivepowfivep1 << ") = " << r << std::endl; +//] [/root_finding_main_?] + } + catch(const std::exception& e) + { // Always useful to include try & catch blocks because default policies + // are to throw exceptions on arguments that cause errors like underflow, overflow. + // Lacking try & catch blocks, the program will abort without a message below, + // which may give some helpful clues as to the cause of the exception. + std::cout << + "\n""Message from thrown exception was:\n " << e.what() << std::endl; + } + return 0; +} // int main() + +//[root_finding_example_output +/*` +Normal output is: + +[pre + root_finding_example.cpp + Generating code + Finished generating code + root_finding_example.vcxproj -> J:\Cpp\MathToolkit\test\Math_test\Release\root_finding_example.exe + Cube Root finding (cbrt) Example. + Iterations 10 + cbrt_1(27) = 3 + Iterations 10 + Unable to locate solution in chosen iterations: Current best guess is between 3.0365889718756613 and 3.0365889718756627 + cbrt_1(28) = 3.0365889718756618 + cbrt_1(27) = 3 + cbrt_2(28) = 3.0365889718756627 + Iterations 4 + cbrt_3(27) = 3 + Iterations 5 + cbrt_3(28) = 3.0365889718756627 + +] [/pre] + +to get some (much!) diagnostic output we can add + +#define BOOST_MATH_INSTRUMENT + +[pre + +] +*/ +//] [/root_finding_example_output] + +/* + +cbrt(28) 3.0365889718756622 +std::cbrt(28) 3.0365889718756627 + +*/ diff --git a/src/boost/libs/math/example/root_finding_fifth.cpp b/src/boost/libs/math/example/root_finding_fifth.cpp new file mode 100644 index 000000000..6c9811475 --- /dev/null +++ b/src/boost/libs/math/example/root_finding_fifth.cpp @@ -0,0 +1,485 @@ +// root_finding_fith.cpp + +// Copyright Paul A. Bristow 2014. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Example of finding fifth root using Newton-Raphson, Halley, Schroder, TOMS748 . + +// Note that this file contains Quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +// To get (copious!) diagnostic output, add make this define here or elsewhere. +//#define BOOST_MATH_INSTRUMENT + + +//[root_fifth_headers +/* +This example demonstrates how to use the Boost.Math tools for root finding, +taking the fifth root function (fifth_root) as an example. +It shows how use of derivatives can improve the speed. + +First some includes that will be needed. +Using statements are provided to list what functions are being used in this example: +you can of course qualify the names in other ways. +*/ + +#include <boost/math/tools/roots.hpp> +using boost::math::policies::policy; +using boost::math::tools::newton_raphson_iterate; +using boost::math::tools::halley_iterate; +using boost::math::tools::eps_tolerance; // Binary functor for specified number of bits. +using boost::math::tools::bracket_and_solve_root; +using boost::math::tools::toms748_solve; + +#include <boost/math/special_functions/next.hpp> + +#include <tuple> +#include <utility> // pair, make_pair + +//] [/root_finding_headers] + +#include <iostream> +using std::cout; using std::endl; +#include <iomanip> +using std::setw; using std::setprecision; +#include <limits> +using std::numeric_limits; + +/* +//[root_finding_fifth_1 +Let's suppose we want to find the fifth root of a number. + +The equation we want to solve is: + +__spaces ['f](x) = x[fifth] + +We will first solve this without using any information +about the slope or curvature of the fifth function. + +If your differentiation is a little rusty +(or you are faced with an equation whose complexity is daunting, +then you can get help, for example from the invaluable + +http://www.wolframalpha.com/ site + +entering the command + + differentiate x^5 + +or the Wolfram Language command + + D[x^5, x] + +gives the output + + d/dx(x^5) = 5 x^4 + +and to get the second differential, enter + + second differentiate x^5 + +or the Wolfram Language + + D[x^5, {x, 2}] + +to get the output + + d^2/dx^2(x^5) = 20 x^3 + +or + + 20 x^3 + +To get a reference value we can enter + + fifth root 3126 + +or + + N[3126^(1/5), 50] + +to get a result with a precision of 50 decimal digits + + 5.0003199590478625588206333405631053401128722314376 + +(We could also get a reference value using Boost.Multiprecision). + +We then show how adding what we can know, for this function, about the slope, +the 1st derivation /f'(x)/, will speed homing in on the solution, +and then finally how adding the curvature /f''(x)/ as well will improve even more. + +The 1st and 2nd derivatives of x[fifth] are: + +__spaces ['f]\'(x) = 2x[sup2] + +__spaces ['f]\'\'(x) = 6x + +*/ + +//] [/root_finding_fifth_1] + +//[root_finding_fifth_functor_noderiv + +template <class T> +struct fifth_functor_noderiv +{ // fifth root of x using only function - no derivatives. + fifth_functor_noderiv(T const& to_find_root_of) : value(to_find_root_of) + { // Constructor stores value to find root of. + // For example: calling fifth_functor<T>(x) to get fifth root of x. + } + T operator()(T const& x) + { //! \returns f(x) - value. + T fx = x*x*x*x*x - value; // Difference (estimate x^5 - value). + return fx; + } +private: + T value; // to be 'fifth_rooted'. +}; + +//] [/root_finding_fifth_functor_noderiv] + +//cout << ", std::numeric_limits<" << typeid(T).name() << ">::digits = " << digits +// << ", accuracy " << get_digits << " bits."<< endl; + + +/*`Implementing the fifth root function itself is fairly trivial now: +the hardest part is finding a good approximation to begin with. +In this case we'll just divide the exponent by five. +(There are better but more complex guess algorithms used in 'real-life'.) + +fifth root function is 'Really Well Behaved' in that it is monotonic +and has only one root +(we leave negative values 'as an exercise for the student'). +*/ + +//[root_finding_fifth_noderiv + +template <class T> +T fifth_noderiv(T x) +{ //! \returns fifth root of x using bracket_and_solve (no derivatives). + using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; // For bracket_and_solve_root. + + int exponent; + frexp(x, &exponent); // Get exponent of z (ignore mantissa). + T guess = ldexp(1., exponent / 5); // Rough guess is to divide the exponent by five. + T factor = 2; // To multiply and divide guess to bracket. + // digits used to control how accurate to try to make the result. + // int digits = 3 * std::numeric_limits<T>::digits / 4; // 3/4 maximum possible binary digits accuracy for type T. + int digits = std::numeric_limits<T>::digits; // Maximum possible binary digits accuracy for type T. + + //boost::uintmax_t maxit = (std::numeric_limits<boost::uintmax_t>::max)(); + // (std::numeric_limits<boost::uintmax_t>::max)() = 18446744073709551615 + // which is more than anyone might wish to wait for!!! + // so better to choose some reasonable estimate of how many iterations may be needed. + + const boost::uintmax_t maxit = 50; // Chosen max iterations, + // but updated on exit with actual iteration count. + + // We could also have used a maximum iterations provided by any policy: + // boost::uintmax_t max_it = policies::get_max_root_iterations<Policy>(); + + boost::uintmax_t it = maxit; // Initially our chosen max iterations, + + bool is_rising = true; // So if result if guess^5 is too low, try increasing guess. + eps_tolerance<double> tol(digits); + std::pair<T, T> r = + bracket_and_solve_root(fifth_functor_noderiv<T>(x), guess, factor, is_rising, tol, it); + // because the iteration count is updating, + // you can't call with a literal maximum iterations value thus: + //bracket_and_solve_root(fifth_functor_noderiv<T>(x), guess, factor, is_rising, tol, 20); + + // Can show how many iterations (this information is lost outside fifth_noderiv). + cout << "Iterations " << it << endl; + if (it >= maxit) + { // Failed to converge (or is jumping between bracket values). + cout << "Unable to locate solution in chosen iterations:" + " Current best guess is between " << r.first << " and " << r.second << endl; + } + T distance = float_distance(r.first, r.second); + if (distance > 0) + { // + std::cout << distance << " bits separate the bracketing values." << std::endl; + for (int i = 0; i < distance; i++) + { // Show all the values within the bracketing values. + std::cout << float_advance(r.first, i) << std::endl; + } + } + else + { // distance == 0 and r.second == r.first + std::cout << "Converged to a single value " << r.first << std::endl; + } + + return r.first + (r.second - r.first) / 2; // return midway between bracketed interval. +} // T fifth_noderiv(T x) + +//] [/root_finding_fifth_noderiv] + + + +// maxit = 10 +// Unable to locate solution in chosen iterations: Current best guess is between 3.0365889718756613 and 3.0365889718756627 + + +/*` +We now solve the same problem, but using more information about the function, +to show how this can speed up finding the best estimate of the root. + +For this function, the 1st differential (the slope of the tangent to a curve at any point) is known. + +[@http://en.wikipedia.org/wiki/Derivative#Derivatives_of_elementary_functions Derivatives] +gives some reminders. + +Using the rule that the derivative of x^n for positive n (actually all nonzero n) is nx^n-1, +allows use to get the 1st differential as 3x^2. + +To see how this extra information is used to find the root, view this demo: +[@http://en.wikipedia.org/wiki/Newton%27s_methodNewton Newton-Raphson iterations]. + +We need to define a different functor that returns +both the evaluation of the function to solve, along with its first derivative: + +To \'return\' two values, we use a pair of floating-point values: +*/ + +//[root_finding_fifth_functor_1stderiv + +template <class T> +struct fifth_functor_1stderiv +{ // Functor returning function and 1st derivative. + + fifth_functor_1stderiv(T const& target) : value(target) + { // Constructor stores the value to be 'fifth_rooted'. + } + + std::pair<T, T> operator()(T const& z) // z is best estimate so far. + { // Return both f(x) and first derivative f'(x). + T fx = z*z*z*z*z - value; // Difference estimate fx = x^5 - value. + T d1x = 5 * z*z*z*z; // 1st derivative d1x = 5x^4. + return std::make_pair(fx, d1x); // 'return' both fx and d1x. + } +private: + T value; // to be 'fifth_rooted'. +}; // fifth_functor_1stderiv + +//] [/root_finding_fifth_functor_1stderiv] + + +/*`Our fifth root function using fifth_functor_1stderiv is now:*/ + +//[root_finding_fifth_1deriv + +template <class T> +T fifth_1deriv(T x) +{ //! \return fifth root of x using 1st derivative and Newton_Raphson. + using namespace std; // For frexp, ldexp, numeric_limits. + using namespace boost::math::tools; // For newton_raphson_iterate. + + int exponent; + frexp(x, &exponent); // Get exponent of x (ignore mantissa). + T guess = ldexp(1., exponent / 5); // Rough guess is to divide the exponent by three. + // Set an initial bracket interval. + T min = ldexp(0.5, exponent / 5); // Minimum possible value is half our guess. + T max = ldexp(2., exponent / 5);// Maximum possible value is twice our guess. + + // digits used to control how accurate to try to make the result. + int digits = std::numeric_limits<T>::digits; // Maximum possible binary digits accuracy for type T. + + const boost::uintmax_t maxit = 20; // Optionally limit the number of iterations. + boost::uintmax_t it = maxit; // limit the number of iterations. + //cout << "Max Iterations " << maxit << endl; // + T result = newton_raphson_iterate(fifth_functor_1stderiv<T>(x), guess, min, max, digits, it); + // Can check and show how many iterations (updated by newton_raphson_iterate). + cout << it << " iterations (from max of " << maxit << ")" << endl; + return result; +} // fifth_1deriv + +//] [/root_finding_fifth_1deriv] + +// int get_digits = (digits * 2) /3; // Two thirds of maximum possible accuracy. + +//boost::uintmax_t maxit = (std::numeric_limits<boost::uintmax_t>::max)(); +// the default (std::numeric_limits<boost::uintmax_t>::max)() = 18446744073709551615 +// which is more than we might wish to wait for!!! so we can reduce it + +/*` +Finally need to define yet another functor that returns +both the evaluation of the function to solve, +along with its first and second derivatives: + +f''(x) = 3 * 3x + +To \'return\' three values, we use a tuple of three floating-point values: +*/ + +//[root_finding_fifth_functor_2deriv + +template <class T> +struct fifth_functor_2deriv +{ // Functor returning both 1st and 2nd derivatives. + fifth_functor_2deriv(T const& to_find_root_of) : value(to_find_root_of) + { // Constructor stores value to find root of, for example: + } + + // using boost::math::tuple; // to return three values. + std::tuple<T, T, T> operator()(T const& x) + { // Return both f(x) and f'(x) and f''(x). + T fx = x*x*x*x*x - value; // Difference (estimate x^3 - value). + T dx = 5 * x*x*x*x; // 1st derivative = 5x^4. + T d2x = 20 * x*x*x; // 2nd derivative = 20 x^3 + return std::make_tuple(fx, dx, d2x); // 'return' fx, dx and d2x. + } +private: + T value; // to be 'fifth_rooted'. +}; // struct fifth_functor_2deriv + +//] [/root_finding_fifth_functor_2deriv] + + +/*`Our fifth function is now:*/ + +//[root_finding_fifth_2deriv + +template <class T> +T fifth_2deriv(T x) +{ // return fifth root of x using 1st and 2nd derivatives and Halley. + using namespace std; // Help ADL of std functions. + using namespace boost::math; // halley_iterate + + int exponent; + frexp(x, &exponent); // Get exponent of z (ignore mantissa). + T guess = ldexp(1., exponent / 5); // Rough guess is to divide the exponent by three. + T min = ldexp(0.5, exponent / 5); // Minimum possible value is half our guess. + T max = ldexp(2., exponent / 5); // Maximum possible value is twice our guess. + + int digits = std::numeric_limits<T>::digits / 2; // Half maximum possible binary digits accuracy for type T. + const boost::uintmax_t maxit = 50; + boost::uintmax_t it = maxit; + T result = halley_iterate(fifth_functor_2deriv<T>(x), guess, min, max, digits, it); + // Can show how many iterations (updated by halley_iterate). + cout << it << " iterations (from max of " << maxit << ")" << endl; + + return result; +} // fifth_2deriv(x) + +//] [/root_finding_fifth_2deriv] + +int main() +{ + + //[root_finding_example_1 + cout << "fifth Root finding (fifth) Example." << endl; + // Show all possibly significant decimal digits. + cout.precision(std::numeric_limits<double>::max_digits10); + // or use cout.precision(max_digits10 = 2 + std::numeric_limits<double>::digits * 3010/10000); + try + { // Always use try'n'catch blocks with Boost.Math to get any error messages. + + double v27 = 3125; // Example of a value that has an exact integer fifth root. + // exact value of fifth root is exactly 5. + + std::cout << "Fifth root of " << v27 << " is " << 5 << std::endl; + + double v28 = v27+1; // Example of a value whose fifth root is *not* exactly representable. + // Value of fifth root is 5.0003199590478625588206333405631053401128722314376 (50 decimal digits precision) + // and to std::numeric_limits<double>::max_digits10 double precision (usually 17) is + + double root5v2 = static_cast<double>(5.0003199590478625588206333405631053401128722314376); + + std::cout << "Fifth root of " << v28 << " is " << root5v2 << std::endl; + + // Using bracketing: + double r = fifth_noderiv(v27); + cout << "fifth_noderiv(" << v27 << ") = " << r << endl; + + r = fifth_noderiv(v28); + cout << "fifth_noderiv(" << v28 << ") = " << r << endl; + + // Using 1st differential Newton-Raphson: + r = fifth_1deriv(v27); + cout << "fifth_1deriv(" << v27 << ") = " << r << endl; + r = fifth_1deriv(v28); + cout << "fifth_1deriv(" << v28 << ") = " << r << endl; + + // Using Halley with 1st and 2nd differentials. + r = fifth_2deriv(v27); + cout << "fifth_2deriv(" << v27 << ") = " << r << endl; + r = fifth_2deriv(v28); + cout << "fifth_2deriv(" << v28 << ") = " << r << endl; + } + catch (const std::exception& e) + { // Always useful to include try & catch blocks because default policies + // are to throw exceptions on arguments that cause errors like underflow, overflow. + // Lacking try & catch blocks, the program will abort without a message below, + // which may give some helpful clues as to the cause of the exception. + std::cout << + "\n""Message from thrown exception was:\n " << e.what() << std::endl; + } + //] [/root_finding_example_1 + return 0; +} // int main() + +//[root_finding_example_output +/*` +Normal output is: + +[pre +1> Description: Autorun "J:\Cpp\MathToolkit\test\Math_test\Release\root_finding_fifth.exe" +1> fifth Root finding (fifth) Example. +1> Fifth root of 3125 is 5 +1> Fifth root of 3126 is 5.0003199590478626 +1> Iterations 10 +1> Converged to a single value 5 +1> fifth_noderiv(3125) = 5 +1> Iterations 11 +1> 2 bits separate the bracketing values. +1> 5.0003199590478609 +1> 5.0003199590478618 +1> fifth_noderiv(3126) = 5.0003199590478618 +1> 6 iterations (from max of 20) +1> fifth_1deriv(3125) = 5 +1> 7 iterations (from max of 20) +1> fifth_1deriv(3126) = 5.0003199590478626 +1> 4 iterations (from max of 50) +1> fifth_2deriv(3125) = 5 +1> 4 iterations (from max of 50) +1> fifth_2deriv(3126) = 5.0003199590478626 +[/pre] + +to get some (much!) diagnostic output we can add + +#define BOOST_MATH_INSTRUMENT + +[pre +1> fifth Root finding (fifth) Example. +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:537 a = 4 b = 8 fa = -2101 fb = 29643 count = 18 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:340 a = 4.264742943548387 b = 8 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:352 a = 4.264742943548387 b = 5.1409225585147951 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:259 a = 4.264742943548387 b = 5.1409225585147951 d = 8 e = 4 fa = -1714.2037505671719 fb = 465.91652114644285 fd = 29643 fe = -2101 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:267 q11 = -3.735257056451613 q21 = -0.045655399937094755 q31 = 0.68893005658139972 d21 = -2.9047328414222999 d31 = -0.18724955838500826 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:275 q22 = -0.15074699539567221 q32 = 0.007740525571111408 d32 = -0.13385363287680208 q33 = 0.074868009790687237 c = 5.0362815354915851 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:388 a = 4.264742943548387 b = 5.0362815354915851 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:259 a = 4.264742943548387 b = 5.0362815354915851 d = 5.1409225585147951 e = 8 fa = -1714.2037505671719 fb = 115.03721886368339 fd = 465.91652114644285 fe = 29643 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:267 q11 = -0.045655399937094755 q21 = -0.034306988726112195 q31 = 0.7230181097615842 d21 = -0.1389480117493222 d31 = -0.048520482181613811 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:275 q22 = -0.00036345624935100459 q32 = 0.011175908093791367 d32 = -0.0030375853617102483 q33 = 0.00014618657296010219 c = 4.999083147976723 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:408 a = 4.999083147976723 b = 5.0362815354915851 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:433 a = 4.999083147976723 b = 5.0008904277935091 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:434 tol = -0.00036152225583956088 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:259 a = 4.999083147976723 b = 5.0008904277935091 d = 5.0362815354915851 e = 4.264742943548387 fa = -2.8641119933622576 fb = 2.7835781082976609 fd = 115.03721886368339 fe = -1714.2037505671719 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:267 q11 = -0.048520482181613811 q21 = -0.00087760104664616457 q31 = 0.00091652546535745522 d21 = -0.036268708744722128 d31 = -0.00089075435142862297 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:275 q22 = -1.9862562616034592e-005 q32 = 3.1952597740788757e-007 d32 = -1.2833778805050512e-005 q33 = 1.1763429980834706e-008 c = 5.0000000047314881 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:388 a = 4.999083147976723 b = 5.0000000047314881 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:259 a = 4.999083147976723 b = 5.0000000047314881 d = 5.0008904277935091 e = 5.0362815354915851 fa = -2.8641119933622576 fb = 1.4785900475544622e-005 fd = 2.7835781082976609 fe = 115.03721886368339 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:267 q11 = -0.00087760104664616457 q21 = -4.7298032238887272e-009 q31 = 0.00091685202154135855 d21 = -0.00089042779182425238 d31 = -4.7332236912279757e-009 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:275 q22 = -1.6486403607318402e-012 q32 = 1.7346209428817704e-012 d32 = -1.6858463963666777e-012 q33 = 9.0382569995250912e-016 c = 5 +1> I:\modular-boost\boost/math/tools/toms748_solve.hpp:592 max_iter = 10 count = 7 +1> Iterations 20 +1> 0 bits separate brackets. +1> fifth_noderiv(3125) = 5 +] +*/ +//] [/root_finding_example_output] diff --git a/src/boost/libs/math/example/root_finding_multiprecision_example.cpp b/src/boost/libs/math/example/root_finding_multiprecision_example.cpp new file mode 100644 index 000000000..0b1452ba1 --- /dev/null +++ b/src/boost/libs/math/example/root_finding_multiprecision_example.cpp @@ -0,0 +1,232 @@ +// Copyright Paul A. Bristow 2015. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains Quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +// Example of root finding using Boost.Multiprecision. + +#include <boost/math/tools/roots.hpp> +//using boost::math::policies::policy; +//using boost::math::tools::newton_raphson_iterate; +//using boost::math::tools::halley_iterate; +//using boost::math::tools::eps_tolerance; // Binary functor for specified number of bits. +//using boost::math::tools::bracket_and_solve_root; +//using boost::math::tools::toms748_solve; + +#include <boost/math/special_functions/next.hpp> // For float_distance. +#include <boost/math/special_functions/pow.hpp> +#include <boost/math/constants/constants.hpp> + +//[root_finding_multiprecision_include_1 +#include <boost/multiprecision/cpp_bin_float.hpp> // For cpp_bin_float_50. +#include <boost/multiprecision/cpp_dec_float.hpp> // For cpp_dec_float_50. +#ifndef _MSC_VER // float128 is not yet supported by Microsoft compiler at 2013. +# include <boost/multiprecision/float128.hpp> // Requires libquadmath. +#endif +//] [/root_finding_multiprecision_include_1] + +#include <iostream> +// using std::cout; using std::endl; +#include <iomanip> +// using std::setw; using std::setprecision; +#include <limits> +// using std::numeric_limits; +#include <tuple> +#include <utility> // pair, make_pair + +// #define BUILTIN_POW_GUESS // define to use std::pow function to obtain a guess. + +template <class T> +T cbrt_2deriv(T x) +{ // return cube root of x using 1st and 2nd derivatives and Halley. + using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; // For halley_iterate. + + // If T is not a binary floating-point type, for example, cpp_dec_float_50 + // then frexp may not be defined, + // so it may be necessary to compute the guess using a built-in type, + // probably quickest using double, but perhaps with float or long double. + // Note that the range of exponent may be restricted by a built-in-type for guess. + + typedef long double guess_type; + +#ifdef BUILTIN_POW_GUESS + guess_type pow_guess = std::pow(static_cast<guess_type>(x), static_cast<guess_type>(1) / 3); + T guess = pow_guess; + T min = pow_guess /2; + T max = pow_guess * 2; +#else + int exponent; + frexp(static_cast<guess_type>(x), &exponent); // Get exponent of z (ignore mantissa). + T guess = ldexp(static_cast<guess_type>(1.), exponent / 3); // Rough guess is to divide the exponent by three. + T min = ldexp(static_cast<guess_type>(1.) / 2, exponent / 3); // Minimum possible value is half our guess. + T max = ldexp(static_cast<guess_type>(2.), exponent / 3); // Maximum possible value is twice our guess. +#endif + + int digits = std::numeric_limits<T>::digits / 2; // Half maximum possible binary digits accuracy for type T. + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + T result = halley_iterate(cbrt_functor_2deriv<T>(x), guess, min, max, digits, it); + // Can show how many iterations (updated by halley_iterate). + // std::cout << "Iterations " << it << " (from max of "<< maxit << ")." << std::endl; + return result; +} // cbrt_2deriv(x) + + +template <class T> +struct cbrt_functor_2deriv +{ // Functor returning both 1st and 2nd derivatives. + cbrt_functor_2deriv(T const& to_find_root_of) : a(to_find_root_of) + { // Constructor stores value to find root of, for example: + } + + // using boost::math::tuple; // to return three values. + std::tuple<T, T, T> operator()(T const& x) + { + // Return both f(x) and f'(x) and f''(x). + T fx = x*x*x - a; // Difference (estimate x^3 - value). + // std::cout << "x = " << x << "\nfx = " << fx << std::endl; + T dx = 3 * x*x; // 1st derivative = 3x^2. + T d2x = 6 * x; // 2nd derivative = 6x. + return std::make_tuple(fx, dx, d2x); // 'return' fx, dx and d2x. + } +private: + T a; // to be 'cube_rooted'. +}; // struct cbrt_functor_2deriv + +template <int n, class T> +struct nth_functor_2deriv +{ // Functor returning both 1st and 2nd derivatives. + + nth_functor_2deriv(T const& to_find_root_of) : value(to_find_root_of) + { /* Constructor stores value to find root of, for example: */ } + + // using std::tuple; // to return three values. + std::tuple<T, T, T> operator()(T const& x) + { + // Return both f(x) and f'(x) and f''(x). + using boost::math::pow; + T fx = pow<n>(x) - value; // Difference (estimate x^3 - value). + T dx = n * pow<n - 1>(x); // 1st derivative = 5x^4. + T d2x = n * (n - 1) * pow<n - 2 >(x); // 2nd derivative = 20 x^3 + return std::make_tuple(fx, dx, d2x); // 'return' fx, dx and d2x. + } +private: + T value; // to be 'nth_rooted'. +}; // struct nth_functor_2deriv + + +template <int n, class T> +T nth_2deriv(T x) +{ + // return nth root of x using 1st and 2nd derivatives and Halley. + using namespace std; // Help ADL of std functions. + using namespace boost::math; // For halley_iterate. + + int exponent; + frexp(x, &exponent); // Get exponent of z (ignore mantissa). + T guess = ldexp(static_cast<T>(1.), exponent / n); // Rough guess is to divide the exponent by three. + T min = ldexp(static_cast<T>(0.5), exponent / n); // Minimum possible value is half our guess. + T max = ldexp(static_cast<T>(2.), exponent / n); // Maximum possible value is twice our guess. + + int digits = std::numeric_limits<T>::digits / 2; // Half maximum possible binary digits accuracy for type T. + const boost::uintmax_t maxit = 50; + boost::uintmax_t it = maxit; + T result = halley_iterate(nth_functor_2deriv<n, T>(x), guess, min, max, digits, it); + // Can show how many iterations (updated by halley_iterate). + std::cout << it << " iterations (from max of " << maxit << ")" << std::endl; + + return result; +} // nth_2deriv(x) + +//[root_finding_multiprecision_show_1 + +template <typename T> +T show_cube_root(T value) +{ // Demonstrate by printing the root using all definitely significant digits. + std::cout.precision(std::numeric_limits<T>::digits10); + T r = cbrt_2deriv(value); + std::cout << "value = " << value << ", cube root =" << r << std::endl; + return r; +} + +//] [/root_finding_multiprecision_show_1] + +int main() +{ + std::cout << "Multiprecision Root finding Example." << std::endl; + // Show all possibly significant decimal digits. + std::cout.precision(std::numeric_limits<double>::digits10); + // or use cout.precision(max_digits10 = 2 + std::numeric_limits<double>::digits * 3010/10000); + //[root_finding_multiprecision_example_1 + using boost::multiprecision::cpp_dec_float_50; // decimal. + using boost::multiprecision::cpp_bin_float_50; // binary. +#ifndef _MSC_VER // Not supported by Microsoft compiler. + using boost::multiprecision::float128; +#endif + //] [/root_finding_multiprecision_example_1 + + try + { // Always use try'n'catch blocks with Boost.Math to get any error messages. + // Increase the precision to 50 decimal digits using Boost.Multiprecision +//[root_finding_multiprecision_example_2 + + std::cout.precision(std::numeric_limits<cpp_dec_float_50>::digits10); + + cpp_dec_float_50 two = 2; // + cpp_dec_float_50 r = cbrt_2deriv(two); + std::cout << "cbrt(" << two << ") = " << r << std::endl; + + r = cbrt_2deriv(2.); // Passing a double, so ADL will compute a double precision result. + std::cout << "cbrt(" << two << ") = " << r << std::endl; + // cbrt(2) = 1.2599210498948731906665443602832965552806854248047 'wrong' from digits 17 onwards! + r = cbrt_2deriv(static_cast<cpp_dec_float_50>(2.)); // Passing a cpp_dec_float_50, + // so will compute a cpp_dec_float_50 precision result. + std::cout << "cbrt(" << two << ") = " << r << std::endl; + r = cbrt_2deriv<cpp_dec_float_50>(2.); // Explicitly a cpp_dec_float_50, so will compute a cpp_dec_float_50 precision result. + std::cout << "cbrt(" << two << ") = " << r << std::endl; + // cpp_dec_float_50 1.2599210498948731647672106072782283505702514647015 +//] [/root_finding_multiprecision_example_2 + // N[2^(1/3), 50] 1.2599210498948731647672106072782283505702514647015 + + //show_cube_root(2); // Integer parameter - Errors! + //show_cube_root(2.F); // Float parameter - Warnings! +//[root_finding_multiprecision_example_3 + show_cube_root(2.); + show_cube_root(2.L); + show_cube_root(two); + +//] [/root_finding_multiprecision_example_3 + + } + catch (const std::exception& e) + { // Always useful to include try&catch blocks because default policies + // are to throw exceptions on arguments that cause errors like underflow & overflow. + // Lacking try&catch blocks, the program will abort without a message below, + // which may give some helpful clues as to the cause of the exception. + std::cout << + "\n""Message from thrown exception was:\n " << e.what() << std::endl; + } + return 0; +} // int main() + + +/* + +Description: Autorun "J:\Cpp\MathToolkit\test\Math_test\Release\root_finding_multiprecision.exe" +Multiprecision Root finding Example. +cbrt(2) = 1.2599210498948731647672106072782283505702514647015 +cbrt(2) = 1.2599210498948731906665443602832965552806854248047 +cbrt(2) = 1.2599210498948731647672106072782283505702514647015 +cbrt(2) = 1.2599210498948731647672106072782283505702514647015 +value = 2, cube root =1.25992104989487 +value = 2, cube root =1.25992104989487 +value = 2, cube root =1.2599210498948731647672106072782283505702514647015 + + +*/ diff --git a/src/boost/libs/math/example/root_finding_n_example.cpp b/src/boost/libs/math/example/root_finding_n_example.cpp new file mode 100644 index 000000000..096ed9545 --- /dev/null +++ b/src/boost/libs/math/example/root_finding_n_example.cpp @@ -0,0 +1,213 @@ +// Copyright Paul A. Bristow 2014, 2015. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Note that this file contains Quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! + +// Example of finding nth root using 1st and 2nd derivatives of x^n. + +#include <boost/math/tools/roots.hpp> +//using boost::math::policies::policy; +//using boost::math::tools::newton_raphson_iterate; +//using boost::math::tools::halley_iterate; +//using boost::math::tools::eps_tolerance; // Binary functor for specified number of bits. +//using boost::math::tools::bracket_and_solve_root; +//using boost::math::tools::toms748_solve; + +#include <boost/math/special_functions/next.hpp> +#include <boost/multiprecision/cpp_dec_float.hpp> +#include <boost/math/special_functions/pow.hpp> +#include <boost/math/constants/constants.hpp> + +#include <boost/multiprecision/cpp_dec_float.hpp> // For cpp_dec_float_50. +#include <boost/multiprecision/cpp_bin_float.hpp> // using boost::multiprecision::cpp_bin_float_50; +#ifndef _MSC_VER // float128 is not yet supported by Microsoft compiler at 2013. +# include <boost/multiprecision/float128.hpp> +#endif + +#include <iostream> +// using std::cout; using std::endl; +#include <iomanip> +// using std::setw; using std::setprecision; +#include <limits> +using std::numeric_limits; +#include <tuple> +#include <utility> // pair, make_pair + + +//[root_finding_nth_functor_2deriv +template <int N, class T = double> +struct nth_functor_2deriv +{ // Functor returning both 1st and 2nd derivatives. + BOOST_STATIC_ASSERT_MSG(boost::is_integral<T>::value == false, "Only floating-point type types can be used!"); + BOOST_STATIC_ASSERT_MSG((N > 0) == true, "root N must be > 0!"); + + nth_functor_2deriv(T const& to_find_root_of) : a(to_find_root_of) + { /* Constructor stores value a to find root of, for example: */ } + + // using boost::math::tuple; // to return three values. + std::tuple<T, T, T> operator()(T const& x) + { + // Return f(x), f'(x) and f''(x). + using boost::math::pow; + T fx = pow<N>(x) - a; // Difference (estimate x^n - a). + T dx = N * pow<N - 1>(x); // 1st derivative f'(x). + T d2x = N * (N - 1) * pow<N - 2 >(x); // 2nd derivative f''(x). + + return std::make_tuple(fx, dx, d2x); // 'return' fx, dx and d2x. + } +private: + T a; // to be 'nth_rooted'. +}; + +//] [/root_finding_nth_functor_2deriv] + +/* +To show the progress, one might use this before the return statement above? +#ifdef BOOST_MATH_ROOT_DIAGNOSTIC +std::cout << " x = " << x << ", fx = " << fx << ", dx = " << dx << ", dx2 = " << d2x << std::endl; +#endif +*/ + +// If T is a floating-point type, might be quicker to compute the guess using a built-in type, +// probably quickest using double, but perhaps with float or long double, T. + +// If T is a type for which frexp and ldexp are not defined, +// then it is necessary to compute the guess using a built-in type, +// probably quickest (but limited range) using double, +// but perhaps with float or long double, or a multiprecision T for the full range of T. +// typedef double guess_type; is used to specify the this. + +//[root_finding_nth_function_2deriv + +template <int N, class T = double> +T nth_2deriv(T x) +{ // return nth root of x using 1st and 2nd derivatives and Halley. + + using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; // For halley_iterate. + + BOOST_STATIC_ASSERT_MSG(boost::is_integral<T>::value == false, "Only floating-point type types can be used!"); + BOOST_STATIC_ASSERT_MSG((N > 0) == true, "root N must be > 0!"); + BOOST_STATIC_ASSERT_MSG((N > 1000) == false, "root N is too big!"); + + typedef double guess_type; // double may restrict (exponent) range for a multiprecision T? + + int exponent; + frexp(static_cast<guess_type>(x), &exponent); // Get exponent of z (ignore mantissa). + T guess = ldexp(static_cast<guess_type>(1.), exponent / N); // Rough guess is to divide the exponent by n. + T min = ldexp(static_cast<guess_type>(1.) / 2, exponent / N); // Minimum possible value is half our guess. + T max = ldexp(static_cast<guess_type>(2.), exponent / N); // Maximum possible value is twice our guess. + + int digits = std::numeric_limits<T>::digits * 0.4; // Accuracy triples with each step, so stop when + // slightly more than one third of the digits are correct. + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + T result = halley_iterate(nth_functor_2deriv<N, T>(x), guess, min, max, digits, it); + return result; +} + +//] [/root_finding_nth_function_2deriv] + + +template <int N, typename T = double> +T show_nth_root(T value) +{ // Demonstrate by printing the nth root using all possibly significant digits. + //std::cout.precision(std::numeric_limits<T>::max_digits10); + // or use cout.precision(max_digits10 = 2 + std::numeric_limits<double>::digits * 3010/10000); + // Or guaranteed significant digits: + std::cout.precision(std::numeric_limits<T>::digits10); + + T r = nth_2deriv<N>(value); + std::cout << "Type " << typeid(T).name() << " value = " << value << ", " << N << "th root = " << r << std::endl; + return r; +} // print_nth_root + + +int main() +{ + std::cout << "nth Root finding Example." << std::endl; + using boost::multiprecision::cpp_dec_float_50; // decimal. + using boost::multiprecision::cpp_bin_float_50; // binary. +#ifndef _MSC_VER // Not supported by Microsoft compiler. + using boost::multiprecision::float128; // Requires libquadmath +#endif + try + { // Always use try'n'catch blocks with Boost.Math to get any error messages. + +//[root_finding_n_example_1 + double r1 = nth_2deriv<5, double>(2); // Integral value converted to double. + + // double r2 = nth_2deriv<5>(2); // Only floating-point type types can be used! + +//] [/root_finding_n_example_1 + + //show_nth_root<5, float>(2); // Integral value converted to float. + //show_nth_root<5, float>(2.F); // 'initializing' : conversion from 'double' to 'float', possible loss of data + +//[root_finding_n_example_2 + + + show_nth_root<5, double>(2.); + show_nth_root<5, long double>(2.); +#ifndef _MSC_VER // float128 is not supported by Microsoft compiler 2013. + show_nth_root<5, float128>(2); +#endif + show_nth_root<5, cpp_dec_float_50>(2); // dec + show_nth_root<5, cpp_bin_float_50>(2); // bin +//] [/root_finding_n_example_2 + + // show_nth_root<1000000>(2.); // Type double value = 2, 555th root = 1.00124969405651 + // Type double value = 2, 1000th root = 1.00069338746258 + // Type double value = 2, 1000000th root = 1.00000069314783 + } + catch (const std::exception& e) + { // Always useful to include try & catch blocks because default policies + // are to throw exceptions on arguments that cause errors like underflow, overflow. + // Lacking try & catch blocks, the program will abort without a message below, + // which may give some helpful clues as to the cause of the exception. + std::cout << + "\n""Message from thrown exception was:\n " << e.what() << std::endl; + } + return 0; +} // int main() + + +/* +//[root_finding_example_output_1 + Using MSVC 2013 + +nth Root finding Example. +Type double value = 2, 5th root = 1.14869835499704 +Type long double value = 2, 5th root = 1.14869835499704 +Type class boost::multiprecision::number<class boost::multiprecision::backends::cpp_dec_float<50,int,void>,1> value = 2, + 5th root = 1.1486983549970350067986269467779275894438508890978 +Type class boost::multiprecision::number<class boost::multiprecision::backends::cpp_bin_float<50,10,void,int,0,0>,0> value = 2, + 5th root = 1.1486983549970350067986269467779275894438508890978 + +//] [/root_finding_example_output_1] + +//[root_finding_example_output_2 + + Using GCC 4.91 (includes float_128 type) + + nth Root finding Example. +Type d value = 2, 5th root = 1.14869835499704 +Type e value = 2, 5th root = 1.14869835499703501 +Type N5boost14multiprecision6numberINS0_8backends16float128_backendELNS0_26expression_template_optionE0EEE value = 2, 5th root = 1.148698354997035006798626946777928 +Type N5boost14multiprecision6numberINS0_8backends13cpp_dec_floatILj50EivEELNS0_26expression_template_optionE1EEE value = 2, 5th root = 1.1486983549970350067986269467779275894438508890978 +Type N5boost14multiprecision6numberINS0_8backends13cpp_bin_floatILj50ELNS2_15digit_base_typeE10EviLi0ELi0EEELNS0_26expression_template_optionE0EEE value = 2, 5th root = 1.1486983549970350067986269467779275894438508890978 + +RUN SUCCESSFUL (total time: 63ms) + +//] [/root_finding_example_output_2] +*/ + +/* +Throw out of range using GCC release mode :-( + + */ diff --git a/src/boost/libs/math/example/root_finding_start_locations.cpp b/src/boost/libs/math/example/root_finding_start_locations.cpp new file mode 100644 index 000000000..ba1e437af --- /dev/null +++ b/src/boost/libs/math/example/root_finding_start_locations.cpp @@ -0,0 +1,449 @@ +// Copyright John Maddock 2015 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Comparison of finding roots using TOMS748, Newton-Raphson, Halley & Schroder algorithms. +// Note that this file contains Quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! +// This program also writes files in Quickbook tables mark-up format. + +#include <boost/cstdlib.hpp> +#include <boost/config.hpp> +#include <boost/array.hpp> +#include <boost/math/tools/roots.hpp> +#include <boost/math/special_functions/ellint_1.hpp> +#include <boost/math/special_functions/ellint_2.hpp> +template <class T> +struct cbrt_functor_noderiv +{ + // cube root of x using only function - no derivatives. + cbrt_functor_noderiv(T const& to_find_root_of) : a(to_find_root_of) + { /* Constructor just stores value a to find root of. */ + } + T operator()(T const& x) + { + T fx = x*x*x - a; // Difference (estimate x^3 - a). + return fx; + } +private: + T a; // to be 'cube_rooted'. +}; +//] [/root_finding_noderiv_1 + +template <class T> +boost::uintmax_t cbrt_noderiv(T x, T guess) +{ + // return cube root of x using bracket_and_solve (no derivatives). + using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; // For bracket_and_solve_root. + + T factor = 2; // How big steps to take when searching. + + const boost::uintmax_t maxit = 20; // Limit to maximum iterations. + boost::uintmax_t it = maxit; // Initially our chosen max iterations, but updated with actual. + bool is_rising = true; // So if result if guess^3 is too low, then try increasing guess. + int digits = std::numeric_limits<T>::digits; // Maximum possible binary digits accuracy for type T. + // Some fraction of digits is used to control how accurate to try to make the result. + int get_digits = digits - 3; // We have to have a non-zero interval at each step, so + // maximum accuracy is digits - 1. But we also have to + // allow for inaccuracy in f(x), otherwise the last few + // iterations just thrash around. + eps_tolerance<T> tol(get_digits); // Set the tolerance. + bracket_and_solve_root(cbrt_functor_noderiv<T>(x), guess, factor, is_rising, tol, it); + return it; +} + +template <class T> +struct cbrt_functor_deriv +{ // Functor also returning 1st derivative. + cbrt_functor_deriv(T const& to_find_root_of) : a(to_find_root_of) + { // Constructor stores value a to find root of, + // for example: calling cbrt_functor_deriv<T>(a) to use to get cube root of a. + } + std::pair<T, T> operator()(T const& x) + { + // Return both f(x) and f'(x). + T fx = x*x*x - a; // Difference (estimate x^3 - value). + T dx = 3 * x*x; // 1st derivative = 3x^2. + return std::make_pair(fx, dx); // 'return' both fx and dx. + } +private: + T a; // Store value to be 'cube_rooted'. +}; + +template <class T> +boost::uintmax_t cbrt_deriv(T x, T guess) +{ + // return cube root of x using 1st derivative and Newton_Raphson. + using namespace boost::math::tools; + T min = guess / 100; // We don't really know what this should be! + T max = guess * 100; // We don't really know what this should be! + const int digits = std::numeric_limits<T>::digits; // Maximum possible binary digits accuracy for type T. + int get_digits = static_cast<int>(digits * 0.6); // Accuracy doubles with each step, so stop when we have + // just over half the digits correct. + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + newton_raphson_iterate(cbrt_functor_deriv<T>(x), guess, min, max, get_digits, it); + return it; +} + +template <class T> +struct cbrt_functor_2deriv +{ + // Functor returning both 1st and 2nd derivatives. + cbrt_functor_2deriv(T const& to_find_root_of) : a(to_find_root_of) + { // Constructor stores value a to find root of, for example: + // calling cbrt_functor_2deriv<T>(x) to get cube root of x, + } + std::tuple<T, T, T> operator()(T const& x) + { + // Return both f(x) and f'(x) and f''(x). + T fx = x*x*x - a; // Difference (estimate x^3 - value). + T dx = 3 * x*x; // 1st derivative = 3x^2. + T d2x = 6 * x; // 2nd derivative = 6x. + return std::make_tuple(fx, dx, d2x); // 'return' fx, dx and d2x. + } +private: + T a; // to be 'cube_rooted'. +}; + +template <class T> +boost::uintmax_t cbrt_2deriv(T x, T guess) +{ + // return cube root of x using 1st and 2nd derivatives and Halley. + //using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; + T min = guess / 100; // We don't really know what this should be! + T max = guess * 100; // We don't really know what this should be! + const int digits = std::numeric_limits<T>::digits; // Maximum possible binary digits accuracy for type T. + // digits used to control how accurate to try to make the result. + int get_digits = static_cast<int>(digits * 0.4); // Accuracy triples with each step, so stop when just + // over one third of the digits are correct. + boost::uintmax_t maxit = 20; + halley_iterate(cbrt_functor_2deriv<T>(x), guess, min, max, get_digits, maxit); + return maxit; +} + +template <class T> +boost::uintmax_t cbrt_2deriv_s(T x, T guess) +{ + // return cube root of x using 1st and 2nd derivatives and Halley. + //using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; + T min = guess / 100; // We don't really know what this should be! + T max = guess * 100; // We don't really know what this should be! + const int digits = std::numeric_limits<T>::digits; // Maximum possible binary digits accuracy for type T. + // digits used to control how accurate to try to make the result. + int get_digits = static_cast<int>(digits * 0.4); // Accuracy triples with each step, so stop when just + // over one third of the digits are correct. + boost::uintmax_t maxit = 20; + schroder_iterate(cbrt_functor_2deriv<T>(x), guess, min, max, get_digits, maxit); + return maxit; +} + +template <typename T = double> +struct elliptic_root_functor_noderiv +{ + elliptic_root_functor_noderiv(T const& arc, T const& radius) : m_arc(arc), m_radius(radius) + { // Constructor just stores value a to find root of. + } + T operator()(T const& x) + { + // return the difference between required arc-length, and the calculated arc-length for an + // ellipse with radii m_radius and x: + T a = (std::max)(m_radius, x); + T b = (std::min)(m_radius, x); + T k = sqrt(1 - b * b / (a * a)); + return 4 * a * boost::math::ellint_2(k) - m_arc; + } +private: + T m_arc; // length of arc. + T m_radius; // one of the two radii of the ellipse +}; // template <class T> struct elliptic_root_functor_noderiv + +template <class T = double> +boost::uintmax_t elliptic_root_noderiv(T radius, T arc, T guess) +{ // return the other radius of an ellipse, given one radii and the arc-length + using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; // For bracket_and_solve_root. + + T factor = 2; // How big steps to take when searching. + + const boost::uintmax_t maxit = 50; // Limit to maximum iterations. + boost::uintmax_t it = maxit; // Initially our chosen max iterations, but updated with actual. + bool is_rising = true; // arc-length increases if one radii increases, so function is rising + // Define a termination condition, stop when nearly all digits are correct, but allow for + // the fact that we are returning a range, and must have some inaccuracy in the elliptic integral: + eps_tolerance<T> tol(std::numeric_limits<T>::digits - 2); + // Call bracket_and_solve_root to find the solution, note that this is a rising function: + bracket_and_solve_root(elliptic_root_functor_noderiv<T>(arc, radius), guess, factor, is_rising, tol, it); + return it; +} + +template <class T = double> +struct elliptic_root_functor_1deriv +{ // Functor also returning 1st derivative. + BOOST_STATIC_ASSERT_MSG(boost::is_integral<T>::value == false, "Only floating-point type types can be used!"); + + elliptic_root_functor_1deriv(T const& arc, T const& radius) : m_arc(arc), m_radius(radius) + { // Constructor just stores value a to find root of. + } + std::pair<T, T> operator()(T const& x) + { + // Return the difference between required arc-length, and the calculated arc-length for an + // ellipse with radii m_radius and x, plus it's derivative. + // See http://www.wolframalpha.com/input/?i=d%2Fda+[4+*+a+*+EllipticE%281+-+b^2%2Fa^2%29] + // We require two elliptic integral calls, but from these we can calculate both + // the function and it's derivative: + T a = (std::max)(m_radius, x); + T b = (std::min)(m_radius, x); + T a2 = a * a; + T b2 = b * b; + T k = sqrt(1 - b2 / a2); + T Ek = boost::math::ellint_2(k); + T Kk = boost::math::ellint_1(k); + T fx = 4 * a * Ek - m_arc; + T dfx = 4 * (a2 * Ek - b2 * Kk) / (a2 - b2); + return std::make_pair(fx, dfx); + } +private: + T m_arc; // length of arc. + T m_radius; // one of the two radii of the ellipse +}; // struct elliptic_root__functor_1deriv + +template <class T = double> +boost::uintmax_t elliptic_root_1deriv(T radius, T arc, T guess) +{ + using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; // For newton_raphson_iterate. + + BOOST_STATIC_ASSERT_MSG(boost::is_integral<T>::value == false, "Only floating-point type types can be used!"); + + T min = 0; // Minimum possible value is zero. + T max = arc; // Maximum possible value is the arc length. + + // Accuracy doubles at each step, so stop when just over half of the digits are + // correct, and rely on that step to polish off the remainder: + int get_digits = static_cast<int>(std::numeric_limits<T>::digits * 0.6); + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + newton_raphson_iterate(elliptic_root_functor_1deriv<T>(arc, radius), guess, min, max, get_digits, it); + return it; +} + +template <class T = double> +struct elliptic_root_functor_2deriv +{ // Functor returning both 1st and 2nd derivatives. + BOOST_STATIC_ASSERT_MSG(boost::is_integral<T>::value == false, "Only floating-point type types can be used!"); + + elliptic_root_functor_2deriv(T const& arc, T const& radius) : m_arc(arc), m_radius(radius) {} + std::tuple<T, T, T> operator()(T const& x) + { + // Return the difference between required arc-length, and the calculated arc-length for an + // ellipse with radii m_radius and x, plus it's derivative. + // See http://www.wolframalpha.com/input/?i=d^2%2Fda^2+[4+*+a+*+EllipticE%281+-+b^2%2Fa^2%29] + // for the second derivative. + T a = (std::max)(m_radius, x); + T b = (std::min)(m_radius, x); + T a2 = a * a; + T b2 = b * b; + T k = sqrt(1 - b2 / a2); + T Ek = boost::math::ellint_2(k); + T Kk = boost::math::ellint_1(k); + T fx = 4 * a * Ek - m_arc; + T dfx = 4 * (a2 * Ek - b2 * Kk) / (a2 - b2); + T dfx2 = 4 * b2 * ((a2 + b2) * Kk - 2 * a2 * Ek) / (a * (a2 - b2) * (a2 - b2)); + return std::make_tuple(fx, dfx, dfx2); + } +private: + T m_arc; // length of arc. + T m_radius; // one of the two radii of the ellipse +}; + +template <class T = double> +boost::uintmax_t elliptic_root_2deriv(T radius, T arc, T guess) +{ + using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; // For halley_iterate. + + BOOST_STATIC_ASSERT_MSG(boost::is_integral<T>::value == false, "Only floating-point type types can be used!"); + + T min = 0; // Minimum possible value is zero. + T max = arc; // radius can't be larger than the arc length. + + // Accuracy triples at each step, so stop when just over one-third of the digits + // are correct, and the last iteration will polish off the remaining digits: + int get_digits = static_cast<int>(std::numeric_limits<T>::digits * 0.4); + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + halley_iterate(elliptic_root_functor_2deriv<T>(arc, radius), guess, min, max, get_digits, it); + return it; +} // nth_2deriv Halley +//] +// Using 1st and 2nd derivatives using Schroder algorithm. + +template <class T = double> +boost::uintmax_t elliptic_root_2deriv_s(T radius, T arc, T guess) +{ // return nth root of x using 1st and 2nd derivatives and Schroder. + + using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; // For schroder_iterate. + + BOOST_STATIC_ASSERT_MSG(boost::is_integral<T>::value == false, "Only floating-point type types can be used!"); + + T min = 0; // Minimum possible value is zero. + T max = arc; // radius can't be larger than the arc length. + + int digits = std::numeric_limits<T>::digits; // Maximum possible binary digits accuracy for type T. + int get_digits = static_cast<int>(digits * 0.4); + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + schroder_iterate(elliptic_root_functor_2deriv<T>(arc, radius), guess, min, max, get_digits, it); + return it; +} // T elliptic_root_2deriv_s Schroder + + +int main() +{ + try + { + double to_root = 500; + double answer = 7.93700525984; + + std::cout << "[table\n" + << "[[Initial Guess=][-500% ([approx]1.323)][-100% ([approx]3.97)][-50% ([approx]3.96)][-20% ([approx]6.35)][-10% ([approx]7.14)][-5% ([approx]7.54)]" + "[5% ([approx]8.33)][10% ([approx]8.73)][20% ([approx]9.52)][50% ([approx]11.91)][100% ([approx]15.87)][500 ([approx]47.6)]]\n"; + std::cout << "[[bracket_and_solve_root][" + << cbrt_noderiv(to_root, answer / 6) + << "][" << cbrt_noderiv(to_root, answer / 2) + << "][" << cbrt_noderiv(to_root, answer - answer * 0.5) + << "][" << cbrt_noderiv(to_root, answer - answer * 0.2) + << "][" << cbrt_noderiv(to_root, answer - answer * 0.1) + << "][" << cbrt_noderiv(to_root, answer - answer * 0.05) + << "][" << cbrt_noderiv(to_root, answer + answer * 0.05) + << "][" << cbrt_noderiv(to_root, answer + answer * 0.1) + << "][" << cbrt_noderiv(to_root, answer + answer * 0.2) + << "][" << cbrt_noderiv(to_root, answer + answer * 0.5) + << "][" << cbrt_noderiv(to_root, answer + answer) + << "][" << cbrt_noderiv(to_root, answer + answer * 5) << "]]\n"; + + std::cout << "[[newton_iterate][" + << cbrt_deriv(to_root, answer / 6) + << "][" << cbrt_deriv(to_root, answer / 2) + << "][" << cbrt_deriv(to_root, answer - answer * 0.5) + << "][" << cbrt_deriv(to_root, answer - answer * 0.2) + << "][" << cbrt_deriv(to_root, answer - answer * 0.1) + << "][" << cbrt_deriv(to_root, answer - answer * 0.05) + << "][" << cbrt_deriv(to_root, answer + answer * 0.05) + << "][" << cbrt_deriv(to_root, answer + answer * 0.1) + << "][" << cbrt_deriv(to_root, answer + answer * 0.2) + << "][" << cbrt_deriv(to_root, answer + answer * 0.5) + << "][" << cbrt_deriv(to_root, answer + answer) + << "][" << cbrt_deriv(to_root, answer + answer * 5) << "]]\n"; + + std::cout << "[[halley_iterate][" + << cbrt_2deriv(to_root, answer / 6) + << "][" << cbrt_2deriv(to_root, answer / 2) + << "][" << cbrt_2deriv(to_root, answer - answer * 0.5) + << "][" << cbrt_2deriv(to_root, answer - answer * 0.2) + << "][" << cbrt_2deriv(to_root, answer - answer * 0.1) + << "][" << cbrt_2deriv(to_root, answer - answer * 0.05) + << "][" << cbrt_2deriv(to_root, answer + answer * 0.05) + << "][" << cbrt_2deriv(to_root, answer + answer * 0.1) + << "][" << cbrt_2deriv(to_root, answer + answer * 0.2) + << "][" << cbrt_2deriv(to_root, answer + answer * 0.5) + << "][" << cbrt_2deriv(to_root, answer + answer) + << "][" << cbrt_2deriv(to_root, answer + answer * 5) << "]]\n"; + + std::cout << "[[schr'''ö'''der_iterate][" + << cbrt_2deriv_s(to_root, answer / 6) + << "][" << cbrt_2deriv_s(to_root, answer / 2) + << "][" << cbrt_2deriv_s(to_root, answer - answer * 0.5) + << "][" << cbrt_2deriv_s(to_root, answer - answer * 0.2) + << "][" << cbrt_2deriv_s(to_root, answer - answer * 0.1) + << "][" << cbrt_2deriv_s(to_root, answer - answer * 0.05) + << "][" << cbrt_2deriv_s(to_root, answer + answer * 0.05) + << "][" << cbrt_2deriv_s(to_root, answer + answer * 0.1) + << "][" << cbrt_2deriv_s(to_root, answer + answer * 0.2) + << "][" << cbrt_2deriv_s(to_root, answer + answer * 0.5) + << "][" << cbrt_2deriv_s(to_root, answer + answer) + << "][" << cbrt_2deriv_s(to_root, answer + answer * 5) << "]]\n]\n\n"; + + + double radius_a = 10; + double arc_length = 500; + double radius_b = 123.6216507967705; + + std::cout << std::setprecision(4) << "[table\n" + << "[[Initial Guess=][-500% ([approx]" << radius_b / 6 << ")][-100% ([approx]" << radius_b / 2 << ")][-50% ([approx]" + << radius_b - radius_b * 0.5 << ")][-20% ([approx]" << radius_b - radius_b * 0.2 << ")][-10% ([approx]" << radius_b - radius_b * 0.1 << ")][-5% ([approx]" << radius_b - radius_b * 0.05 << ")]" + "[5% ([approx]" << radius_b + radius_b * 0.05 << ")][10% ([approx]" << radius_b + radius_b * 0.1 << ")][20% ([approx]" << radius_b + radius_b * 0.2 << ")][50% ([approx]" << radius_b + radius_b * 0.5 + << ")][100% ([approx]" << radius_b + radius_b << ")][500 ([approx]" << radius_b + radius_b * 5 << ")]]\n"; + std::cout << "[[bracket_and_solve_root][" + << elliptic_root_noderiv(radius_a, arc_length, radius_b / 6) + << "][" << elliptic_root_noderiv(radius_a, arc_length, radius_b / 2) + << "][" << elliptic_root_noderiv(radius_a, arc_length, radius_b - radius_b * 0.5) + << "][" << elliptic_root_noderiv(radius_a, arc_length, radius_b - radius_b * 0.2) + << "][" << elliptic_root_noderiv(radius_a, arc_length, radius_b - radius_b * 0.1) + << "][" << elliptic_root_noderiv(radius_a, arc_length, radius_b - radius_b * 0.05) + << "][" << elliptic_root_noderiv(radius_a, arc_length, radius_b + radius_b * 0.05) + << "][" << elliptic_root_noderiv(radius_a, arc_length, radius_b + radius_b * 0.1) + << "][" << elliptic_root_noderiv(radius_a, arc_length, radius_b + radius_b * 0.2) + << "][" << elliptic_root_noderiv(radius_a, arc_length, radius_b + radius_b * 0.5) + << "][" << elliptic_root_noderiv(radius_a, arc_length, radius_b + radius_b) + << "][" << elliptic_root_noderiv(radius_a, arc_length, radius_b + radius_b * 5) << "]]\n"; + + std::cout << "[[newton_iterate][" + << elliptic_root_1deriv(radius_a, arc_length, radius_b / 6) + << "][" << elliptic_root_1deriv(radius_a, arc_length, radius_b / 2) + << "][" << elliptic_root_1deriv(radius_a, arc_length, radius_b - radius_b * 0.5) + << "][" << elliptic_root_1deriv(radius_a, arc_length, radius_b - radius_b * 0.2) + << "][" << elliptic_root_1deriv(radius_a, arc_length, radius_b - radius_b * 0.1) + << "][" << elliptic_root_1deriv(radius_a, arc_length, radius_b - radius_b * 0.05) + << "][" << elliptic_root_1deriv(radius_a, arc_length, radius_b + radius_b * 0.05) + << "][" << elliptic_root_1deriv(radius_a, arc_length, radius_b + radius_b * 0.1) + << "][" << elliptic_root_1deriv(radius_a, arc_length, radius_b + radius_b * 0.2) + << "][" << elliptic_root_1deriv(radius_a, arc_length, radius_b + radius_b * 0.5) + << "][" << elliptic_root_1deriv(radius_a, arc_length, radius_b + radius_b) + << "][" << elliptic_root_1deriv(radius_a, arc_length, radius_b + radius_b * 5) << "]]\n"; + + std::cout << "[[halley_iterate][" + << elliptic_root_2deriv(radius_a, arc_length, radius_b / 6) + << "][" << elliptic_root_2deriv(radius_a, arc_length, radius_b / 2) + << "][" << elliptic_root_2deriv(radius_a, arc_length, radius_b - radius_b * 0.5) + << "][" << elliptic_root_2deriv(radius_a, arc_length, radius_b - radius_b * 0.2) + << "][" << elliptic_root_2deriv(radius_a, arc_length, radius_b - radius_b * 0.1) + << "][" << elliptic_root_2deriv(radius_a, arc_length, radius_b - radius_b * 0.05) + << "][" << elliptic_root_2deriv(radius_a, arc_length, radius_b + radius_b * 0.05) + << "][" << elliptic_root_2deriv(radius_a, arc_length, radius_b + radius_b * 0.1) + << "][" << elliptic_root_2deriv(radius_a, arc_length, radius_b + radius_b * 0.2) + << "][" << elliptic_root_2deriv(radius_a, arc_length, radius_b + radius_b * 0.5) + << "][" << elliptic_root_2deriv(radius_a, arc_length, radius_b + radius_b) + << "][" << elliptic_root_2deriv(radius_a, arc_length, radius_b + radius_b * 5) << "]]\n"; + + std::cout << "[[schr'''ö'''der_iterate][" + << elliptic_root_2deriv_s(radius_a, arc_length, radius_b / 6) + << "][" << elliptic_root_2deriv_s(radius_a, arc_length, radius_b / 2) + << "][" << elliptic_root_2deriv_s(radius_a, arc_length, radius_b - radius_b * 0.5) + << "][" << elliptic_root_2deriv_s(radius_a, arc_length, radius_b - radius_b * 0.2) + << "][" << elliptic_root_2deriv_s(radius_a, arc_length, radius_b - radius_b * 0.1) + << "][" << elliptic_root_2deriv_s(radius_a, arc_length, radius_b - radius_b * 0.05) + << "][" << elliptic_root_2deriv_s(radius_a, arc_length, radius_b + radius_b * 0.05) + << "][" << elliptic_root_2deriv_s(radius_a, arc_length, radius_b + radius_b * 0.1) + << "][" << elliptic_root_2deriv_s(radius_a, arc_length, radius_b + radius_b * 0.2) + << "][" << elliptic_root_2deriv_s(radius_a, arc_length, radius_b + radius_b * 0.5) + << "][" << elliptic_root_2deriv_s(radius_a, arc_length, radius_b + radius_b) + << "][" << elliptic_root_2deriv_s(radius_a, arc_length, radius_b + radius_b * 5) << "]]\n]\n\n"; + + return boost::exit_success; + } + catch(std::exception ex) + { + std::cout << "exception thrown: " << ex.what() << std::endl; + return boost::exit_failure; + } +} // int main() + diff --git a/src/boost/libs/math/example/root_n_finding_algorithms.cpp b/src/boost/libs/math/example/root_n_finding_algorithms.cpp new file mode 100644 index 000000000..70f017923 --- /dev/null +++ b/src/boost/libs/math/example/root_n_finding_algorithms.cpp @@ -0,0 +1,870 @@ +// Copyright Paul A. Bristow 2015 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Comparison of finding roots using TOMS748, Newton-Raphson, Halley & Schroder algorithms. +// root_n_finding_algorithms.cpp Generalised for nth root version. + +// http://en.wikipedia.org/wiki/Cube_root + +// Note that this file contains Quickbook mark-up as well as code +// and comments, don't change any of the special comment mark-ups! +// This program also writes files in Quickbook tables mark-up format. + +#include <boost/cstdlib.hpp> +#include <boost/config.hpp> +#include <boost/array.hpp> +#include <boost/type_traits/is_floating_point.hpp> +#include <boost/math/concepts/real_concept.hpp> +#include <boost/math/tools/roots.hpp> + +//using boost::math::policies::policy; +//using boost::math::tools::eps_tolerance; // Binary functor for specified number of bits. +//using boost::math::tools::bracket_and_solve_root; +//using boost::math::tools::toms748_solve; +//using boost::math::tools::halley_iterate; +//using boost::math::tools::newton_raphson_iterate; +//using boost::math::tools::schroder_iterate; + +#include <boost/math/special_functions/next.hpp> // For float_distance. +#include <boost/math/special_functions/pow.hpp> // For pow<N>. +#include <boost/math/tools/tuple.hpp> // for tuple and make_tuple. + +#include <boost/multiprecision/cpp_bin_float.hpp> // is binary. +using boost::multiprecision::cpp_bin_float_100; +using boost::multiprecision::cpp_bin_float_50; + +#include <boost/timer/timer.hpp> +#include <boost/system/error_code.hpp> +#include <boost/preprocessor/stringize.hpp> + +// STL +#include <iostream> +#include <iomanip> +#include <string> +#include <vector> +#include <limits> +#include <fstream> // std::ofstream +#include <cmath> +#include <typeinfo> // for type name using typid(thingy).name(); + +#ifdef __FILE__ + std::string sourcefilename = __FILE__; +#else + std::string sourcefilename(""); +#endif + + std::string chop_last(std::string s) + { + std::string::size_type pos = s.find_last_of("\\/"); + if(pos != std::string::npos) + s.erase(pos); + else if(s.empty()) + abort(); + else + s.erase(); + return s; + } + + std::string make_root() + { + std::string result; + if(sourcefilename.find_first_of(":") != std::string::npos) + { + result = chop_last(sourcefilename); // lose filename part + result = chop_last(result); // lose /example/ + result = chop_last(result); // lose /math/ + result = chop_last(result); // lose /libs/ + } + else + { + result = chop_last(sourcefilename); // lose filename part + if(result.empty()) + result = "."; + result += "/../../.."; + } + return result; + } + + std::string short_file_name(std::string s) + { + std::string::size_type pos = s.find_last_of("\\/"); + if(pos != std::string::npos) + s.erase(0, pos + 1); + return s; + } + + std::string boost_root = make_root(); + + +std::string fp_hardware; // Any hardware features like SEE or AVX + +const std::string roots_name = "libs/math/doc/roots/"; + +const std::string full_roots_name(boost_root + "/libs/math/doc/roots/"); + +const std::size_t nooftypes = 4; +const std::size_t noofalgos = 4; + +double digits_accuracy = 1.0; // 1 == maximum possible accuracy. + +std::stringstream ss; + +std::ofstream fout; + +std::vector<std::string> algo_names = +{ + "TOMS748", "Newton", "Halley", "Schr'''ö'''der" +}; + +std::vector<std::string> names = +{ + "float", "double", "long double", "cpp_bin_float50" +}; + +uintmax_t iters; // Global as value of iterations is not returned. + +struct root_info +{ // for a floating-point type, float, double ... + std::size_t max_digits10; // for type. + std::string full_typename; // for type from type_id.name(). + std::string short_typename; // for type "float", "double", "cpp_bin_float_50" .... + std::size_t bin_digits; // binary in floating-point type numeric_limits<T>::digits; + int get_digits; // fraction of maximum possible accuracy required. + // = digits * digits_accuracy + // Vector of values (4) for each algorithm, TOMS748, Newton, Halley & Schroder. + //std::vector< boost::int_least64_t> times; converted to int. + std::vector<int> times; // arbitrary units (ticks). + //boost::int_least64_t min_time = std::numeric_limits<boost::int_least64_t>::max(); // Used to normalize times (as int). + std::vector<double> normed_times; + int min_time = (std::numeric_limits<int>::max)(); // Used to normalize times. + std::vector<uintmax_t> iterations; + std::vector<long int> distances; + std::vector<cpp_bin_float_100> full_results; +}; // struct root_info + +std::vector<root_info> root_infos; // One element for each floating-point type used. + +inline std::string build_test_name(const char* type_name, const char* test_name) +{ + std::string result(BOOST_COMPILER); + result += "|"; + result += BOOST_STDLIB; + result += "|"; + result += BOOST_PLATFORM; + result += "|"; + result += type_name; + result += "|"; + result += test_name; +#if defined(_DEBUG) || !defined(NDEBUG) + result += "|"; + result += " debug"; +#else + result += "|"; + result += " release"; +#endif + result += "|"; + return result; +} // std::string build_test_name + +// Algorithms ////////////////////////////////////////////// + +// No derivatives - using TOMS748 internally. + +template <int N, typename T = double> +struct nth_root_functor_noderiv +{ // Nth root of x using only function - no derivatives. + nth_root_functor_noderiv(T const& to_find_root_of) : a(to_find_root_of) + { // Constructor just stores value a to find root of. + } + T operator()(T const& x) + { + using boost::math::pow; + T fx = pow<N>(x) -a; // Difference (estimate x^n - a). + return fx; + } +private: + T a; // to be 'cube_rooted'. +}; // template <int N, class T> struct nth_root_functor_noderiv + +template <int N, class T = double> +T nth_root_noderiv(T x) +{ // return Nth root of x using bracket_and_solve (using NO derivatives). + using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; // For bracket_and_solve_root. + + typedef double guess_type; + + int exponent; + frexp(static_cast<guess_type>(x), &exponent); // Get exponent of z (ignore mantissa). + T guess = static_cast<T>(ldexp(static_cast<guess_type>(1.), exponent / N)); // Rough guess is to divide the exponent by n. + //T min = static_cast<T>(ldexp(static_cast<guess_type>(1.) / 2, exponent / N)); // Minimum possible value is half our guess. + //T max = static_cast<T>(ldexp(static_cast<guess_type>(2.), exponent / N)); // Maximum possible value is twice our guess. + + T factor = 2; // How big steps to take when searching. + + const boost::uintmax_t maxit = 50; // Limit to maximum iterations. + boost::uintmax_t it = maxit; // Initially our chosen max iterations, but updated with actual. + bool is_rising = true; // So if result if guess^3 is too low, then try increasing guess. + // Some fraction of digits is used to control how accurate to try to make the result. + int get_digits = std::numeric_limits<T>::digits - 2; + eps_tolerance<T> tol(get_digits); // Set the tolerance. + std::pair<T, T> r; + r = bracket_and_solve_root(nth_root_functor_noderiv<N, T>(x), guess, factor, is_rising, tol, it); + iters = it; + T result = r.first + (r.second - r.first) / 2; // Midway between brackets. + return result; +} // template <class T> T nth_root_noderiv(T x) + +// Using 1st derivative only Newton-Raphson + +template <int N, class T = double> +struct nth_root_functor_1deriv +{ // Functor also returning 1st derivative. + BOOST_STATIC_ASSERT_MSG(boost::is_integral<T>::value == false, "Only floating-point type types can be used!"); + BOOST_STATIC_ASSERT_MSG((N > 0) == true, "root N must be > 0!"); + + nth_root_functor_1deriv(T const& to_find_root_of) : a(to_find_root_of) + { // Constructor stores value a to find root of, for example: + } + std::pair<T, T> operator()(T const& x) + { // Return both f(x) and f'(x). + using boost::math::pow; // // Compile-time integral power. + T p = pow<N - 1>(x); + return std::make_pair(p * x - a, N * p); // 'return' both fx and dx. + } + +private: + T a; // to be 'nth_rooted'. +}; // struct nthroot__functor_1deriv + +template <int N, class T = double> +T nth_root_1deriv(T x) +{ // return nth root of x using 1st derivative and Newton_Raphson. + using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; // For newton_raphson_iterate. + + BOOST_STATIC_ASSERT_MSG(boost::is_integral<T>::value == false, "Only floating-point type types can be used!"); + BOOST_STATIC_ASSERT_MSG((N > 0) == true, "root N must be > 0!"); + BOOST_STATIC_ASSERT_MSG((N > 1000) == false, "root N is too big!"); + + typedef double guess_type; + + int exponent; + frexp(static_cast<guess_type>(x), &exponent); // Get exponent of z (ignore mantissa). + T guess = static_cast<T>(ldexp(static_cast<guess_type>(1.), exponent / N)); // Rough guess is to divide the exponent by n. + T min = static_cast<T>(ldexp(static_cast<guess_type>(1.) / 2, exponent / N)); // Minimum possible value is half our guess. + T max = static_cast<T>(ldexp(static_cast<guess_type>(2.), exponent / N)); // Maximum possible value is twice our guess. + + int digits = std::numeric_limits<T>::digits; // Maximum possible binary digits accuracy for type T. + int get_digits = static_cast<int>(digits * 0.6); + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + T result = newton_raphson_iterate(nth_root_functor_1deriv<N, T>(x), guess, min, max, get_digits, it); + iters = it; + return result; +} // T nth_root_1_deriv Newton-Raphson + +// Using 1st and 2nd derivatives with Halley algorithm. + +template <int N, class T = double> +struct nth_root_functor_2deriv +{ // Functor returning both 1st and 2nd derivatives. + BOOST_STATIC_ASSERT_MSG(boost::is_integral<T>::value == false, "Only floating-point type types can be used!"); + BOOST_STATIC_ASSERT_MSG((N > 0) == true, "root N must be > 0!"); + + nth_root_functor_2deriv(T const& to_find_root_of) : a(to_find_root_of) + { // Constructor stores value a to find root of, for example: + } + + // using boost::math::tuple; // to return three values. + std::tuple<T, T, T> operator()(T const& x) + { // Return f(x), f'(x) and f''(x). + using boost::math::pow; // Compile-time integral power. + T p = pow<N - 2>(x); + + return std::make_tuple(p * x * x - a, p * x * N, p * N * (N - 1)); // 'return' fx, dx and d2x. + } +private: + T a; // to be 'nth_rooted'. +}; + +template <int N, class T = double> +T nth_root_2deriv(T x) +{ // return nth root of x using 1st and 2nd derivatives and Halley. + + using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; // For halley_iterate. + + BOOST_STATIC_ASSERT_MSG(boost::is_integral<T>::value == false, "Only floating-point type types can be used!"); + BOOST_STATIC_ASSERT_MSG((N > 0) == true, "root N must be > 0!"); + BOOST_STATIC_ASSERT_MSG((N > 1000) == false, "root N is too big!"); + + typedef double guess_type; + + int exponent; + frexp(static_cast<guess_type>(x), &exponent); // Get exponent of z (ignore mantissa). + T guess = static_cast<T>(ldexp(static_cast<guess_type>(1.), exponent / N)); // Rough guess is to divide the exponent by n. + T min = static_cast<T>(ldexp(static_cast<guess_type>(1.) / 2, exponent / N)); // Minimum possible value is half our guess. + T max = static_cast<T>(ldexp(static_cast<guess_type>(2.), exponent / N)); // Maximum possible value is twice our guess. + + int digits = std::numeric_limits<T>::digits; // Maximum possible binary digits accuracy for type T. + int get_digits = static_cast<int>(digits * 0.4); + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + T result = halley_iterate(nth_root_functor_2deriv<N, T>(x), guess, min, max, get_digits, it); + iters = it; + + return result; +} // nth_2deriv Halley + +template <int N, class T = double> +T nth_root_2deriv_s(T x) +{ // return nth root of x using 1st and 2nd derivatives and Schroder. + + using namespace std; // Help ADL of std functions. + using namespace boost::math::tools; // For schroder_iterate. + + BOOST_STATIC_ASSERT_MSG(boost::is_integral<T>::value == false, "Only floating-point type types can be used!"); + BOOST_STATIC_ASSERT_MSG((N > 0) == true, "root N must be > 0!"); + BOOST_STATIC_ASSERT_MSG((N > 1000) == false, "root N is too big!"); + + typedef double guess_type; + + int exponent; + frexp(static_cast<guess_type>(x), &exponent); // Get exponent of z (ignore mantissa). + T guess = static_cast<T>(ldexp(static_cast<guess_type>(1.), exponent / N)); // Rough guess is to divide the exponent by n. + T min = static_cast<T>(ldexp(static_cast<guess_type>(1.) / 2, exponent / N)); // Minimum possible value is half our guess. + T max = static_cast<T>(ldexp(static_cast<guess_type>(2.), exponent / N)); // Maximum possible value is twice our guess. + + int get_digits = static_cast<int>(std::numeric_limits<T>::digits * 0.4); + const boost::uintmax_t maxit = 20; + boost::uintmax_t it = maxit; + T result = schroder_iterate(nth_root_functor_2deriv<N, T>(x), guess, min, max, get_digits, it); + iters = it; + + return result; +} // T nth_root_2deriv_s Schroder + +//////////////////////////////////////////////////////// end of algorithms - perhaps in a separate .hpp? + +//! Print 4 floating-point types info: max_digits10, digits and required accuracy digits as a Quickbook table. +int table_type_info(double digits_accuracy) +{ + std::string qbk_name = full_roots_name; // Prefix by boost_root file. + + qbk_name += "type_info_table"; + std::stringstream ss; + ss.precision(3); + ss << "_" << digits_accuracy * 100; + qbk_name += ss.str(); + +#ifdef _MSC_VER + qbk_name += "_msvc.qbk"; +#else // assume GCC + qbk_name += "_gcc.qbk"; +#endif + + // Example: type_info_table_100_msvc.qbk + fout.open(qbk_name, std::ios_base::out); + + if (fout.is_open()) + { + std::cout << "Output type table to " << qbk_name << std::endl; + } + else + { // Failed to open. + std::cout << " Open file " << qbk_name << " for output failed!" << std::endl; + std::cout << "errno " << errno << std::endl; + return errno; + } + + fout << + "[/" + << qbk_name + << "\n" + "Copyright 2015 Paul A. Bristow.""\n" + "Copyright 2015 John Maddock.""\n" + "Distributed under the Boost Software License, Version 1.0.""\n" + "(See accompanying file LICENSE_1_0.txt or copy at""\n" + "http://www.boost.org/LICENSE_1_0.txt).""\n" + "]""\n" + << std::endl; + + fout << "[h6 Fraction of maximum possible bits of accuracy required is " << digits_accuracy << ".]\n" << std::endl; + + std::string table_id("type_info"); + table_id += ss.str(); // Fraction digits accuracy. + +#ifdef _MSC_VER + table_id += "_msvc"; +#else // assume GCC + table_id += "_gcc"; +#endif + + fout << "[table:" << table_id << " Digits for float, double, long double and cpp_bin_float_50\n" + << "[[type name] [max_digits10] [binary digits] [required digits]]\n";// header. + + // For all fout types: + + fout << "[[" << "float" << "]" + << "[" << std::numeric_limits<float>::max_digits10 << "]" // max_digits10 + << "[" << std::numeric_limits<float>::digits << "]"// < "Binary digits + << "[" << static_cast<int>(std::numeric_limits<float>::digits * digits_accuracy) << "]]\n"; // Accuracy digits. + + fout << "[[" << "float" << "]" + << "[" << std::numeric_limits<double>::max_digits10 << "]" // max_digits10 + << "[" << std::numeric_limits<double>::digits << "]"// < "Binary digits + << "[" << static_cast<int>(std::numeric_limits<double>::digits * digits_accuracy) << "]]\n"; // Accuracy digits. + + fout << "[[" << "long double" << "]" + << "[" << std::numeric_limits<long double>::max_digits10 << "]" // max_digits10 + << "[" << std::numeric_limits<long double>::digits << "]"// < "Binary digits + << "[" << static_cast<int>(std::numeric_limits<long double>::digits * digits_accuracy) << "]]\n"; // Accuracy digits. + + fout << "[[" << "cpp_bin_float_50" << "]" + << "[" << std::numeric_limits<cpp_bin_float_50>::max_digits10 << "]" // max_digits10 + << "[" << std::numeric_limits<cpp_bin_float_50>::digits << "]"// < "Binary digits + << "[" << static_cast<int>(std::numeric_limits<cpp_bin_float_50>::digits * digits_accuracy) << "]]\n"; // Accuracy digits. + + fout << "] [/table table_id_msvc] \n" << std::endl; // End of table. + + fout.close(); + return 0; +} // type_table + +//! Evaluate root N timing for each algorithm, and for one floating-point type T. +template <int N, typename T> +int test_root(cpp_bin_float_100 big_value, cpp_bin_float_100 answer, const char* type_name, std::size_t type_no) +{ + std::size_t max_digits = 2 + std::numeric_limits<T>::digits * 3010 / 10000; + // For new versions use max_digits10 + // std::cout.precision(std::numeric_limits<T>::max_digits10); + std::cout.precision(max_digits); + std::cout << std::showpoint << std::endl; // Show trailing zeros too. + + root_infos.push_back(root_info()); + + root_infos[type_no].max_digits10 = max_digits; + root_infos[type_no].full_typename = typeid(T).name(); // Full typename. + root_infos[type_no].short_typename = type_name; // Short typename. + root_infos[type_no].bin_digits = std::numeric_limits<T>::digits; + root_infos[type_no].get_digits = static_cast<int>(std::numeric_limits<T>::digits * digits_accuracy); + + T to_root = static_cast<T>(big_value); + + T result; // root + T sum = 0; + T ans = static_cast<T>(answer); + + using boost::timer::nanosecond_type; + using boost::timer::cpu_times; + using boost::timer::cpu_timer; + + int eval_count = boost::is_floating_point<T>::value ? 10000000 : 100000; // To give a sufficiently stable timing for the fast built-in types, + //int eval_count = 1000000; // To give a sufficiently stable timing for the fast built-in types, + // This takes an inconveniently long time for multiprecision cpp_bin_float_50 etc types. + + cpu_times now; // Holds wall, user and system times. + + { // Evaluate times etc for each algorithm. + //algorithm_names.push_back("TOMS748"); // + cpu_timer ti; // Can start, pause, resume and stop, and read elapsed. + ti.start(); + for (long i = 0; i < eval_count; ++i) + { + result = nth_root_noderiv<N, T>(to_root); // + sum += result; + } + now = ti.elapsed(); + int time = static_cast<int>(now.user / eval_count); + root_infos[type_no].times.push_back(time); // CPU time taken. + if (time < root_infos[type_no].min_time) + { + root_infos[type_no].min_time = time; + } + ti.stop(); + long int distance = static_cast<int>(boost::math::float_distance<T>(result, ans)); + root_infos[type_no].distances.push_back(distance); + root_infos[type_no].iterations.push_back(iters); // + root_infos[type_no].full_results.push_back(result); + } + { + // algorithm_names.push_back("Newton"); // algorithm + cpu_timer ti; // Can start, pause, resume and stop, and read elapsed. + ti.start(); + for (long i = 0; i < eval_count; ++i) + { + result = nth_root_1deriv<N, T>(to_root); // + sum += result; + } + now = ti.elapsed(); + int time = static_cast<int>(now.user / eval_count); + root_infos[type_no].times.push_back(time); // CPU time taken. + if (time < root_infos[type_no].min_time) + { + root_infos[type_no].min_time = time; + } + + ti.stop(); + long int distance = static_cast<int>(boost::math::float_distance<T>(result, ans)); + root_infos[type_no].distances.push_back(distance); + root_infos[type_no].iterations.push_back(iters); // + root_infos[type_no].full_results.push_back(result); + } + { + //algorithm_names.push_back("Halley"); // algorithm + cpu_timer ti; // Can start, pause, resume and stop, and read elapsed. + ti.start(); + for (long i = 0; i < eval_count; ++i) + { + result = nth_root_2deriv<N>(to_root); // + sum += result; + } + now = ti.elapsed(); + int time = static_cast<int>(now.user / eval_count); + root_infos[type_no].times.push_back(time); // CPU time taken. + ti.stop(); + if (time < root_infos[type_no].min_time) + { + root_infos[type_no].min_time = time; + } + long int distance = static_cast<int>(boost::math::float_distance<T>(result, ans)); + root_infos[type_no].distances.push_back(distance); + root_infos[type_no].iterations.push_back(iters); // + root_infos[type_no].full_results.push_back(result); + } + { + // algorithm_names.push_back("Schroder"); // algorithm + cpu_timer ti; // Can start, pause, resume and stop, and read elapsed. + ti.start(); + for (long i = 0; i < eval_count; ++i) + { + result = nth_root_2deriv_s<N>(to_root); // + sum += result; + } + now = ti.elapsed(); + int time = static_cast<int>(now.user / eval_count); + root_infos[type_no].times.push_back(time); // CPU time taken. + if (time < root_infos[type_no].min_time) + { + root_infos[type_no].min_time = time; + } + ti.stop(); + long int distance = static_cast<int>(boost::math::float_distance<T>(result, ans)); + root_infos[type_no].distances.push_back(distance); + root_infos[type_no].iterations.push_back(iters); // + root_infos[type_no].full_results.push_back(result); + } + for (size_t i = 0; i != root_infos[type_no].times.size(); i++) // For each time. + { // Normalize times. + root_infos[type_no].normed_times.push_back(static_cast<double>(root_infos[type_no].times[i]) / root_infos[type_no].min_time); + } + + std::cout << "Accumulated result was: " << sum << std::endl; + + return 4; // eval_count of how many algorithms used. +} // test_root + +/*! Fill array of times, iterations, etc for Nth root for all 4 types, + and write a table of results in Quickbook format. + */ +template <int N> +void table_root_info(cpp_bin_float_100 full_value) +{ + using std::abs; + std::cout << nooftypes << " floating-point types tested:" << std::endl; +#if defined(_DEBUG) || !defined(NDEBUG) + std::cout << "Compiled in debug mode." << std::endl; +#else + std::cout << "Compiled in optimise mode." << std::endl; +#endif + std::cout << "FP hardware " << fp_hardware << std::endl; + // Compute the 'right' answer for root N at 100 decimal digits. + cpp_bin_float_100 full_answer = nth_root_noderiv<N, cpp_bin_float_100>(full_value); + + root_infos.clear(); // Erase any previous data. + // Fill the elements of the array for each floating-point type. + + test_root<N, float>(full_value, full_answer, "float", 0); + test_root<N, double>(full_value, full_answer, "double", 1); + test_root<N, long double>(full_value, full_answer, "long double", 2); + test_root<N, cpp_bin_float_50>(full_value, full_answer, "cpp_bin_float_50", 3); + + // Use info from 4 floating point types to + + // Prepare Quickbook table for a single root + // with columns of times, iterations, distances repeated for various floating-point types, + // and 4 rows for each algorithm. + + std::stringstream table_info; + table_info.precision(3); + table_info << "[table:root_" << N << " " << N << "th root(" << static_cast<float>(full_value) << ") for float, double, long double and cpp_bin_float_50 types"; + if (fp_hardware != "") + { + table_info << ", using " << fp_hardware; + } + table_info << std::endl; + + fout << table_info.str() + << "[[][float][][][] [][double][][][] [][long d][][][] [][cpp50][][]]\n" + << "[[Algo ]"; + for (size_t tp = 0; tp != nooftypes; tp++) + { // For all types: + fout << "[Its]" << "[Times]" << "[Norm]" << "[Dis]" << "[ ]"; + } + fout << "]" << std::endl; + + // Row for all algorithms. + for (std::size_t algo = 0; algo != noofalgos; algo++) + { + fout << "[[" << std::left << std::setw(9) << algo_names[algo] << "]"; + for (size_t tp = 0; tp != nooftypes; tp++) + { // For all types: + fout + << "[" << std::right << std::showpoint + << std::setw(3) << std::setprecision(2) << root_infos[tp].iterations[algo] << "][" + << std::setw(5) << std::setprecision(5) << root_infos[tp].times[algo] << "]["; + fout << std::setw(3) << std::setprecision(3); + double normed_time = root_infos[tp].normed_times[algo]; + if (abs(normed_time - 1.00) <= 0.05) + { // At or near the best time, so show as blue. + fout << "[role blue " << normed_time << "]"; + } + else if (abs(normed_time) > 4.) + { // markedly poor so show as red. + fout << "[role red " << normed_time << "]"; + } + else + { // Not the best, so normal black. + fout << normed_time; + } + fout << "][" + << std::setw(3) << std::setprecision(2) << root_infos[tp].distances[algo] << "][ ]"; + } // tp + fout << "]" << std::endl; + } // for algo + fout << "] [/end of table root]\n"; +} // void table_root_info + +/*! Output program header, table of type info, and tables for 4 algorithms and 4 floating-point types, + for Nth root required digits_accuracy. + */ + +int roots_tables(cpp_bin_float_100 full_value, double digits_accuracy) +{ + ::digits_accuracy = digits_accuracy; + // Save globally so that it is available to root-finding algorithms. Ugly :-( + +#if defined(_DEBUG) || !defined(NDEBUG) + std::string debug_or_optimize("Compiled in debug mode."); +#else + std::string debug_or_optimize("Compiled in optimise mode."); +#endif + + // Create filename for roots_table + std::string qbk_name = full_roots_name; + qbk_name += "roots_table"; + + std::stringstream ss; + ss.precision(3); + // ss << "_" << N // now put all the tables in one .qbk file? + ss << "_" << digits_accuracy * 100 + << std::flush; + // Assume only save optimize mode runs, so don't add any _DEBUG info. + qbk_name += ss.str(); + +#ifdef _MSC_VER + qbk_name += "_msvc"; +#else // assume GCC + qbk_name += "_gcc"; +#endif + if (fp_hardware != "") + { + qbk_name += fp_hardware; + } + qbk_name += ".qbk"; + + fout.open(qbk_name, std::ios_base::out); + + if (fout.is_open()) + { + std::cout << "Output root table to " << qbk_name << std::endl; + } + else + { // Failed to open. + std::cout << " Open file " << qbk_name << " for output failed!" << std::endl; + std::cout << "errno " << errno << std::endl; + return errno; + } + + fout << + "[/" + << qbk_name + << "\n" + "Copyright 2015 Paul A. Bristow.""\n" + "Copyright 2015 John Maddock.""\n" + "Distributed under the Boost Software License, Version 1.0.""\n" + "(See accompanying file LICENSE_1_0.txt or copy at""\n" + "http://www.boost.org/LICENSE_1_0.txt).""\n" + "]""\n" + << std::endl; + + // Print out the program/compiler/stdlib/platform names as a Quickbook comment: + fout << "\n[h6 Program " << sourcefilename << ",\n " + << BOOST_COMPILER << ", " + << BOOST_STDLIB << ", " + << BOOST_PLATFORM << "\n" + << debug_or_optimize + << ((fp_hardware != "") ? ", " + fp_hardware : "") + << "]" // [h6 close]. + << std::endl; + + fout << "Fraction of full accuracy " << digits_accuracy << std::endl; + + table_root_info<5>(full_value); + table_root_info<7>(full_value); + table_root_info<11>(full_value); + + fout.close(); + + // table_type_info(digits_accuracy); + + return 0; +} // roots_tables + + +int main() +{ + using namespace boost::multiprecision; + using namespace boost::math; + + + try + { + std::cout << "Tests run with " << BOOST_COMPILER << ", " + << BOOST_STDLIB << ", " << BOOST_PLATFORM << ", "; + +// How to: Configure Visual C++ Projects to Target 64-Bit Platforms +// https://msdn.microsoft.com/en-us/library/9yb4317s.aspx + +#ifdef _M_X64 // Defined for compilations that target x64 processors. + std::cout << "X64 " << std::endl; + fp_hardware += "_X64"; +#else +# ifdef _M_IX86 + std::cout << "X32 " << std::endl; + fp_hardware += "_X86"; +# endif +#endif + +#ifdef _M_AMD64 + std::cout << "AMD64 " << std::endl; + // fp_hardware += "_AMD64"; +#endif + +// https://msdn.microsoft.com/en-us/library/7t5yh4fd.aspx +// /arch (x86) options /arch:[IA32|SSE|SSE2|AVX|AVX2] +// default is to use SSE and SSE2 instructions by default. +// https://msdn.microsoft.com/en-us/library/jj620901.aspx +// /arch (x64) options /arch:AVX and /arch:AVX2 + +// MSVC doesn't bother to set these SSE macros! +// http://stackoverflow.com/questions/18563978/sse-sse2-is-enabled-control-in-visual-studio +// https://msdn.microsoft.com/en-us/library/b0084kay.aspx predefined macros. + +// But some of these macros are *not* defined by MSVC, +// unlike AVX (but *are* defined by GCC and Clang). +// So the macro code above does define them. +#if (defined(_M_AMD64) || defined (_M_X64)) +#ifndef _M_X64 +# define _M_X64 +#endif +#ifndef __SSE2__ +# define __SSE2__ +#endif +#else +# ifdef _M_IX86_FP // Expands to an integer literal value indicating which /arch compiler option was used: + std::cout << "Floating-point _M_IX86_FP = " << _M_IX86_FP << std::endl; +# if (_M_IX86_FP == 2) // 2 if /arch:SSE2, /arch:AVX or /arch:AVX2 +# define __SSE2__ // x32 +# elif (_M_IX86_FP == 1) // 1 if /arch:SSE was used. +# define __SSE__ // x32 +# elif (_M_IX86_FP == 0) // 0 if /arch:IA32 was used. +# define _X32 // No special FP instructions. +# endif +# endif +#endif +// Set the fp_hardware that is used in the .qbk filename. +#ifdef __AVX2__ + std::cout << "Floating-point AVX2 " << std::endl; + fp_hardware += "_AVX2"; +# else +# ifdef __AVX__ + std::cout << "Floating-point AVX " << std::endl; + fp_hardware += "_AVX"; +# else +# ifdef __SSE2__ + std::cout << "Floating-point SSE2 " << std::endl; + fp_hardware += "_SSE2"; +# else +# ifdef __SSE__ + std::cout << "Floating-point SSE " << std::endl; + fp_hardware += "_SSE"; +# endif +# endif +# endif +# endif + +#ifdef _M_IX86 + std::cout << "Floating-point X86 _M_IX86 = " << _M_IX86 << std::endl; + // https://msdn.microsoft.com/en-us/library/aa273918%28v=vs.60%29.aspx#_predir_table_1..3 + // 600 = Pentium Pro +#endif + +#ifdef _MSC_FULL_VER + std::cout << "Floating-point _MSC_FULL_VER " << _MSC_FULL_VER << std::endl; +#endif + +#ifdef __MSVC_RUNTIME_CHECKS + std::cout << "Runtime __MSVC_RUNTIME_CHECKS " << std::endl; +#endif + + BOOST_MATH_CONTROL_FP; + + cpp_bin_float_100 full_value("28."); + // Compute full answer to more than precision of tests. + //T value = 28.; // integer (exactly representable as floating-point) + // whose cube root is *not* exactly representable. + // Wolfram Alpha command N[28 ^ (1 / 3), 100] computes cube root to 100 decimal digits. + // 3.036588971875662519420809578505669635581453977248111123242141654169177268411884961770250390838097895 + + std::cout.precision(100); + std::cout << "value " << full_value << std::endl; + // std::cout << ",\n""answer = " << full_answer << std::endl; + std::cout.precision(6); + // cbrt cpp_bin_float_100 full_answer("3.036588971875662519420809578505669635581453977248111123242141654169177268411884961770250390838097895"); + + // Output the table of types, maxdigits10 and digits and required digits for some accuracies. + + // Output tables for some roots at full accuracy. + roots_tables(full_value, 1.); + + // Output tables for some roots at less accuracy. + //roots_tables(full_value, 0.75); + + return boost::exit_success; + } + catch (std::exception const& ex) + { + std::cout << "exception thrown: " << ex.what() << std::endl; + return boost::exit_failure; + } +} // int main() + +/* + +*/ diff --git a/src/boost/libs/math/example/series.cpp b/src/boost/libs/math/example/series.cpp new file mode 100644 index 000000000..8bfce824f --- /dev/null +++ b/src/boost/libs/math/example/series.cpp @@ -0,0 +1,107 @@ +// (C) Copyright John Maddock 2018. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/math/tools/series.hpp> +#include <boost/assert.hpp> + +#include <iostream> +#include <complex> +#include <cassert> + +//[series_log1p +template <class T> +struct log1p_series +{ + // we must define a result_type typedef: + typedef T result_type; + + log1p_series(T x) + : k(0), m_mult(-x), m_prod(-1) {} + + T operator()() + { + // This is the function operator invoked by the summation + // algorithm, the first call to this operator should return + // the first term of the series, the second call the second + // term and so on. + m_prod *= m_mult; + return m_prod / ++k; + } + +private: + int k; + const T m_mult; + T m_prod; +}; +//] + +//[series_log1p_func +template <class T> +T log1p(T x) +{ + // We really should add some error checking on x here! + BOOST_ASSERT(std::fabs(x) < 1); + + // Construct the series functor: + log1p_series<T> s(x); + // Set a limit on how many iterations we permit: + boost::uintmax_t max_iter = 1000; + // Add it up, with enough precision for full machine precision: + return boost::math::tools::sum_series(s, std::numeric_limits<T>::epsilon(), max_iter); +} +//] + +//[series_clog1p_func +template <class T> +struct log1p_series<std::complex<T> > +{ + // we must define a result_type typedef: + typedef std::complex<T> result_type; + + log1p_series(std::complex<T> x) + : k(0), m_mult(-x), m_prod(-1) {} + + std::complex<T> operator()() + { + // This is the function operator invoked by the summation + // algorithm, the first call to this operator should return + // the first term of the series, the second call the second + // term and so on. + m_prod *= m_mult; + return m_prod / T(++k); + } + +private: + int k; + const std::complex<T> m_mult; + std::complex<T> m_prod; +}; + + +template <class T> +std::complex<T> log1p(std::complex<T> x) +{ + // We really should add some error checking on x here! + BOOST_ASSERT(abs(x) < 1); + + // Construct the series functor: + log1p_series<std::complex<T> > s(x); + // Set a limit on how many iterations we permit: + boost::uintmax_t max_iter = 1000; + // Add it up, with enough precision for full machine precision: + return boost::math::tools::sum_series(s, std::complex<T>(std::numeric_limits<T>::epsilon()), max_iter); +} +//] + +int main() +{ + using namespace boost::math::tools; + + std::cout << log1p(0.25) << std::endl; + + std::cout << log1p(std::complex<double>(0.25, 0.25)) << std::endl; + + return 0; +} diff --git a/src/boost/libs/math/example/sines.hpp b/src/boost/libs/math/example/sines.hpp new file mode 100644 index 000000000..d4cbbbbf3 --- /dev/null +++ b/src/boost/libs/math/example/sines.hpp @@ -0,0 +1,47 @@ +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Copyright A N Other, 2019. + +// Table of 32 values with 50 decimal digits precision, +// generated by program fft_sines_table.cpp. + +#include <array> // std::array + +static const std::array<double, 32> sines = +{{ + 1, + 0.70710678118654752440084436210484903928483593768847, + 0.38268343236508977172845998403039886676134456248563, + 0.19509032201612826784828486847702224092769161775195, + 0.098017140329560601994195563888641845861136673167501, + 0.049067674327418014254954976942682658314745363025753, + 0.024541228522912288031734529459282925065466119239452, + 0.012271538285719926079408261951003212140372319591769, + 0.0061358846491544753596402345903725809170578863173913, + 0.003067956762965976270145365490919842518944610213452, + 0.0015339801862847656123036971502640790799548645752374, + 0.00076699031874270452693856835794857664314091945206328, + 0.00038349518757139558907246168118138126339502603496474, + 0.00019174759731070330743990956198900093346887403385916, + 9.5873799095977345870517210976476351187065612851145e-05, + 4.7936899603066884549003990494658872746866687685767e-05, + 2.3968449808418218729186577165021820094761474895673e-05, + 1.1984224905069706421521561596988984804731977538387e-05, + 5.9921124526424278428797118088908617299871778780951e-06, + 2.9960562263346607504548128083570598118251878683408e-06, + 1.4980281131690112288542788461553611206917585861527e-06, + 7.4901405658471572113049856673065563715595930217207e-07, + 3.7450702829238412390316917908463317739740476297248e-07, + 1.8725351414619534486882457659356361712045272098286e-07, + 9.3626757073098082799067286680885620193236507169473e-08, + 4.681337853654909269511551813854009695950362701667e-08, + 2.3406689268274552759505493419034844037886207223779e-08, + 1.1703344634137277181246213503238103798093456639976e-08, + 5.8516723170686386908097901008341396943900085051756e-09, + 2.9258361585343193579282304690689559020175857150074e-09, + 1.4629180792671596805295321618659637103742615227834e-09, + 7.3145903963357984046044319684941757518633453150407e-10 +}}; // array sines diff --git a/src/boost/libs/math/example/skew_normal_example.cpp b/src/boost/libs/math/example/skew_normal_example.cpp new file mode 100644 index 000000000..5858aff35 --- /dev/null +++ b/src/boost/libs/math/example/skew_normal_example.cpp @@ -0,0 +1,275 @@ +// Copyright Benjamin Sobotta 2012 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + +#ifdef _MSC_VER +# pragma warning (disable : 4512) // assignment operator could not be generated +# pragma warning (disable : 4127) // conditional expression is constant. +#endif + +#include <boost/math/distributions/skew_normal.hpp> +using boost::math::skew_normal_distribution; +using boost::math::skew_normal; +#include <iostream> +#include <cmath> +#include <utility> + +void check(const double loc, const double sc, const double sh, + const double * const cumulants, const std::pair<double, double> qu, + const double x, const double tpdf, const double tcdf) +{ + using namespace boost::math; + + skew_normal D(loc, sc, sh); + + const double sk = cumulants[2] / (std::pow(cumulants[1], 1.5)); + const double kt = cumulants[3] / (cumulants[1] * cumulants[1]); + + // checks against tabulated values + std::cout << "mean: table=" << cumulants[0] << "\tcompute=" << mean(D) << "\tdiff=" << fabs(cumulants[0]-mean(D)) << std::endl; + std::cout << "var: table=" << cumulants[1] << "\tcompute=" << variance(D) << "\tdiff=" << fabs(cumulants[1]-variance(D)) << std::endl; + std::cout << "skew: table=" << sk << "\tcompute=" << skewness(D) << "\tdiff=" << fabs(sk-skewness(D)) << std::endl; + std::cout << "kur.: table=" << kt << "\tcompute=" << kurtosis_excess(D) << "\tdiff=" << fabs(kt-kurtosis_excess(D)) << std::endl; + std::cout << "mode: table=" << "N/A" << "\tcompute=" << mode(D) << "\tdiff=" << "N/A" << std::endl; + + const double q = quantile(D, qu.first); + const double cq = quantile(complement(D, qu.first)); + + std::cout << "quantile(" << qu.first << "): table=" << qu.second << "\tcompute=" << q << "\tdiff=" << fabs(qu.second-q) << std::endl; + + // consistency + std::cout << "cdf(quantile)=" << cdf(D, q) << "\tp=" << qu.first << "\tdiff=" << fabs(qu.first-cdf(D, q)) << std::endl; + std::cout << "ccdf(cquantile)=" << cdf(complement(D,cq)) << "\tp=" << qu.first << "\tdiff=" << fabs(qu.first-cdf(complement(D,cq))) << std::endl; + + // PDF & CDF + std::cout << "pdf(" << x << "): table=" << tpdf << "\tcompute=" << pdf(D,x) << "\tdiff=" << fabs(tpdf-pdf(D,x)) << std::endl; + std::cout << "cdf(" << x << "): table=" << tcdf << "\tcompute=" << cdf(D,x) << "\tdiff=" << fabs(tcdf-cdf(D,x)) << std::endl; + std::cout << "================================\n"; +} + +int main() +{ + using namespace boost::math; + + double sc = 0.0,loc,sh,x,dsn,qsn,psn,p; + std::cout << std::setprecision(20); + + double cumulants[4]; + + + /* R: + > install.packages("sn") + Warning in install.packages("sn") : + 'lib = "/usr/lib64/R/library"' is not writable + Would you like to create a personal library + '~/R/x86_64-unknown-linux-gnu-library/2.12' + to install packages into? (y/n) y + --- Please select a CRAN mirror for use in this session --- + Loading Tcl/Tk interface ... done + also installing the dependency mnormt + + trying URL 'http://mirrors.dotsrc.org/cran/src/contrib/mnormt_1.4-5.tar.gz' + Content type 'application/x-gzip' length 34049 bytes (33 Kb) + opened URL + ================================================== + downloaded 33 Kb + + trying URL 'http://mirrors.dotsrc.org/cran/src/contrib/sn_0.4-17.tar.gz' + Content type 'application/x-gzip' length 65451 bytes (63 Kb) + opened URL + ================================================== + downloaded 63 Kb + + + > library(sn) + > options(digits=22) + + + > sn.cumulants(1.1, 2.2, -3.3) + [1] -0.5799089925398568 2.0179057767837230 -2.0347951542374196 + [4] 2.2553488991015072 + > qsn(0.3, 1.1, 2.2, -3.3) + [1] -1.180104068086876 + > psn(0.4, 1.1, 2.2, -3.3) + [1] 0.733918618927874 + > dsn(0.4, 1.1, 2.2, -3.3) + [1] 0.2941401101565995 + + */ + + //1 st + loc = 1.1; sc = 2.2; sh = -3.3; + std::cout << "location: " << loc << "\tscale: " << sc << "\tshape: " << sh << std::endl; + cumulants[0] = -0.5799089925398568; + cumulants[1] = 2.0179057767837230; + cumulants[2] = -2.0347951542374196; + cumulants[3] = 2.2553488991015072; + x = 0.4; + p = 0.3; + qsn = -1.180104068086876; + psn = 0.733918618927874; + dsn = 0.2941401101565995; + + check(loc, sc, sh, cumulants, std::make_pair(p,qsn), x, dsn, psn); + + /* R: + + > sn.cumulants(1.1, .02, .03) + [1] 1.1004785154529559e+00 3.9977102296128255e-04 4.7027439329779991e-11 + [4] 1.4847542790693825e-14 + > qsn(0.01, 1.1, .02, .03) + [1] 1.053964962950150 + > psn(1.3, 1.1, .02, .03) + [1] 1 + > dsn(1.3, 1.1, .02, .03) + [1] 4.754580380601393e-21 + + */ + + // 2nd + loc = 1.1; sc = .02; sh = .03; + std::cout << "location: " << loc << "\tscale: " << sc << "\tshape: " << sh << std::endl; + cumulants[0] = 1.1004785154529559e+00; + cumulants[1] = 3.9977102296128255e-04; + cumulants[2] = 4.7027439329779991e-11; + cumulants[3] = 1.4847542790693825e-14; + x = 1.3; + p = 0.01; + qsn = 1.053964962950150; + psn = 1; + dsn = 4.754580380601393e-21; + + check(loc, sc, sh, cumulants, std::make_pair(p,qsn), x, dsn, psn); + + /* R: + + > sn.cumulants(10.1, 5, -.03) + [1] 9.980371136761052e+00 2.498568893508016e+01 -7.348037395278123e-04 + [4] 5.799821402614775e-05 + > qsn(.8, 10.1, 5, -.03) + [1] 14.18727407491953 + > psn(-1.3, 10.1, 5, -.03) + [1] 0.01201290665838824 + > dsn(-1.3, 10.1, 5, -.03) + [1] 0.006254346348897927 + + + */ + + // 3rd + loc = 10.1; sc = 5; sh = -.03; + std::cout << "location: " << loc << "\tscale: " << sc << "\tshape: " << sh << std::endl; + cumulants[0] = 9.980371136761052e+00; + cumulants[1] = 2.498568893508016e+01; + cumulants[2] = -7.348037395278123e-04; + cumulants[3] = 5.799821402614775e-05; + x = -1.3; + p = 0.8; + qsn = 14.18727407491953; + psn = 0.01201290665838824; + dsn = 0.006254346348897927; + + check(loc, sc, sh, cumulants, std::make_pair(p,qsn), x, dsn, psn); + + + /* R: + + > sn.cumulants(-10.1, 5, 30) + [1] -6.112791696741384 9.102169946425548 27.206345266148194 71.572537838642916 + > qsn(.8, -10.1, 5, 30) + [1] -3.692242172277 + > psn(-1.3, -10.1, 5, 30) + [1] 0.921592193425035 + > dsn(-1.3, -10.1, 5, 30) + [1] 0.0339105445232089 + + */ + + // 4th + loc = -10.1; sc = 5; sh = 30; + std::cout << "location: " << loc << "\tscale: " << sc << "\tshape: " << sh << std::endl; + cumulants[0] = -6.112791696741384; + cumulants[1] = 9.102169946425548; + cumulants[2] = 27.206345266148194; + cumulants[3] = 71.572537838642916; + x = -1.3; + p = 0.8; + qsn = -3.692242172277; + psn = 0.921592193425035; + dsn = 0.0339105445232089; + + check(loc, sc, sh, cumulants, std::make_pair(p,qsn), x, dsn, psn); + + + /* R: + + > sn.cumulants(0,1,5) + [1] 0.7823901817554269 0.3878656034927102 0.2055576317962637 0.1061119471655128 + > qsn(0.5,0,1,5) + [1] 0.674471117502844 + > psn(-0.5, 0,1,5) + [1] 0.0002731513884140924 + > dsn(-0.5, 0,1,5) + [1] 0.00437241570403263 + + */ + + // 5th + loc = 0; sc = 1; sh = 5; + std::cout << "location: " << loc << "\tscale: " << sc << "\tshape: " << sh << std::endl; + cumulants[0] = 0.7823901817554269; + cumulants[1] = 0.3878656034927102; + cumulants[2] = 0.2055576317962637; + cumulants[3] = 0.1061119471655128; + x = -0.5; + p = 0.5; + qsn = 0.674471117502844; + psn = 0.0002731513884140924; + dsn = 0.00437241570403263; + + check(loc, sc, sh, cumulants, std::make_pair(p,qsn), x, dsn, psn); + + /* R: + + > sn.cumulants(0,1,1e5) + [1] 0.7978845607629713 0.3633802276960805 0.2180136141122883 0.1147706820312645 + > qsn(0.5,0,1,1e5) + [1] 0.6744897501960818 + > psn(-0.5, 0,1,1e5) + [1] 0 + > dsn(-0.5, 0,1,1e5) + [1] 0 + + */ + + // 6th + loc = 0; sc = 1; sh = 1e5; + std::cout << "location: " << loc << "\tscale: " << sc << "\tshape: " << sh << std::endl; + cumulants[0] = 0.7978845607629713; + cumulants[1] = 0.3633802276960805; + cumulants[2] = 0.2180136141122883; + cumulants[3] = 0.1147706820312645; + x = -0.5; + p = 0.5; + qsn = 0.6744897501960818; + psn = 0.; + dsn = 0.; + + check(loc, sc, sh, cumulants, std::make_pair(p,qsn), x, dsn, psn); + + return 0; +} + + +// EOF + + + + + + + + diff --git a/src/boost/libs/math/example/special_data.cpp b/src/boost/libs/math/example/special_data.cpp new file mode 100644 index 000000000..2e101b409 --- /dev/null +++ b/src/boost/libs/math/example/special_data.cpp @@ -0,0 +1,84 @@ +// Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +//[special_data_example + +#include <boost/multiprecision/cpp_dec_float.hpp> +#include <boost/math/tools/test_data.hpp> +#include <boost/test/included/prg_exec_monitor.hpp> +#include <fstream> + +using namespace boost::math::tools; +using namespace boost::math; +using namespace std; +using namespace boost::multiprecision; + +template <class T> +T my_special(T a, T b) +{ + // Implementation of my_special here... + return a + b; +} + +int cpp_main(int argc, char*argv []) +{ + // + // We'll use so many digits of precision that any + // calculation errors will still leave us with + // 40-50 good digits. We'll only run this program + // once so it doesn't matter too much how long this takes! + // + typedef number<cpp_dec_float<500> > bignum; + + parameter_info<bignum> arg1, arg2; + test_data<bignum> data; + + bool cont; + std::string line; + + if(argc < 1) + return 1; + + do{ + // + // User interface which prompts for + // range of input parameters: + // + if(0 == get_user_parameter_info(arg1, "a")) + return 1; + if(0 == get_user_parameter_info(arg2, "b")) + return 1; + + // + // Get a pointer to the function and call + // test_data::insert to actually generate + // the values. + // + bignum (*fp)(bignum, bignum) = &my_special; + data.insert(fp, arg2, arg1); + + std::cout << "Any more data [y/n]?"; + std::getline(std::cin, line); + boost::algorithm::trim(line); + cont = (line == "y"); + }while(cont); + // + // Just need to write the results to a file: + // + std::cout << "Enter name of test data file [default=my_special.ipp]"; + std::getline(std::cin, line); + boost::algorithm::trim(line); + if(line == "") + line = "my_special.ipp"; + std::ofstream ofs(line.c_str()); + line.erase(line.find('.')); + ofs << std::scientific << std::setprecision(50); + write_code(ofs, data, line.c_str()); + + return 0; +} + +//] diff --git a/src/boost/libs/math/example/students_t_example1.cpp b/src/boost/libs/math/example/students_t_example1.cpp new file mode 100644 index 000000000..c86b89d5d --- /dev/null +++ b/src/boost/libs/math/example/students_t_example1.cpp @@ -0,0 +1,101 @@ +// students_t_example1.cpp + +// Copyright Paul A. Bristow 2006, 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Example 1 of using Student's t + +// http://en.wikipedia.org/wiki/Student's_t-test says: +// The t statistic was invented by William Sealy Gosset +// for cheaply monitoring the quality of beer brews. +// "Student" was his pen name. +// WS Gosset was statistician for Guinness brewery in Dublin, Ireland, +// hired due to Claude Guinness's innovative policy of recruiting the +// best graduates from Oxford and Cambridge for applying biochemistry +// and statistics to Guinness's industrial processes. +// Gosset published the t test in Biometrika in 1908, +// but was forced to use a pen name by his employer who regarded the fact +// that they were using statistics as a trade secret. +// In fact, Gosset's identity was unknown not only to fellow statisticians +// but to his employer - the company insisted on the pseudonym +// so that it could turn a blind eye to the breach of its rules. + +// Data for this example from: +// P.K.Hou, O. W. Lau & M.C. Wong, Analyst (1983) vol. 108, p 64. +// from Statistics for Analytical Chemistry, 3rd ed. (1994), pp 54-55 +// J. C. Miller and J. N. Miller, Ellis Horwood ISBN 0 13 0309907 + +// Determination of mercury by cold-vapour atomic absorption, +// the following values were obtained fusing a trusted +// Standard Reference Material containing 38.9% mercury, +// which we assume is correct or 'true'. +double standard = 38.9; + +const int values = 3; +double value[values] = {38.9, 37.4, 37.1}; + +// Is there any evidence for systematic error? + +// The Students't distribution function is described at +// http://en.wikipedia.org/wiki/Student%27s_t_distribution +#include <boost/math/distributions/students_t.hpp> + using boost::math::students_t; // Probability of students_t(df, t). + +#include <iostream> + using std::cout; using std::endl; +#include <iomanip> + using std::setprecision; +#include <cmath> + using std::sqrt; + +int main() +{ + cout << "Example 1 using Student's t function. " << endl; + + // Example/test using tabulated value + // (deliberately coded as naively as possible). + + // Null hypothesis is that there is no difference (greater or less) + // between measured and standard. + + double degrees_of_freedom = values-1; // 3-1 = 2 + cout << "Measurement 1 = " << value[0] << ", measurement 2 = " << value[1] << ", measurement 3 = " << value[2] << endl; + double mean = (value[0] + value[1] + value[2]) / static_cast<double>(values); + cout << "Standard = " << standard << ", mean = " << mean << ", (mean - standard) = " << mean - standard << endl; + double sd = sqrt(((value[0] - mean) * (value[0] - mean) + (value[1] - mean) * (value[1] - mean) + (value[2] - mean) * (value[2] - mean))/ static_cast<double>(values-1)); + cout << "Standard deviation = " << sd << endl; + if (sd == 0.) + { + cout << "Measured mean is identical to SRM value," << endl; + cout << "so probability of no difference between measured and standard (the 'null hypothesis') is unity." << endl; + return 0; + } + + double t = (mean - standard) * std::sqrt(static_cast<double>(values)) / sd; + cout << "Student's t = " << t << endl; + cout.precision(2); // Useful accuracy is only a few decimal digits. + cout << "Probability of Student's t is " << cdf(students_t(degrees_of_freedom), std::abs(t)) << endl; + // 0.91, is 1 tailed. + // So there is insufficient evidence of a difference to meet a 95% (1 in 20) criterion. + + return 0; +} // int main() + +/* + +Output is: + +Example 1 using Student's t function. +Measurement 1 = 38.9, measurement 2 = 37.4, measurement 3 = 37.1 +Standard = 38.9, mean = 37.8, (mean - standard) = -1.1 +Standard deviation = 0.964365 +Student's t = -1.97566 +Probability of Student's t is 0.91 + +*/ + + diff --git a/src/boost/libs/math/example/students_t_example2.cpp b/src/boost/libs/math/example/students_t_example2.cpp new file mode 100644 index 000000000..bbd423162 --- /dev/null +++ b/src/boost/libs/math/example/students_t_example2.cpp @@ -0,0 +1,126 @@ +// students_t_example2.cpp + +// Copyright Paul A. Bristow 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Example 2 of using Student's t + +// A general guide to Student's t is at +// http://en.wikipedia.org/wiki/Student's_t-test +// (and many other elementary and advanced statistics texts). +// It says: +// The t statistic was invented by William Sealy Gosset +// for cheaply monitoring the quality of beer brews. +// "Student" was his pen name. +// Gosset was statistician for Guinness brewery in Dublin, Ireland, +// hired due to Claude Guinness's innovative policy of recruiting the +// best graduates from Oxford and Cambridge for applying biochemistry +// and statistics to Guinness's industrial processes. +// Gosset published the t test in Biometrika in 1908, +// but was forced to use a pen name by his employer who regarded the fact +// that they were using statistics as a trade secret. +// In fact, Gosset's identity was unknown not only to fellow statisticians +// but to his employer - the company insisted on the pseudonym +// so that it could turn a blind eye to the breach of its rules. + +// The Students't distribution function is described at +// http://en.wikipedia.org/wiki/Student%27s_t_distribution + +#include <boost/math/distributions/students_t.hpp> + using boost::math::students_t; // Probability of students_t(df, t). + +#include <iostream> + using std::cout; + using std::endl; +#include <iomanip> + using std::setprecision; + using std::setw; +#include <cmath> + using std::sqrt; + +// This example of a one-sided test is from: +// +// from Statistics for Analytical Chemistry, 3rd ed. (1994), pp 59-60 +// J. C. Miller and J. N. Miller, Ellis Horwood ISBN 0 13 0309907. + +// An acid-base titrimetric method has a significant indicator error and +// thus tends to give results with a positive systematic error (+bias). +// To test this an exactly 0.1 M solution of acid is used to titrate +// 25.00 ml of exactly 0.1 M solution of alkali, +// with the following results (ml): + +double reference = 25.00; // 'True' result. +const int values = 6; // titrations. +double data [values] = {25.06, 25.18, 24.87, 25.51, 25.34, 25.41}; + +int main() +{ + cout << "Example2 using Student's t function. "; +#if defined(__FILE__) && defined(__TIMESTAMP__) && defined(_MSC_FULL_VER) + cout << " " << __FILE__ << ' ' << __TIMESTAMP__ << ' '<< _MSC_FULL_VER; +#endif + cout << endl; + + double sum = 0.; + for (int value = 0; value < values; value++) + { // Echo data and calculate mean. + sum += data[value]; + cout << setw(4) << value << ' ' << setw(14) << data[value] << endl; + } + double mean = sum /static_cast<double>(values); + cout << "Mean = " << mean << endl; // 25.2283 + + double sd = 0.; + for (int value = 0; value < values; value++) + { // Calculate standard deviation. + sd +=(data[value] - mean) * (data[value] - mean); + } + int degrees_of_freedom = values - 1; // Use the n-1 formula. + sd /= degrees_of_freedom; // == variance. + sd= sqrt(sd); + cout << "Standard deviation = " << sd<< endl; // = 0.238279 + + double t = (mean - reference) * sqrt(static_cast<double>(values))/ sd; // + cout << "Student's t = " << t << ", with " << degrees_of_freedom << " degrees of freedom." << endl; // = 2.34725 + + cout << "Probability of positive bias is " << cdf(students_t(degrees_of_freedom), t) << "."<< endl; // = 0.967108. + // A 1-sided test because only testing for a positive bias. + // If > 0.95 then greater than 1 in 20 conventional (arbitrary) requirement. + + return 0; +} // int main() + +/* + +Output is: + +------ Build started: Project: students_t_example2, Configuration: Debug Win32 ------ +Compiling... +students_t_example2.cpp +Linking... +Autorun "i:\boost-06-05-03-1300\libs\math\test\Math_test\debug\students_t_example2.exe" +Example2 using Student's t function. ..\..\..\..\..\..\boost-sandbox\libs\math_functions\example\students_t_example2.cpp Sat Aug 12 16:55:59 2006 140050727 + 0 25.06 + 1 25.18 + 2 24.87 + 3 25.51 + 4 25.34 + 5 25.41 +Mean = 25.2283 +Standard deviation = 0.238279 +Student's t = 2.34725, with 5 degrees of freedom. +Probability of positive bias is 0.967108. +Build Time 0:03 +Build log was saved at "file://i:\boost-06-05-03-1300\libs\math\test\Math_test\students_t_example2\Debug\BuildLog.htm" +students_t_example2 - 0 error(s), 0 warning(s) +========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ========== + +*/ + + + + + diff --git a/src/boost/libs/math/example/students_t_example3.cpp b/src/boost/libs/math/example/students_t_example3.cpp new file mode 100644 index 000000000..289daec09 --- /dev/null +++ b/src/boost/libs/math/example/students_t_example3.cpp @@ -0,0 +1,120 @@ +// students_t_example3.cpp +// Copyright Paul A. Bristow 2006, 2007. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Example 3 of using Student's t. + +// A general guide to Student's t is at +// http://en.wikipedia.org/wiki/Student's_t-test +// (and many other elementary and advanced statistics texts). +// It says: +// The t statistic was invented by William Sealy Gosset +// for cheaply monitoring the quality of beer brews. +// "Student" was his pen name. +// Gosset was statistician for Guinness brewery in Dublin, Ireland, +// hired due to Claude Guinness's innovative policy of recruiting the +// best graduates from Oxford and Cambridge for applying biochemistry +// and statistics to Guinness's industrial processes. +// Gosset published the t test in Biometrika in 1908, +// but was forced to use a pen name by his employer who regarded the fact +// that they were using statistics as a trade secret. +// In fact, Gosset's identity was unknown not only to fellow statisticians +// but to his employer - the company insisted on the pseudonym +// so that it could turn a blind eye to the breach of its rules. + +// The Students't distribution function is described at +// http://en.wikipedia.org/wiki/Student%27s_t_distribution + +#include <boost/math/distributions/students_t.hpp> + using boost::math::students_t; // Probability of students_t(df, t). + +#include <iostream> + using std::cout; using std::endl; +#include <iomanip> + using std::setprecision; using std::setw; +#include <cmath> + using std::sqrt; + +// This example of a two-sided test is from: +// B. M. Smith & M. B. Griffiths, Analyst, 1982, 107, 253, +// from Statistics for Analytical Chemistry, 3rd ed. (1994), pp 58-59 +// J. C. Miller and J. N. Miller, Ellis Horwood ISBN 0 13 0309907 + +// Concentrations of lead (ug/l) determined by two different methods +// for each of four test portions, +// the concentration of each portion is significantly different, +// the values may NOT be pooled. +// (Called a 'paired test' by Miller and Miller +// because each portion analysed has a different concentration.) + +// Portion Wet oxidation Direct Extraction +// 1 71 76 +// 2 61 68 +// 3 50 48 +// 4 60 57 + +const int portions = 4; +const int methods = 2; +float data [portions][methods] = {{71, 76}, {61,68}, {50, 48}, {60, 57}}; +float diffs[portions]; + +int main() +{ + cout << "Example3 using Student's t function. " << endl; + float mean_diff = 0.f; + cout << "\n""Portion wet_oxidation Direct_extraction difference" << endl; + for (int portion = 0; portion < portions; portion++) + { // Echo data and differences. + diffs[portion] = data[portion][0] - data[portion][1]; + mean_diff += diffs[portion]; + cout << setw(4) << portion << ' ' << setw(14) << data[portion][0] << ' ' << setw(18)<< data[portion][1] << ' ' << setw(9) << diffs[portion] << endl; + } + mean_diff /= portions; + cout << "Mean difference = " << mean_diff << endl; // -1.75 + + float sd_diffs = 0.f; + for (int portion = 0; portion < portions; portion++) + { // Calculate standard deviation of differences. + sd_diffs +=(diffs[portion] - mean_diff) * (diffs[portion] - mean_diff); + } + int degrees_of_freedom = portions-1; // Use the n-1 formula. + sd_diffs /= degrees_of_freedom; + sd_diffs = sqrt(sd_diffs); + cout << "Standard deviation of differences = " << sd_diffs << endl; // 4.99166 + // Standard deviation of differences = 4.99166 + double t = mean_diff * sqrt(static_cast<double>(portions))/ sd_diffs; // -0.70117 + cout << "Student's t = " << t << ", if " << degrees_of_freedom << " degrees of freedom." << endl; + // Student's t = -0.70117, if 3 degrees of freedom. + cout << "Probability of the means being different is " + << 2.F * cdf(students_t(degrees_of_freedom), t) << "."<< endl; // 0.266846 * 2 = 0.533692 + // Double the probability because using a 'two-sided test' because + // mean for 'Wet oxidation' could be either + // greater OR LESS THAN for 'Direct extraction'. + + return 0; +} // int main() + +/* + +Output is: + +Example3 using Student's t function. +Portion wet_oxidation Direct_extraction difference + 0 71 76 -5 + 1 61 68 -7 + 2 50 48 2 + 3 60 57 3 +Mean difference = -1.75 +Standard deviation of differences = 4.99166 +Student's t = -0.70117, if 3 degrees of freedom. +Probability of the means being different is 0.533692. + +*/ + + + + diff --git a/src/boost/libs/math/example/students_t_single_sample.cpp b/src/boost/libs/math/example/students_t_single_sample.cpp new file mode 100644 index 000000000..591466ae5 --- /dev/null +++ b/src/boost/libs/math/example/students_t_single_sample.cpp @@ -0,0 +1,424 @@ +// Copyright John Maddock 2006 +// Copyright Paul A. Bristow 2007, 2010 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifdef _MSC_VER +# pragma warning(disable: 4512) // assignment operator could not be generated. +# pragma warning(disable: 4510) // default constructor could not be generated. +# pragma warning(disable: 4610) // can never be instantiated - user defined constructor required. +#endif + +#include <boost/math/distributions/students_t.hpp> + +// avoid "using namespace std;" and "using namespace boost::math;" +// to avoid potential ambiguity with names in std random. +#include <iostream> +using std::cout; using std::endl; +using std::left; using std::fixed; using std::right; using std::scientific; +#include <iomanip> +using std::setw; +using std::setprecision; + +void confidence_limits_on_mean(double Sm, double Sd, unsigned Sn) +{ + // + // Sm = Sample Mean. + // Sd = Sample Standard Deviation. + // Sn = Sample Size. + // + // Calculate confidence intervals for the mean. + // For example if we set the confidence limit to + // 0.95, we know that if we repeat the sampling + // 100 times, then we expect that the true mean + // will be between out limits on 95 occasions. + // Note: this is not the same as saying a 95% + // confidence interval means that there is a 95% + // probability that the interval contains the true mean. + // The interval computed from a given sample either + // contains the true mean or it does not. + // See http://www.itl.nist.gov/div898/handbook/eda/section3/eda352.htm + + using boost::math::students_t; + + // Print out general info: + cout << + "__________________________________\n" + "2-Sided Confidence Limits For Mean\n" + "__________________________________\n\n"; + cout << setprecision(7); + cout << setw(40) << left << "Number of Observations" << "= " << Sn << "\n"; + cout << setw(40) << left << "Mean" << "= " << Sm << "\n"; + cout << setw(40) << left << "Standard Deviation" << "= " << Sd << "\n"; + // + // Define a table of significance/risk levels: + // + double alpha[] = { 0.5, 0.25, 0.1, 0.05, 0.01, 0.001, 0.0001, 0.00001 }; + // + // Start by declaring the distribution we'll need: + // + students_t dist(Sn - 1); + // + // Print table header: + // + cout << "\n\n" + "_______________________________________________________________\n" + "Confidence T Interval Lower Upper\n" + " Value (%) Value Width Limit Limit\n" + "_______________________________________________________________\n"; + // + // Now print out the data for the table rows. + // + for(unsigned i = 0; i < sizeof(alpha)/sizeof(alpha[0]); ++i) + { + // Confidence value: + cout << fixed << setprecision(3) << setw(10) << right << 100 * (1-alpha[i]); + // calculate T: + double T = quantile(complement(dist, alpha[i] / 2)); + // Print T: + cout << fixed << setprecision(3) << setw(10) << right << T; + // Calculate width of interval (one sided): + double w = T * Sd / sqrt(double(Sn)); + // Print width: + if(w < 0.01) + cout << scientific << setprecision(3) << setw(17) << right << w; + else + cout << fixed << setprecision(3) << setw(17) << right << w; + // Print Limits: + cout << fixed << setprecision(5) << setw(15) << right << Sm - w; + cout << fixed << setprecision(5) << setw(15) << right << Sm + w << endl; + } + cout << endl; +} // void confidence_limits_on_mean + +void single_sample_t_test(double M, double Sm, double Sd, unsigned Sn, double alpha) +{ + // + // M = true mean. + // Sm = Sample Mean. + // Sd = Sample Standard Deviation. + // Sn = Sample Size. + // alpha = Significance Level. + // + // A Students t test applied to a single set of data. + // We are testing the null hypothesis that the true + // mean of the sample is M, and that any variation is down + // to chance. We can also test the alternative hypothesis + // that any difference is not down to chance. + // See http://www.itl.nist.gov/div898/handbook/eda/section3/eda352.htm + + using boost::math::students_t; + + // Print header: + cout << + "__________________________________\n" + "Student t test for a single sample\n" + "__________________________________\n\n"; + cout << setprecision(5); + cout << setw(55) << left << "Number of Observations" << "= " << Sn << "\n"; + cout << setw(55) << left << "Sample Mean" << "= " << Sm << "\n"; + cout << setw(55) << left << "Sample Standard Deviation" << "= " << Sd << "\n"; + cout << setw(55) << left << "Expected True Mean" << "= " << M << "\n\n"; + // + // Now we can calculate and output some stats: + // + // Difference in means: + double diff = Sm - M; + cout << setw(55) << left << "Sample Mean - Expected Test Mean" << "= " << diff << "\n"; + // Degrees of freedom: + unsigned v = Sn - 1; + cout << setw(55) << left << "Degrees of Freedom" << "= " << v << "\n"; + // t-statistic: + double t_stat = diff * sqrt(double(Sn)) / Sd; + cout << setw(55) << left << "T Statistic" << "= " << t_stat << "\n"; + // + // Finally define our distribution, and get the probability: + // + students_t dist(v); + double q = cdf(complement(dist, fabs(t_stat))); + cout << setw(55) << left << "Probability that difference is due to chance" << "= " + << setprecision(3) << scientific << 2 * q << "\n\n"; + // + // Finally print out results of alternative hypothesis: + // + cout << setw(55) << left << + "Results for Alternative Hypothesis and alpha" << "= " + << setprecision(4) << fixed << alpha << "\n\n"; + cout << "Alternative Hypothesis Conclusion\n"; + cout << "Mean != " << setprecision(3) << fixed << M << " "; + if(q < alpha / 2) + cout << "NOT REJECTED\n"; + else + cout << "REJECTED\n"; + cout << "Mean < " << setprecision(3) << fixed << M << " "; + if(cdf(complement(dist, t_stat)) > alpha) + cout << "NOT REJECTED\n"; + else + cout << "REJECTED\n"; + cout << "Mean > " << setprecision(3) << fixed << M << " "; + if(cdf(dist, t_stat) > alpha) + cout << "NOT REJECTED\n"; + else + cout << "REJECTED\n"; + cout << endl << endl; +} // void single_sample_t_test( + +void single_sample_find_df(double M, double Sm, double Sd) +{ + // + // M = true mean. + // Sm = Sample Mean. + // Sd = Sample Standard Deviation. + // + + using boost::math::students_t; + + // Print out general info: + cout << + "_____________________________________________________________\n" + "Estimated sample sizes required for various confidence levels\n" + "_____________________________________________________________\n\n"; + cout << setprecision(5); + cout << setw(40) << left << "True Mean" << "= " << M << "\n"; + cout << setw(40) << left << "Sample Mean" << "= " << Sm << "\n"; + cout << setw(40) << left << "Sample Standard Deviation" << "= " << Sd << "\n"; + // + // Define a table of significance intervals: + // + double alpha[] = { 0.5, 0.25, 0.1, 0.05, 0.01, 0.001, 0.0001, 0.00001 }; + // + // Print table header: + // + cout << "\n\n" + "_______________________________________________________________\n" + "Confidence Estimated Estimated\n" + " Value (%) Sample Size Sample Size\n" + " (one sided test) (two sided test)\n" + "_______________________________________________________________\n"; + // + // Now print out the data for the table rows. + // + for(unsigned i = 1; i < sizeof(alpha)/sizeof(alpha[0]); ++i) + { + // Confidence value: + cout << fixed << setprecision(3) << setw(10) << right << 100 * (1-alpha[i]); + // calculate df for single sided test: + double df = students_t::find_degrees_of_freedom( + fabs(M - Sm), alpha[i], alpha[i], Sd); + // convert to sample size, always one more than the degrees of freedom: + double size = ceil(df) + 1; + // Print size: + cout << fixed << setprecision(0) << setw(16) << right << size; + // calculate df for two sided test: + df = students_t::find_degrees_of_freedom( + fabs(M - Sm), alpha[i]/2, alpha[i], Sd); + // convert to sample size: + size = ceil(df) + 1; + // Print size: + cout << fixed << setprecision(0) << setw(16) << right << size << endl; + } + cout << endl; +} // void single_sample_find_df + +int main() +{ + // + // Run tests for Heat Flow Meter data + // see http://www.itl.nist.gov/div898/handbook/eda/section4/eda428.htm + // The data was collected while calibrating a heat flow meter + // against a known value. + // + confidence_limits_on_mean(9.261460, 0.2278881e-01, 195); + single_sample_t_test(5, 9.261460, 0.2278881e-01, 195, 0.05); + single_sample_find_df(5, 9.261460, 0.2278881e-01); + + // + // Data for this example from: + // P.K.Hou, O. W. Lau & M.C. Wong, Analyst (1983) vol. 108, p 64. + // from Statistics for Analytical Chemistry, 3rd ed. (1994), pp 54-55 + // J. C. Miller and J. N. Miller, Ellis Horwood ISBN 0 13 0309907 + // + // Determination of mercury by cold-vapour atomic absorption, + // the following values were obtained fusing a trusted + // Standard Reference Material containing 38.9% mercury, + // which we assume is correct or 'true'. + // + confidence_limits_on_mean(37.8, 0.964365, 3); + // 95% test: + single_sample_t_test(38.9, 37.8, 0.964365, 3, 0.05); + // 90% test: + single_sample_t_test(38.9, 37.8, 0.964365, 3, 0.1); + // parameter estimate: + single_sample_find_df(38.9, 37.8, 0.964365); + + return 0; +} // int main() + +/* + +Output: + +------ Rebuild All started: Project: students_t_single_sample, Configuration: Release Win32 ------ + students_t_single_sample.cpp + Generating code + Finished generating code + students_t_single_sample.vcxproj -> J:\Cpp\MathToolkit\test\Math_test\Release\students_t_single_sample.exe +__________________________________ +2-Sided Confidence Limits For Mean +__________________________________ + +Number of Observations = 195 +Mean = 9.26146 +Standard Deviation = 0.02278881 + + +_______________________________________________________________ +Confidence T Interval Lower Upper + Value (%) Value Width Limit Limit +_______________________________________________________________ + 50.000 0.676 1.103e-003 9.26036 9.26256 + 75.000 1.154 1.883e-003 9.25958 9.26334 + 90.000 1.653 2.697e-003 9.25876 9.26416 + 95.000 1.972 3.219e-003 9.25824 9.26468 + 99.000 2.601 4.245e-003 9.25721 9.26571 + 99.900 3.341 5.453e-003 9.25601 9.26691 + 99.990 3.973 6.484e-003 9.25498 9.26794 + 99.999 4.537 7.404e-003 9.25406 9.26886 + +__________________________________ +Student t test for a single sample +__________________________________ + +Number of Observations = 195 +Sample Mean = 9.26146 +Sample Standard Deviation = 0.02279 +Expected True Mean = 5.00000 + +Sample Mean - Expected Test Mean = 4.26146 +Degrees of Freedom = 194 +T Statistic = 2611.28380 +Probability that difference is due to chance = 0.000e+000 + +Results for Alternative Hypothesis and alpha = 0.0500 + +Alternative Hypothesis Conclusion +Mean != 5.000 NOT REJECTED +Mean < 5.000 REJECTED +Mean > 5.000 NOT REJECTED + + +_____________________________________________________________ +Estimated sample sizes required for various confidence levels +_____________________________________________________________ + +True Mean = 5.00000 +Sample Mean = 9.26146 +Sample Standard Deviation = 0.02279 + + +_______________________________________________________________ +Confidence Estimated Estimated + Value (%) Sample Size Sample Size + (one sided test) (two sided test) +_______________________________________________________________ + 75.000 2 2 + 90.000 2 2 + 95.000 2 2 + 99.000 2 2 + 99.900 3 3 + 99.990 3 3 + 99.999 4 4 + +__________________________________ +2-Sided Confidence Limits For Mean +__________________________________ + +Number of Observations = 3 +Mean = 37.8000000 +Standard Deviation = 0.9643650 + + +_______________________________________________________________ +Confidence T Interval Lower Upper + Value (%) Value Width Limit Limit +_______________________________________________________________ + 50.000 0.816 0.455 37.34539 38.25461 + 75.000 1.604 0.893 36.90717 38.69283 + 90.000 2.920 1.626 36.17422 39.42578 + 95.000 4.303 2.396 35.40438 40.19562 + 99.000 9.925 5.526 32.27408 43.32592 + 99.900 31.599 17.594 20.20639 55.39361 + 99.990 99.992 55.673 -17.87346 93.47346 + 99.999 316.225 176.067 -138.26683 213.86683 + +__________________________________ +Student t test for a single sample +__________________________________ + +Number of Observations = 3 +Sample Mean = 37.80000 +Sample Standard Deviation = 0.96437 +Expected True Mean = 38.90000 + +Sample Mean - Expected Test Mean = -1.10000 +Degrees of Freedom = 2 +T Statistic = -1.97566 +Probability that difference is due to chance = 1.869e-001 + +Results for Alternative Hypothesis and alpha = 0.0500 + +Alternative Hypothesis Conclusion +Mean != 38.900 REJECTED +Mean < 38.900 NOT REJECTED +Mean > 38.900 NOT REJECTED + + +__________________________________ +Student t test for a single sample +__________________________________ + +Number of Observations = 3 +Sample Mean = 37.80000 +Sample Standard Deviation = 0.96437 +Expected True Mean = 38.90000 + +Sample Mean - Expected Test Mean = -1.10000 +Degrees of Freedom = 2 +T Statistic = -1.97566 +Probability that difference is due to chance = 1.869e-001 + +Results for Alternative Hypothesis and alpha = 0.1000 + +Alternative Hypothesis Conclusion +Mean != 38.900 REJECTED +Mean < 38.900 NOT REJECTED +Mean > 38.900 REJECTED + + +_____________________________________________________________ +Estimated sample sizes required for various confidence levels +_____________________________________________________________ + +True Mean = 38.90000 +Sample Mean = 37.80000 +Sample Standard Deviation = 0.96437 + + +_______________________________________________________________ +Confidence Estimated Estimated + Value (%) Sample Size Sample Size + (one sided test) (two sided test) +_______________________________________________________________ + 75.000 3 4 + 90.000 7 9 + 95.000 11 13 + 99.000 20 22 + 99.900 35 37 + 99.990 50 53 + 99.999 66 68 + +*/ + diff --git a/src/boost/libs/math/example/students_t_two_samples.cpp b/src/boost/libs/math/example/students_t_two_samples.cpp new file mode 100644 index 000000000..66a9e7036 --- /dev/null +++ b/src/boost/libs/math/example/students_t_two_samples.cpp @@ -0,0 +1,245 @@ +// Copyright John Maddock 2006. +// Copyright Paul A. Bristow 2007, 2010 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifdef _MSC_VER +# pragma warning(disable: 4512) // assignment operator could not be generated. +# pragma warning(disable: 4510) // default constructor could not be generated. +# pragma warning(disable: 4610) // can never be instantiated - user defined constructor required. +#endif + +#include <iostream> +using std::cout; using std::endl; +using std::left; using std::fixed; using std::right; using std::scientific; +#include <iomanip> +using std::setw; +using std::setprecision; + +#include <boost/math/distributions/students_t.hpp> + using boost::math::students_t; + + +void two_samples_t_test_equal_sd( + double Sm1, // Sm1 = Sample Mean 1. + double Sd1, // Sd1 = Sample Standard Deviation 1. + unsigned Sn1, // Sn1 = Sample Size 1. + double Sm2, // Sm2 = Sample Mean 2. + double Sd2, // Sd2 = Sample Standard Deviation 2. + unsigned Sn2, // Sn2 = Sample Size 2. + double alpha) // alpha = Significance Level. +{ + // A Students t test applied to two sets of data. + // We are testing the null hypothesis that the two + // samples have the same mean and that any difference + // if due to chance. + // See http://www.itl.nist.gov/div898/handbook/eda/section3/eda353.htm + // + using namespace std; + // using namespace boost::math; + + using boost::math::students_t; + + // Print header: + cout << + "_______________________________________________\n" + "Student t test for two samples (equal variances)\n" + "_______________________________________________\n\n"; + cout << setprecision(5); + cout << setw(55) << left << "Number of Observations (Sample 1)" << "= " << Sn1 << "\n"; + cout << setw(55) << left << "Sample 1 Mean" << "= " << Sm1 << "\n"; + cout << setw(55) << left << "Sample 1 Standard Deviation" << "= " << Sd1 << "\n"; + cout << setw(55) << left << "Number of Observations (Sample 2)" << "= " << Sn2 << "\n"; + cout << setw(55) << left << "Sample 2 Mean" << "= " << Sm2 << "\n"; + cout << setw(55) << left << "Sample 2 Standard Deviation" << "= " << Sd2 << "\n"; + // + // Now we can calculate and output some stats: + // + // Degrees of freedom: + double v = Sn1 + Sn2 - 2; + cout << setw(55) << left << "Degrees of Freedom" << "= " << v << "\n"; + // Pooled variance and hence standard deviation: + double sp = sqrt(((Sn1-1) * Sd1 * Sd1 + (Sn2-1) * Sd2 * Sd2) / v); + cout << setw(55) << left << "Pooled Standard Deviation" << "= " << sp << "\n"; + // t-statistic: + double t_stat = (Sm1 - Sm2) / (sp * sqrt(1.0 / Sn1 + 1.0 / Sn2)); + cout << setw(55) << left << "T Statistic" << "= " << t_stat << "\n"; + // + // Define our distribution, and get the probability: + // + students_t dist(v); + double q = cdf(complement(dist, fabs(t_stat))); + cout << setw(55) << left << "Probability that difference is due to chance" << "= " + << setprecision(3) << scientific << 2 * q << "\n\n"; + // + // Finally print out results of alternative hypothesis: + // + cout << setw(55) << left << + "Results for Alternative Hypothesis and alpha" << "= " + << setprecision(4) << fixed << alpha << "\n\n"; + cout << "Alternative Hypothesis Conclusion\n"; + cout << "Sample 1 Mean != Sample 2 Mean " ; + if(q < alpha / 2) + cout << "NOT REJECTED\n"; + else + cout << "REJECTED\n"; + cout << "Sample 1 Mean < Sample 2 Mean "; + if(cdf(dist, t_stat) < alpha) + cout << "NOT REJECTED\n"; + else + cout << "REJECTED\n"; + cout << "Sample 1 Mean > Sample 2 Mean "; + if(cdf(complement(dist, t_stat)) < alpha) + cout << "NOT REJECTED\n"; + else + cout << "REJECTED\n"; + cout << endl << endl; +} + +void two_samples_t_test_unequal_sd( + double Sm1, // Sm1 = Sample Mean 1. + double Sd1, // Sd1 = Sample Standard Deviation 1. + unsigned Sn1, // Sn1 = Sample Size 1. + double Sm2, // Sm2 = Sample Mean 2. + double Sd2, // Sd2 = Sample Standard Deviation 2. + unsigned Sn2, // Sn2 = Sample Size 2. + double alpha) // alpha = Significance Level. +{ + // A Students t test applied to two sets of data. + // We are testing the null hypothesis that the two + // samples have the same mean and + // that any difference is due to chance. + // See http://www.itl.nist.gov/div898/handbook/eda/section3/eda353.htm + // + using namespace std; + using boost::math::students_t; + + // Print header: + cout << + "_________________________________________________\n" + "Student t test for two samples (unequal variances)\n" + "_________________________________________________\n\n"; + cout << setprecision(5); + cout << setw(55) << left << "Number of Observations (Sample 1)" << "= " << Sn1 << "\n"; + cout << setw(55) << left << "Sample 1 Mean" << "= " << Sm1 << "\n"; + cout << setw(55) << left << "Sample 1 Standard Deviation" << "= " << Sd1 << "\n"; + cout << setw(55) << left << "Number of Observations (Sample 2)" << "= " << Sn2 << "\n"; + cout << setw(55) << left << "Sample 2 Mean" << "= " << Sm2 << "\n"; + cout << setw(55) << left << "Sample 2 Standard Deviation" << "= " << Sd2 << "\n"; + // + // Now we can calculate and output some stats: + // + // Degrees of freedom: + double v = Sd1 * Sd1 / Sn1 + Sd2 * Sd2 / Sn2; + v *= v; + double t1 = Sd1 * Sd1 / Sn1; + t1 *= t1; + t1 /= (Sn1 - 1); + double t2 = Sd2 * Sd2 / Sn2; + t2 *= t2; + t2 /= (Sn2 - 1); + v /= (t1 + t2); + cout << setw(55) << left << "Degrees of Freedom" << "= " << v << "\n"; + // t-statistic: + double t_stat = (Sm1 - Sm2) / sqrt(Sd1 * Sd1 / Sn1 + Sd2 * Sd2 / Sn2); + cout << setw(55) << left << "T Statistic" << "= " << t_stat << "\n"; + // + // Define our distribution, and get the probability: + // + students_t dist(v); + double q = cdf(complement(dist, fabs(t_stat))); + cout << setw(55) << left << "Probability that difference is due to chance" << "= " + << setprecision(3) << scientific << 2 * q << "\n\n"; + // + // Finally print out results of alternative hypothesis: + // + cout << setw(55) << left << + "Results for Alternative Hypothesis and alpha" << "= " + << setprecision(4) << fixed << alpha << "\n\n"; + cout << "Alternative Hypothesis Conclusion\n"; + cout << "Sample 1 Mean != Sample 2 Mean " ; + if(q < alpha / 2) + cout << "NOT REJECTED\n"; + else + cout << "REJECTED\n"; + cout << "Sample 1 Mean < Sample 2 Mean "; + if(cdf(dist, t_stat) < alpha) + cout << "NOT REJECTED\n"; + else + cout << "REJECTED\n"; + cout << "Sample 1 Mean > Sample 2 Mean "; + if(cdf(complement(dist, t_stat)) < alpha) + cout << "NOT REJECTED\n"; + else + cout << "REJECTED\n"; + cout << endl << endl; +} + +int main() +{ + // + // Run tests for Car Mileage sample data + // http://www.itl.nist.gov/div898/handbook/eda/section3/eda3531.htm + // from the NIST website http://www.itl.nist.gov. The data compares + // miles per gallon of US cars with miles per gallon of Japanese cars. + // + two_samples_t_test_equal_sd(20.14458, 6.414700, 249, 30.48101, 6.107710, 79, 0.05); + two_samples_t_test_unequal_sd(20.14458, 6.414700, 249, 30.48101, 6.107710, 79, 0.05); + + return 0; +} // int main() + +/* +Output is: + + _______________________________________________ + Student t test for two samples (equal variances) + _______________________________________________ + + Number of Observations (Sample 1) = 249 + Sample 1 Mean = 20.145 + Sample 1 Standard Deviation = 6.4147 + Number of Observations (Sample 2) = 79 + Sample 2 Mean = 30.481 + Sample 2 Standard Deviation = 6.1077 + Degrees of Freedom = 326 + Pooled Standard Deviation = 6.3426 + T Statistic = -12.621 + Probability that difference is due to chance = 5.273e-030 + + Results for Alternative Hypothesis and alpha = 0.0500 + + Alternative Hypothesis Conclusion + Sample 1 Mean != Sample 2 Mean NOT REJECTED + Sample 1 Mean < Sample 2 Mean NOT REJECTED + Sample 1 Mean > Sample 2 Mean REJECTED + + + _________________________________________________ + Student t test for two samples (unequal variances) + _________________________________________________ + + Number of Observations (Sample 1) = 249 + Sample 1 Mean = 20.14458 + Sample 1 Standard Deviation = 6.41470 + Number of Observations (Sample 2) = 79 + Sample 2 Mean = 30.48101 + Sample 2 Standard Deviation = 6.10771 + Degrees of Freedom = 136.87499 + T Statistic = -12.94627 + Probability that difference is due to chance = 1.571e-025 + + Results for Alternative Hypothesis and alpha = 0.0500 + + Alternative Hypothesis Conclusion + Sample 1 Mean != Sample 2 Mean NOT REJECTED + Sample 1 Mean < Sample 2 Mean NOT REJECTED + Sample 1 Mean > Sample 2 Mean REJECTED + + + +*/ + diff --git a/src/boost/libs/math/example/table_type.hpp b/src/boost/libs/math/example/table_type.hpp new file mode 100644 index 000000000..b8f16cfdf --- /dev/null +++ b/src/boost/libs/math/example/table_type.hpp @@ -0,0 +1,29 @@ +// Copyright John Maddock 2012. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_TEST_TABLE_TYPE_HPP +#define BOOST_MATH_TEST_TABLE_TYPE_HPP + +template <class T> +struct table_type +{ + typedef T type; +}; + +namespace boost{ namespace math{ namespace concepts{ + + class real_concept; + +}}} + +template <> +struct table_type<boost::math::concepts::real_concept> +{ + typedef long double type; +}; + +#endif diff --git a/src/boost/libs/math/example/test_cpp_float_close_fraction.cpp b/src/boost/libs/math/example/test_cpp_float_close_fraction.cpp new file mode 100644 index 000000000..b4699fad8 --- /dev/null +++ b/src/boost/libs/math/example/test_cpp_float_close_fraction.cpp @@ -0,0 +1,119 @@ +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Copyright Paul A. Bristow 2013 +// Copyright Christopher Kormanyos 2013. +// Copyright John Maddock 2013. + +#ifdef _MSC_VER +# pragma warning (disable : 4512) +# pragma warning (disable : 4996) +#endif + +#define BOOST_TEST_MAIN +#define BOOST_LIB_DIAGNOSTIC "on"// Show library file details. + +#include <boost/test/unit_test.hpp> +#include <boost/test/tools/floating_point_comparison.hpp> // Extra test tool for FP comparison. + +#include <iostream> +#include <limits> + +//[expression_template_1 + +#include <boost/multiprecision/cpp_dec_float.hpp> + +/*`To define a 50 decimal digit type using `cpp_dec_float`, +you must pass two template parameters to `boost::multiprecision::number`. + +It may be more legible to use a two-staged type definition such as this: + +`` +typedef boost::multiprecision::cpp_dec_float<50> mp_backend; +typedef boost::multiprecision::number<mp_backend, boost::multiprecision::et_off> cpp_dec_float_50_noet; +`` + +Here, we first define `mp_backend` as `cpp_dec_float` with 50 digits. +The second step passes this backend to `boost::multiprecision::number` +with `boost::multiprecision::et_off`, an enumerated type. + + typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<50>, boost::multiprecision::et_off> + cpp_dec_float_50_noet; + +You can reduce typing with a `using` directive `using namespace boost::multiprecision;` +if desired, as shown below. +*/ + +using namespace boost::multiprecision; + + +/*`Now `cpp_dec_float_50_noet` or `cpp_dec_float_50_et` +can be used as a direct replacement for built-in types like `double` etc. +*/ + +BOOST_AUTO_TEST_CASE(cpp_float_test_check_close_noet) +{ // No expression templates/ + typedef number<cpp_dec_float<50>, et_off> cpp_dec_float_50_noet; + + std::cout.precision(std::numeric_limits<cpp_dec_float_50_noet>::digits10); // All significant digits. + std::cout << std::showpoint << std::endl; // Show trailing zeros. + + cpp_dec_float_50_noet a ("1.0"); + cpp_dec_float_50_noet b ("1.0"); + b += std::numeric_limits<cpp_dec_float_50_noet>::epsilon(); // Increment least significant decimal digit. + + cpp_dec_float_50_noet eps = std::numeric_limits<cpp_dec_float_50_noet>::epsilon(); + + std::cout <<"a = " << a << ",\nb = " << b << ",\neps = " << eps << std::endl; + + BOOST_CHECK_CLOSE(a, b, eps * 100); // Expected to pass (because tolerance is as percent). + BOOST_CHECK_CLOSE_FRACTION(a, b, eps); // Expected to pass (because tolerance is as fraction). + + + +} // BOOST_AUTO_TEST_CASE(cpp_float_test_check_close) + +BOOST_AUTO_TEST_CASE(cpp_float_test_check_close_et) +{ // Using expression templates. + typedef number<cpp_dec_float<50>, et_on> cpp_dec_float_50_et; + + std::cout.precision(std::numeric_limits<cpp_dec_float_50_et>::digits10); // All significant digits. + std::cout << std::showpoint << std::endl; // Show trailing zeros. + + cpp_dec_float_50_et a("1.0"); + cpp_dec_float_50_et b("1.0"); + b += std::numeric_limits<cpp_dec_float_50_et>::epsilon(); // Increment least significant decimal digit. + + cpp_dec_float_50_et eps = std::numeric_limits<cpp_dec_float_50_et>::epsilon(); + + std::cout << "a = " << a << ",\nb = " << b << ",\neps = " << eps << std::endl; + + BOOST_CHECK_CLOSE(a, b, eps * 100); // Expected to pass (because tolerance is as percent). + BOOST_CHECK_CLOSE_FRACTION(a, b, eps); // Expected to pass (because tolerance is as fraction). + + /*`Using `cpp_dec_float_50` with the default expression template use switched on, + the compiler error message for `BOOST_CHECK_CLOSE_FRACTION(a, b, eps); would be: + */ + // failure floating_point_comparison.hpp(59): error C2440: 'static_cast' : + // cannot convert from 'int' to 'boost::multiprecision::detail::expression<tag,Arg1,Arg2,Arg3,Arg4>' +//] [/expression_template_1] + +} // BOOST_AUTO_TEST_CASE(cpp_float_test_check_close) + +/* + +Output: + + Description: Autorun "J:\Cpp\big_number\Debug\test_cpp_float_close_fraction.exe" + Running 1 test case... + + a = 1.0000000000000000000000000000000000000000000000000, + b = 1.0000000000000000000000000000000000000000000000001, + eps = 1.0000000000000000000000000000000000000000000000000e-49 + + *** No errors detected + + +*/ + diff --git a/src/boost/libs/math/example/test_nonfinite_loopback.cpp b/src/boost/libs/math/example/test_nonfinite_loopback.cpp new file mode 100644 index 000000000..c7b8e4204 --- /dev/null +++ b/src/boost/libs/math/example/test_nonfinite_loopback.cpp @@ -0,0 +1,97 @@ +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Copyright (c) 2006 Johan Rade +// Copyright (c) 2011 Paul A. Bristow + +/*! +\file +\brief Basic tests of native nonfinite loopback. + +\detail Basic loopback test outputs using the platforms built-in facets +and reads back in, and checks if loopback OK. + +Using MSVC this doesn't work OK: +input produces just "1" instead of "1.#QNAN", 1.#SNAN" or 1.#IND"! + +*/ + +#include <iostream> +using std::cout; +using std::endl; +#include <locale> +using std::locale; +#include <string> +using std::string; +#include <sstream> + using std::stringstream; +#include <limits> +using std::numeric_limits; + +int main() +{ + locale default_locale; // Current global locale. + // Try to use the default locale first. + // On MSVC this doesn't work. + + { // Try infinity. + stringstream ss; // Both input and output. + ss.imbue(default_locale); // Redundant, of course. + string infs; + if(numeric_limits<double>::has_infinity) + { // Make sure infinity is specialised for type double. + double inf = numeric_limits<double>::infinity(); + ss << inf; // Output infinity. + infs = ss.str(); // + } + else + { // Need to provide a suitable string for infinity. + infs = "1.#INF"; // Might suit MSVC? + ss << infs; + } + double r; + ss >> r; // Read back in. + + cout << "infinity output was " << infs << endl; // "1.#INF" + cout << "infinity input was " << r << endl; // "1" + } + + { // Try Quiet NaN + stringstream ss; // Both input and output. + ss.imbue(default_locale); // Redundant, of course. + string infs; + if(numeric_limits<double>::has_quiet_NaN) + { // Make sure quiet NaN is specialised for type double. + double qnan = numeric_limits<double>::quiet_NaN(); + ss << qnan; // Output quiet_NaN. + infs = ss.str(); // + } + else + { // Need to provide a suitable string for quiet_NAN. + infs = "1.#QNAN"; + ss << infs; + } + double r; + ss >> r; // Read back in. + + cout << "quiet_NaN output was " << infs << endl; // "1.#QNAN" + cout << "quiet_NaN input was " << r << endl; // "1#" + } + + +} // int main() + +/* + +Output (MSVC Version 10.0): + + + infinity output was 1.#INF + infinity input was 1 + quiet_NaN output was 1.#QNAN + quiet_NaN input was 1 + + +*/ + diff --git a/src/boost/libs/math/example/trapezoidal_example.cpp b/src/boost/libs/math/example/trapezoidal_example.cpp new file mode 100644 index 000000000..bbea64152 --- /dev/null +++ b/src/boost/libs/math/example/trapezoidal_example.cpp @@ -0,0 +1,29 @@ +/* + * Copyright Nick Thompson, 2017 + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + * This example shows to to numerically integrate a periodic function using the adaptive_trapezoidal routine provided by boost. + */ + +#include <iostream> +#include <cmath> +#include <limits> +#include <boost/math/quadrature/trapezoidal.hpp> + +int main() +{ + using boost::math::constants::two_pi; + using boost::math::constants::third; + using boost::math::quadrature::trapezoidal; + // This function has an analytic form for its integral over a period: 2pi/3. + auto f = [](double x) { return 1/(5 - 4*cos(x)); }; + + double Q = trapezoidal(f, (double) 0, two_pi<double>()); + + std::cout << std::setprecision(std::numeric_limits<double>::digits10); + std::cout << "The adaptive trapezoidal rule gives the integral of our function as " << Q << "\n"; + std::cout << "The exact result is " << two_pi<double>()*third<double>() << "\n"; + +} |