diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
commit | 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch) | |
tree | e5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/boost/libs/multiprecision/example | |
parent | Initial commit. (diff) | |
download | ceph-upstream.tar.xz ceph-upstream.zip |
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/multiprecision/example')
28 files changed, 5080 insertions, 0 deletions
diff --git a/src/boost/libs/multiprecision/example/Jamfile.v2 b/src/boost/libs/multiprecision/example/Jamfile.v2 new file mode 100644 index 00000000..0e09c848 --- /dev/null +++ b/src/boost/libs/multiprecision/example/Jamfile.v2 @@ -0,0 +1,112 @@ +# \libs\math\example\jamfile.v2 +# Runs multiprecision examples. +# Copyright 2014 John Maddock +# Copyright Paul A. Bristow 2014. +# Copyright Christpher Kormanyos 2014 + +# 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 modules ; +import path ; +import ../../config/checks/config : requires ; + +local ntl-path = [ modules.peek : NTL_PATH ] ; +local gmp_path = [ modules.peek : GMP_PATH ] ; +local mpfr_path = [ modules.peek : MPFR_PATH ] ; +local mpfi_path = [ modules.peek : MPFI_PATH ] ; +local tommath_path = [ modules.peek : TOMMATH_PATH ] ; + +project + : requirements + <include>$(gmp_path) + <include>$(gmp_path)/mpfr + <include>$(gmp_path)/gmpfrxx + <include>$(mpfr_path) + <include>$(mpfi_path) + <include>$(mpfi_path)/src + <include>$(tommath_path) + <include>../include + <include>../../.. + + <toolset>gcc:<cxxflags>-Wno-missing-braces + + # Assembler error "File too big" caused by lots of C++ templates, for example, math/floating_point_examples.cpp. + # Some projects on some toolsets may require + # <toolset>gcc-mingw:<cxxflags>\"-Wa,-mbig-obj\" + # See https://digitalkarabela.com/mingw-w64-how-to-fix-file-too-big-too-many-sections/ + # <toolset>gcc-mingw:<cxxflags>-Wa,-mbig-obj # Some projects may overflow assembler and require equivalent of MSVC /bigobj. + # Requires version 2.30 of GNU binutils. + # Best applied only to projects that require this, see run math/floating_point_examples.cpp below. + + <toolset>darwin:<cxxflags>-Wno-missing-braces + <toolset>acc:<cxxflags>+W2068,2461,2236,4070 + <toolset>intel:<cxxflags>-Qwd264,239 + <toolset>msvc:<runtime-link>static + <toolset>msvc:<link>static + <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 + ; + +lib gmp : : <search>$(gmp_path) ; +lib mpfr : : <search>$(gmp_path) <search>$(mpfr_path) <search>$(mpfr_path)/build.vc10/lib/Win32/Debug ; +lib mpfi : : <search>$(gmp_path) <search>$(mpfr_path) <search>$(mpfr_path)/build.vc10/lib/Win32/Debug <search>$(mpfi_path) <search>$(mpfi_path)/src ; +lib quadmath ; + +if $(tommath_path) +{ + lib tommath : [ GLOB $(tommath_path) : *.c ] ; + TOMMATH = tommath ; +} +else +{ + lib tommath : : <search>$(tommath_path) ; + TOMMATH = tommath ; +} + +lib no_eh_eg_support : ../test/no_eh_test_support.cpp ; + +test-suite examples : + + [ run cpp_int_snips.cpp no_eh_eg_support ] + [ run cpp_int_import_export.cpp no_eh_eg_support ] + [ run cpp_bin_float_import_export.cpp no_eh_eg_support ] + + [ run cpp_dec_float_snips.cpp no_eh_eg_support ] + + [ run cpp_bin_float_snips.cpp no_eh_eg_support ] + + [ run debug_adaptor_snips.cpp no_eh_eg_support ] + [ run float128_snips.cpp quadmath no_eh_eg_support : : : [ check-target-builds ../config//has_float128 : : <build>no ] ] + + [ run floating_point_examples.cpp no_eh_eg_support : : : <toolset>gcc-mingw:<cxxflags>-Wa,-mbig-obj ] # See note above. + [ run gauss_laguerre_quadrature.cpp no_eh_eg_support : : : release [ requires cxx11_lambdas ] ] + [ run hypergeometric_luke_algorithms.cpp no_eh_eg_support ../../chrono/build//boost_chrono ../../system/build//boost_system : : : [ requires cxx11_nullptr ] ] + [ run integer_examples.cpp no_eh_eg_support ] + [ run logged_adaptor.cpp no_eh_eg_support mpfi mpfr gmp : : : [ check-target-builds ../config//has_mpfi : : <build>no ] ] + [ run mixed_integer_arithmetic.cpp no_eh_eg_support ] + [ run numeric_limits_snips.cpp no_eh_eg_support /boost//test_exec_monitor : : : [ requires cxx11_numeric_limits ] [ check-target-builds ../config//has_float128 : <source>quadmath ] ] + [ run random_snips.cpp gmp no_eh_eg_support : : : [ requires cxx11_explicit_conversion_operators ] [ check-target-builds ../config//has_gmp : : <build>no ] ] + [ run safe_prime.cpp no_eh_eg_support ] + + [ run gmp_snips.cpp gmp no_eh_eg_support : : : [ check-target-builds ../config//has_gmp : : <build>no ] ] + [ run mpfi_snips.cpp mpfi mpfr gmp no_eh_eg_support : : : [ check-target-builds ../config//has_mpfi : : <build>no ] ] + [ run mpfr_snips.cpp mpfr gmp no_eh_eg_support : : : [ check-target-builds ../config//has_mpfr : : <build>no ] ] + [ run tommath_snips.cpp $(TOMMATH) no_eh_eg_support : : : [ check-target-builds ../config//has_tommath : : <build>no ] ] + [ compile constexpr_float_arithmetic_examples.cpp : [ requires cxx14_constexpr cxx17_if_constexpr ] ] + +; diff --git a/src/boost/libs/multiprecision/example/complex128_examples.cpp b/src/boost/libs/multiprecision/example/complex128_examples.cpp new file mode 100644 index 00000000..49f57d18 --- /dev/null +++ b/src/boost/libs/multiprecision/example/complex128_examples.cpp @@ -0,0 +1,120 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2018 Nick Thompson. 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 + +/*`This example demonstrates the usage of the MPC backend for multiprecision complex numbers. +In the following, we will show how using MPC backend allows for the same operations as the C++ standard library complex numbers. +*/ + +//[complex128_eg +#include <iostream> +#include <complex> +#include <boost/multiprecision/complex128.hpp> + +template<class Complex> +void complex_number_examples() +{ + Complex z1{0, 1}; + std::cout << std::setprecision(std::numeric_limits<typename Complex::value_type>::digits10); + std::cout << std::scientific << std::fixed; + std::cout << "Print a complex number: " << z1 << std::endl; + std::cout << "Square it : " << z1*z1 << std::endl; + std::cout << "Real part : " << z1.real() << " = " << real(z1) << std::endl; + std::cout << "Imaginary part : " << z1.imag() << " = " << imag(z1) << std::endl; + using std::abs; + std::cout << "Absolute value : " << abs(z1) << std::endl; + std::cout << "Argument : " << arg(z1) << std::endl; + std::cout << "Norm : " << norm(z1) << std::endl; + std::cout << "Complex conjugate : " << conj(z1) << std::endl; + std::cout << "Projection onto Riemann sphere: " << proj(z1) << std::endl; + typename Complex::value_type r = 1; + typename Complex::value_type theta = 0.8; + using std::polar; + std::cout << "Polar coordinates (phase = 0) : " << polar(r) << std::endl; + std::cout << "Polar coordinates (phase !=0) : " << polar(r, theta) << std::endl; + + std::cout << "\nElementary special functions:\n"; + using std::exp; + std::cout << "exp(z1) = " << exp(z1) << std::endl; + using std::log; + std::cout << "log(z1) = " << log(z1) << std::endl; + using std::log10; + std::cout << "log10(z1) = " << log10(z1) << std::endl; + using std::pow; + std::cout << "pow(z1, z1) = " << pow(z1, z1) << std::endl; + using std::sqrt; + std::cout << "Take its square root : " << sqrt(z1) << std::endl; + using std::sin; + std::cout << "sin(z1) = " << sin(z1) << std::endl; + using std::cos; + std::cout << "cos(z1) = " << cos(z1) << std::endl; + using std::tan; + std::cout << "tan(z1) = " << tan(z1) << std::endl; + using std::asin; + std::cout << "asin(z1) = " << asin(z1) << std::endl; + using std::acos; + std::cout << "acos(z1) = " << acos(z1) << std::endl; + using std::atan; + std::cout << "atan(z1) = " << atan(z1) << std::endl; + using std::sinh; + std::cout << "sinh(z1) = " << sinh(z1) << std::endl; + using std::cosh; + std::cout << "cosh(z1) = " << cosh(z1) << std::endl; + using std::tanh; + std::cout << "tanh(z1) = " << tanh(z1) << std::endl; + using std::asinh; + std::cout << "asinh(z1) = " << asinh(z1) << std::endl; + using std::acosh; + std::cout << "acosh(z1) = " << acosh(z1) << std::endl; + using std::atanh; + std::cout << "atanh(z1) = " << atanh(z1) << std::endl; +} + +int main() +{ + std::cout << "First, some operations we usually perform with std::complex:\n"; + complex_number_examples<std::complex<double>>(); + std::cout << "\nNow the same operations performed using quad precision complex numbers:\n"; + complex_number_examples<boost::multiprecision::complex128>(); + + return 0; +} +//] + +/* + +//[complex128_out + +Print a complex number: (0.000000000000000000000000000000000,1.000000000000000000000000000000000) +Square it : -1.000000000000000000000000000000000 +Real part : 0.000000000000000000000000000000000 = 0.000000000000000000000000000000000 +Imaginary part : 1.000000000000000000000000000000000 = 1.000000000000000000000000000000000 +Absolute value : 1.000000000000000000000000000000000 +Argument : 1.570796326794896619231321691639751 +Norm : 1.000000000000000000000000000000000 +Complex conjugate : (0.000000000000000000000000000000000,-1.000000000000000000000000000000000) +Projection onto Riemann sphere: (0.000000000000000000000000000000000,1.000000000000000000000000000000000) +Polar coordinates (phase = 0) : 1.000000000000000000000000000000000 +Polar coordinates (phase !=0) : (0.696706709347165389063740022772449,0.717356090899522792567167815703377) + +Elementary special functions: +exp(z1) = (0.540302305868139717400936607442977,0.841470984807896506652502321630299) +log(z1) = (0.000000000000000000000000000000000,1.570796326794896619231321691639751) +log10(z1) = (0.000000000000000000000000000000000,0.682188176920920673742891812715678) +pow(z1, z1) = 0.207879576350761908546955619834979 +Take its square root : (0.707106781186547524400844362104849,0.707106781186547524400844362104849) +sin(z1) = (0.000000000000000000000000000000000,1.175201193643801456882381850595601) +cos(z1) = 1.543080634815243778477905620757061 +tan(z1) = (0.000000000000000000000000000000000,0.761594155955764888119458282604794) +asin(z1) = (0.000000000000000000000000000000000,0.881373587019543025232609324979792) +acos(z1) = (1.570796326794896619231321691639751,-0.881373587019543025232609324979792) +atan(z1) = (0.000000000000000000000000000000000,inf) +sinh(z1) = (0.000000000000000000000000000000000,0.841470984807896506652502321630299) +cosh(z1) = 0.540302305868139717400936607442977 +tanh(z1) = (0.000000000000000000000000000000000,1.557407724654902230506974807458360) +asinh(z1) = (0.000000000000000000000000000000000,1.570796326794896619231321691639751) +acosh(z1) = (0.881373587019543025232609324979792,1.570796326794896619231321691639751) +atanh(z1) = (0.000000000000000000000000000000000,0.785398163397448309615660845819876) +//] +*/ diff --git a/src/boost/libs/multiprecision/example/constexpr_float_arithmetic_examples.cpp b/src/boost/libs/multiprecision/example/constexpr_float_arithmetic_examples.cpp new file mode 100644 index 00000000..ef2c4579 --- /dev/null +++ b/src/boost/libs/multiprecision/example/constexpr_float_arithmetic_examples.cpp @@ -0,0 +1,374 @@ +// (C) Copyright John Maddock 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) + +#include <iostream> +#include <boost/math/constants/constants.hpp> +#ifdef BOOST_HAS_FLOAT128 +#include <boost/multiprecision/float128.hpp> +#endif + +//[constexpr_circle + +template <class T> +inline constexpr T circumference(T radius) +{ + return 2 * boost::math::constants::pi<T>() * radius; +} + +template <class T> +inline constexpr T area(T radius) +{ + return boost::math::constants::pi<T>() * radius * radius; +} +//] + +template <class T, unsigned Order> +struct const_polynomial +{ + public: + T data[Order + 1]; + + public: + constexpr const_polynomial(T val = 0) : data{val} {} + constexpr const_polynomial(const std::initializer_list<T>& init) : data{} + { + if (init.size() > Order + 1) + throw std::range_error("Too many initializers in list"); + for (unsigned i = 0; i < init.size(); ++i) + data[i] = init.begin()[i]; + } + constexpr T& operator[](std::size_t N) + { + return data[N]; + } + constexpr const T& operator[](std::size_t N) const + { + return data[N]; + } + template <class U> + constexpr T operator()(U val)const + { + T result = data[Order]; + for (unsigned i = Order; i > 0; --i) + { + result *= val; + result += data[i - 1]; + } + return result; + } + constexpr const_polynomial<T, Order - 1> derivative() const + { + const_polynomial<T, Order - 1> result; + for (unsigned i = 1; i <= Order; ++i) + { + result[i - 1] = (*this)[i] * i; + } + return result; + } + constexpr const_polynomial operator-() + { + const_polynomial t(*this); + for (unsigned i = 0; i <= Order; ++i) + t[i] = -t[i]; + return t; + } + template <class U> + constexpr const_polynomial& operator*=(U val) + { + for (unsigned i = 0; i <= Order; ++i) + data[i] = data[i] * val; + return *this; + } + template <class U> + constexpr const_polynomial& operator/=(U val) + { + for (unsigned i = 0; i <= Order; ++i) + data[i] = data[i] / val; + return *this; + } + template <class U> + constexpr const_polynomial& operator+=(U val) + { + data[0] += val; + return *this; + } + template <class U> + constexpr const_polynomial& operator-=(U val) + { + data[0] -= val; + return *this; + } +}; + +template <class T, unsigned Order1, unsigned Order2> +inline constexpr const_polynomial<T, (Order1 > Order2 ? Order1 : Order2)> operator+(const const_polynomial<T, Order1>& a, const const_polynomial<T, Order2>& b) +{ + if + constexpr(Order1 > Order2) + { + const_polynomial<T, Order1> result(a); + for (unsigned i = 0; i <= Order2; ++i) + result[i] += b[i]; + return result; + } + else + { + const_polynomial<T, Order2> result(b); + for (unsigned i = 0; i <= Order1; ++i) + result[i] += a[i]; + return result; + } +} +template <class T, unsigned Order1, unsigned Order2> +inline constexpr const_polynomial<T, (Order1 > Order2 ? Order1 : Order2)> operator-(const const_polynomial<T, Order1>& a, const const_polynomial<T, Order2>& b) +{ + if + constexpr(Order1 > Order2) + { + const_polynomial<T, Order1> result(a); + for (unsigned i = 0; i <= Order2; ++i) + result[i] -= b[i]; + return result; + } + else + { + const_polynomial<T, Order2> result(b); + for (unsigned i = 0; i <= Order1; ++i) + result[i] = a[i] - b[i]; + return result; + } +} +template <class T, unsigned Order1, unsigned Order2> +inline constexpr const_polynomial<T, Order1 + Order2> operator*(const const_polynomial<T, Order1>& a, const const_polynomial<T, Order2>& b) +{ + const_polynomial<T, Order1 + Order2> result; + for (unsigned i = 0; i <= Order1; ++i) + { + for (unsigned j = 0; j <= Order2; ++j) + { + result[i + j] += a[i] * b[j]; + } + } + return result; +} +template <class T, unsigned Order, class U> +inline constexpr const_polynomial<T, Order> operator*(const const_polynomial<T, Order>& a, const U& b) +{ + const_polynomial<T, Order> result(a); + for (unsigned i = 0; i <= Order; ++i) + { + result[i] *= b; + } + return result; +} +template <class U, class T, unsigned Order> +inline constexpr const_polynomial<T, Order> operator*(const U& b, const const_polynomial<T, Order>& a) +{ + const_polynomial<T, Order> result(a); + for (unsigned i = 0; i <= Order; ++i) + { + result[i] *= b; + } + return result; +} +template <class T, unsigned Order, class U> +inline constexpr const_polynomial<T, Order> operator/(const const_polynomial<T, Order>& a, const U& b) +{ + const_polynomial<T, Order> result; + for (unsigned i = 0; i <= Order; ++i) + { + result[i] /= b; + } + return result; +} + +//[hermite_example +template <class T, unsigned Order> +class hermite_polynomial +{ + const_polynomial<T, Order> m_data; + + public: + constexpr hermite_polynomial() : m_data(hermite_polynomial<T, Order - 1>().data() * const_polynomial<T, 1>{0, 2} - hermite_polynomial<T, Order - 1>().data().derivative()) + { + } + constexpr const const_polynomial<T, Order>& data() const + { + return m_data; + } + constexpr const T& operator[](std::size_t N)const + { + return m_data[N]; + } + template <class U> + constexpr T operator()(U val)const + { + return m_data(val); + } +}; +//] +//[hermite_example2 +template <class T> +class hermite_polynomial<T, 0> +{ + const_polynomial<T, 0> m_data; + + public: + constexpr hermite_polynomial() : m_data{1} {} + constexpr const const_polynomial<T, 0>& data() const + { + return m_data; + } + constexpr const T& operator[](std::size_t N) const + { + return m_data[N]; + } + template <class U> + constexpr T operator()(U val) + { + return m_data(val); + } +}; + +template <class T> +class hermite_polynomial<T, 1> +{ + const_polynomial<T, 1> m_data; + + public: + constexpr hermite_polynomial() : m_data{0, 2} {} + constexpr const const_polynomial<T, 1>& data() const + { + return m_data; + } + constexpr const T& operator[](std::size_t N) const + { + return m_data[N]; + } + template <class U> + constexpr T operator()(U val) + { + return m_data(val); + } +}; +//] + +void test_double() +{ + constexpr double radius = 2.25; + constexpr double c = circumference(radius); + constexpr double a = area(radius); + + std::cout << "Circumference = " << c << std::endl; + std::cout << "Area = " << a << std::endl; + + constexpr const_polynomial<double, 2> pa = {3, 4}; + constexpr const_polynomial<double, 2> pb = {5, 6}; + static_assert(pa[0] == 3); + static_assert(pa[1] == 4); + constexpr auto pc = pa * 2; + static_assert(pc[0] == 6); + static_assert(pc[1] == 8); + constexpr auto pd = 3 * pa; + static_assert(pd[0] == 3 * 3); + static_assert(pd[1] == 4 * 3); + constexpr auto pe = pa + pb; + static_assert(pe[0] == 3 + 5); + static_assert(pe[1] == 4 + 6); + constexpr auto pf = pa - pb; + static_assert(pf[0] == 3 - 5); + static_assert(pf[1] == 4 - 6); + constexpr auto pg = pa * pb; + static_assert(pg[0] == 15); + static_assert(pg[1] == 38); + static_assert(pg[2] == 24); + + constexpr hermite_polynomial<double, 2> h1; + static_assert(h1[0] == -2); + static_assert(h1[1] == 0); + static_assert(h1[2] == 4); + + constexpr hermite_polynomial<double, 3> h3; + static_assert(h3[0] == 0); + static_assert(h3[1] == -12); + static_assert(h3[2] == 0); + static_assert(h3[3] == 8); + + constexpr hermite_polynomial<double, 9> h9; + static_assert(h9[0] == 0); + static_assert(h9[1] == 30240); + static_assert(h9[2] == 0); + static_assert(h9[3] == -80640); + static_assert(h9[4] == 0); + static_assert(h9[5] == 48384); + static_assert(h9[6] == 0); + static_assert(h9[7] == -9216); + static_assert(h9[8] == 0); + static_assert(h9[9] == 512); + + static_assert(h9(0.5) == 6481); + +} + +void test_float128() +{ +#ifdef BOOST_HAS_FLOAT128 + //[constexpr_circle_usage + + using boost::multiprecision::float128; + + constexpr float128 radius = 2.25; + constexpr float128 c = circumference(radius); + constexpr float128 a = area(radius); + + std::cout << "Circumference = " << c << std::endl; + std::cout << "Area = " << a << std::endl; + + //] + + constexpr hermite_polynomial<float128, 2> h1; + static_assert(h1[0] == -2); + static_assert(h1[1] == 0); + static_assert(h1[2] == 4); + + constexpr hermite_polynomial<float128, 3> h3; + static_assert(h3[0] == 0); + static_assert(h3[1] == -12); + static_assert(h3[2] == 0); + static_assert(h3[3] == 8); + + //[hermite_example3 + constexpr hermite_polynomial<float128, 9> h9; + // + // Verify that the polynomial's coefficients match the known values: + // + static_assert(h9[0] == 0); + static_assert(h9[1] == 30240); + static_assert(h9[2] == 0); + static_assert(h9[3] == -80640); + static_assert(h9[4] == 0); + static_assert(h9[5] == 48384); + static_assert(h9[6] == 0); + static_assert(h9[7] == -9216); + static_assert(h9[8] == 0); + static_assert(h9[9] == 512); + // + // Define an abscissa value to evaluate at: + // + constexpr float128 abscissa(0.5); + // + // Evaluate H_9(0.5) using all constexpr arithmetic: + // + static_assert(h9(abscissa) == 6481); + //] +#endif +} + +int main() +{ + test_double(); + test_float128(); + std::cout << "Done!" << std::endl; +} diff --git a/src/boost/libs/multiprecision/example/cpp_bin_float_import_export.cpp b/src/boost/libs/multiprecision/example/cpp_bin_float_import_export.cpp new file mode 100644 index 00000000..3c9bc143 --- /dev/null +++ b/src/boost/libs/multiprecision/example/cpp_bin_float_import_export.cpp @@ -0,0 +1,49 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2015 John Maddock. 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/multiprecision/cpp_bin_float.hpp> +#include <iostream> +#include <iomanip> +#include <vector> +#include <iterator> + +// Contains Quickbook snippets in comments. + +//[IE2 + +/*` +Importing or exporting cpp_bin_float is similar, but we must procede via an intermediate integer: +*/ +/*= +#include <boost/multiprecision/cpp_bin_float.hpp> +#include <iostream> +#include <iomanip> +#include <vector> +#include <iterator> +*/ + +int main() +{ + using boost::multiprecision::cpp_bin_float_100; + using boost::multiprecision::cpp_int; + // Create a cpp_bin_float to import/export: + cpp_bin_float_100 f(1); + f /= 3; + // export into 8-bit unsigned values, most significant bit first: + std::vector<unsigned char> v; + export_bits(cpp_int(f.backend().bits()), std::back_inserter(v), 8); + // Grab the exponent as well: + int e = f.backend().exponent(); + // Import back again, and check for equality, we have to procede via + // an intermediate integer: + cpp_int i; + import_bits(i, v.begin(), v.end()); + cpp_bin_float_100 g(i); + g.backend().exponent() = e; + BOOST_ASSERT(f == g); +} + +//] + diff --git a/src/boost/libs/multiprecision/example/cpp_bin_float_snips.cpp b/src/boost/libs/multiprecision/example/cpp_bin_float_snips.cpp new file mode 100644 index 00000000..ac378e05 --- /dev/null +++ b/src/boost/libs/multiprecision/example/cpp_bin_float_snips.cpp @@ -0,0 +1,32 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2013 John Maddock. 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 + +//[cpp_bin_float_eg +#include <boost/multiprecision/cpp_bin_float.hpp> +#include <boost/math/special_functions/gamma.hpp> +#include <iostream> + +int main() +{ + using namespace boost::multiprecision; + + // Operations at fixed precision and full numeric_limits support: + cpp_bin_float_100 b = 2; + std::cout << std::numeric_limits<cpp_bin_float_100>::digits << std::endl; + std::cout << std::numeric_limits<cpp_bin_float_100>::digits10 << std::endl; + // We can use any C++ std lib function, lets print all the digits as well: + std::cout << std::setprecision(std::numeric_limits<cpp_bin_float_100>::max_digits10) + << log(b) << std::endl; // print log(2) + // We can also use any function from Boost.Math: + std::cout << boost::math::tgamma(b) << std::endl; + // These even work when the argument is an expression template: + std::cout << boost::math::tgamma(b * b) << std::endl; + // And since we have an extended exponent range we can generate some really large + // numbers here (4.0238726007709377354370243e+2564): + std::cout << boost::math::tgamma(cpp_bin_float_100(1000)) << std::endl; + return 0; +} + +//] diff --git a/src/boost/libs/multiprecision/example/cpp_complex_examples.cpp b/src/boost/libs/multiprecision/example/cpp_complex_examples.cpp new file mode 100644 index 00000000..7d00cc73 --- /dev/null +++ b/src/boost/libs/multiprecision/example/cpp_complex_examples.cpp @@ -0,0 +1,120 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2018 Nick Thompson. 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 + +/*`This example demonstrates the usage of the MPC backend for multiprecision complex numbers. +In the following, we will show how using MPC backend allows for the same operations as the C++ standard library complex numbers. +*/ + +//[cpp_complex_eg +#include <iostream> +#include <complex> +#include <boost/multiprecision/cpp_complex.hpp> + +template<class Complex> +void complex_number_examples() +{ + Complex z1{0, 1}; + std::cout << std::setprecision(std::numeric_limits<typename Complex::value_type>::digits10); + std::cout << std::scientific << std::fixed; + std::cout << "Print a complex number: " << z1 << std::endl; + std::cout << "Square it : " << z1*z1 << std::endl; + std::cout << "Real part : " << z1.real() << " = " << real(z1) << std::endl; + std::cout << "Imaginary part : " << z1.imag() << " = " << imag(z1) << std::endl; + using std::abs; + std::cout << "Absolute value : " << abs(z1) << std::endl; + std::cout << "Argument : " << arg(z1) << std::endl; + std::cout << "Norm : " << norm(z1) << std::endl; + std::cout << "Complex conjugate : " << conj(z1) << std::endl; + std::cout << "Projection onto Riemann sphere: " << proj(z1) << std::endl; + typename Complex::value_type r = 1; + typename Complex::value_type theta = 0.8; + using std::polar; + std::cout << "Polar coordinates (phase = 0) : " << polar(r) << std::endl; + std::cout << "Polar coordinates (phase !=0) : " << polar(r, theta) << std::endl; + + std::cout << "\nElementary special functions:\n"; + using std::exp; + std::cout << "exp(z1) = " << exp(z1) << std::endl; + using std::log; + std::cout << "log(z1) = " << log(z1) << std::endl; + using std::log10; + std::cout << "log10(z1) = " << log10(z1) << std::endl; + using std::pow; + std::cout << "pow(z1, z1) = " << pow(z1, z1) << std::endl; + using std::sqrt; + std::cout << "Take its square root : " << sqrt(z1) << std::endl; + using std::sin; + std::cout << "sin(z1) = " << sin(z1) << std::endl; + using std::cos; + std::cout << "cos(z1) = " << cos(z1) << std::endl; + using std::tan; + std::cout << "tan(z1) = " << tan(z1) << std::endl; + using std::asin; + std::cout << "asin(z1) = " << asin(z1) << std::endl; + using std::acos; + std::cout << "acos(z1) = " << acos(z1) << std::endl; + using std::atan; + std::cout << "atan(z1) = " << atan(z1) << std::endl; + using std::sinh; + std::cout << "sinh(z1) = " << sinh(z1) << std::endl; + using std::cosh; + std::cout << "cosh(z1) = " << cosh(z1) << std::endl; + using std::tanh; + std::cout << "tanh(z1) = " << tanh(z1) << std::endl; + using std::asinh; + std::cout << "asinh(z1) = " << asinh(z1) << std::endl; + using std::acosh; + std::cout << "acosh(z1) = " << acosh(z1) << std::endl; + using std::atanh; + std::cout << "atanh(z1) = " << atanh(z1) << std::endl; +} + +int main() +{ + std::cout << "First, some operations we usually perform with std::complex:\n"; + complex_number_examples<std::complex<double>>(); + std::cout << "\nNow the same operations performed using quad precision complex numbers:\n"; + complex_number_examples<boost::multiprecision::cpp_complex_quad>(); + + return 0; +} +//] + +/* + +//[cpp_complex_out + +Print a complex number: (0.000000000000000000000000000000000,1.000000000000000000000000000000000) +Square it : -1.000000000000000000000000000000000 +Real part : 0.000000000000000000000000000000000 = 0.000000000000000000000000000000000 +Imaginary part : 1.000000000000000000000000000000000 = 1.000000000000000000000000000000000 +Absolute value : 1.000000000000000000000000000000000 +Argument : 1.570796326794896619231321691639751 +Norm : 1.000000000000000000000000000000000 +Complex conjugate : (0.000000000000000000000000000000000,-1.000000000000000000000000000000000) +Projection onto Riemann sphere: (0.000000000000000000000000000000000,1.000000000000000000000000000000000) +Polar coordinates (phase = 0) : 1.000000000000000000000000000000000 +Polar coordinates (phase !=0) : (0.696706709347165389063740022772448,0.717356090899522792567167815703377) + +Elementary special functions: +exp(z1) = (0.540302305868139717400936607442977,0.841470984807896506652502321630299) +log(z1) = (0.000000000000000000000000000000000,1.570796326794896619231321691639751) +log10(z1) = (0.000000000000000000000000000000000,0.682188176920920673742891812715678) +pow(z1, z1) = 0.207879576350761908546955619834979 +Take its square root : (0.707106781186547524400844362104849,0.707106781186547524400844362104849) +sin(z1) = (0.000000000000000000000000000000000,1.175201193643801456882381850595601) +cos(z1) = 1.543080634815243778477905620757062 +tan(z1) = (0.000000000000000000000000000000000,0.761594155955764888119458282604794) +asin(z1) = (0.000000000000000000000000000000000,0.881373587019543025232609324979793) +acos(z1) = (1.570796326794896619231321691639751,-0.881373587019543025232609324979793) +atan(z1) = (0.000000000000000000000000000000000,inf) +sinh(z1) = (0.000000000000000000000000000000000,0.841470984807896506652502321630299) +cosh(z1) = 0.540302305868139717400936607442977 +tanh(z1) = (0.000000000000000000000000000000000,1.557407724654902230506974807458360) +asinh(z1) = (0.000000000000000000000000000000000,1.570796326794896619231321691639751) +acosh(z1) = (0.881373587019543025232609324979792,1.570796326794896619231321691639751) +atanh(z1) = (0.000000000000000000000000000000000,0.785398163397448309615660845819876) +//] +*/ diff --git a/src/boost/libs/multiprecision/example/cpp_dec_float_snips.cpp b/src/boost/libs/multiprecision/example/cpp_dec_float_snips.cpp new file mode 100644 index 00000000..4bbd89f9 --- /dev/null +++ b/src/boost/libs/multiprecision/example/cpp_dec_float_snips.cpp @@ -0,0 +1,33 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2011 John Maddock. 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 + + //[cpp_dec_float_eg +#include <boost/multiprecision/cpp_dec_float.hpp> +#include <boost/math/special_functions/gamma.hpp> +#include <iostream> + +int main() +{ + using namespace boost::multiprecision; + + // Operations at fixed precision and full numeric_limits support: + cpp_dec_float_100 b = 2; + std::cout << std::numeric_limits<cpp_dec_float_100>::digits << std::endl; + // Note that digits10 is the same as digits, since we're base 10! : + std::cout << std::numeric_limits<cpp_dec_float_100>::digits10 << std::endl; + // We can use any C++ std lib function, lets print all the digits as well: + std::cout << std::setprecision(std::numeric_limits<cpp_dec_float_100>::max_digits10) + << log(b) << std::endl; // print log(2) + // We can also use any function from Boost.Math: + std::cout << boost::math::tgamma(b) << std::endl; + // These even work when the argument is an expression template: + std::cout << boost::math::tgamma(b * b) << std::endl; + // And since we have an extended exponent range we can generate some really large + // numbers here (4.0238726007709377354370243e+2564): + std::cout << boost::math::tgamma(cpp_dec_float_100(1000)) << std::endl; + return 0; +} +//] + diff --git a/src/boost/libs/multiprecision/example/cpp_int_import_export.cpp b/src/boost/libs/multiprecision/example/cpp_int_import_export.cpp new file mode 100644 index 00000000..0e907118 --- /dev/null +++ b/src/boost/libs/multiprecision/example/cpp_int_import_export.cpp @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2015 John Maddock. 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/multiprecision/cpp_int.hpp> +#include <iostream> +#include <iomanip> +#include <vector> +#include <iterator> + +//[IE1 + +/*` +In this simple example, we'll import/export the bits of a cpp_int +to a vector of 8-bit unsigned values: +*/ +/*= +#include <boost/multiprecision/cpp_int.hpp> +#include <iostream> +#include <iomanip> +#include <vector> +#include <iterator> +*/ + +int main() +{ + using boost::multiprecision::cpp_int; + // Create a cpp_int with just a couple of bits set: + cpp_int i; + bit_set(i, 5000); // set the 5000'th bit + bit_set(i, 200); + bit_set(i, 50); + // export into 8-bit unsigned values, most significant bit first: + std::vector<unsigned char> v; + export_bits(i, std::back_inserter(v), 8); + // import back again, and check for equality: + cpp_int j; + import_bits(j, v.begin(), v.end()); + BOOST_ASSERT(i == j); +} + +//] diff --git a/src/boost/libs/multiprecision/example/cpp_int_snips.cpp b/src/boost/libs/multiprecision/example/cpp_int_snips.cpp new file mode 100644 index 00000000..4175db3f --- /dev/null +++ b/src/boost/libs/multiprecision/example/cpp_int_snips.cpp @@ -0,0 +1,75 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2011 John Maddock. 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/multiprecision/cpp_int.hpp> +#include <iostream> + +void t1() +{ +//[cpp_int_eg +//=#include <boost/multiprecision/cpp_int.hpp> +//=#include <iostream> +//= +//=int main() +//={ + using namespace boost::multiprecision; + + int128_t v = 1; + + // Do some fixed precision arithmetic: + for(unsigned i = 1; i <= 20; ++i) + v *= i; + + std::cout << v << std::endl; // prints 2432902008176640000 (i.e. 20!) + + // Repeat at arbitrary precision: + cpp_int u = 1; + for(unsigned i = 1; i <= 100; ++i) + u *= i; + + // prints 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 (i.e. 100!) + std::cout << u << std::endl; + +//= return 0; +//=} +//] +} + +void t3() +{ +//[cpp_rational_eg +//=#include <boost/multiprecision/cpp_int.hpp> +//=#include <iostream> +//= +//=int main() +//={ + using namespace boost::multiprecision; + + cpp_rational v = 1; + + // Do some arithmetic: + for(unsigned i = 1; i <= 1000; ++i) + v *= i; + v /= 10; + + std::cout << v << std::endl; // prints 1000! / 10 + std::cout << numerator(v) << std::endl; + std::cout << denominator(v) << std::endl; + + cpp_rational w(2, 3); // component wise constructor + std::cout << w << std::endl; // prints 2/3 +//= return 0; +//=} +//] +} + + +int main() +{ + t1(); + t3(); + return 0; +} + diff --git a/src/boost/libs/multiprecision/example/debug_adaptor_snips.cpp b/src/boost/libs/multiprecision/example/debug_adaptor_snips.cpp new file mode 100644 index 00000000..2d0efe9a --- /dev/null +++ b/src/boost/libs/multiprecision/example/debug_adaptor_snips.cpp @@ -0,0 +1,40 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2011 John Maddock. 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/multiprecision/cpp_dec_float.hpp> +#include <boost/multiprecision/debug_adaptor.hpp> +#include <iostream> + +void t1() +{ + //[debug_adaptor_eg + //=#include <boost/multiprecision/debug_adaptor.hpp> + //=#include <boost/multiprecision/cpp_dec_float.hpp> + + using namespace boost::multiprecision; + + typedef number<debug_adaptor<cpp_dec_float<50> > > fp_type; + + fp_type denom = 1; + fp_type sum = 1; + + for(unsigned i = 2; i < 50; ++i) + { + denom *= i; + sum += 1 / denom; + } + + std::cout << std::setprecision(std::numeric_limits<fp_type>::digits) << sum << std::endl; + //] +} + +int main() +{ + t1(); + return 0; +} + + + diff --git a/src/boost/libs/multiprecision/example/eigen_example.cpp b/src/boost/libs/multiprecision/example/eigen_example.cpp new file mode 100644 index 00000000..a70e3fbc --- /dev/null +++ b/src/boost/libs/multiprecision/example/eigen_example.cpp @@ -0,0 +1,52 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2018 John Maddock. 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 + +//[eigen_eg +#include <iostream> +#include <boost/multiprecision/cpp_complex.hpp> +#include <boost/multiprecision/eigen.hpp> +#include <Eigen/Dense> + +int main() +{ + using namespace Eigen; + typedef boost::multiprecision::cpp_complex_quad complex_type; + // + // We want to solve Ax = b for x, + // define A and b first: + // + Matrix<complex_type, 2, 2> A, b; + A << complex_type(2, 3), complex_type(-1, -2), complex_type(-1, -4), complex_type(3, 6); + b << 1, 2, 3, 1; + std::cout << "Here is the matrix A:\n" << A << std::endl; + std::cout << "Here is the right hand side b:\n" << b << std::endl; + // + // Solve for x: + // + Matrix<complex_type, 2, 2> x = A.fullPivHouseholderQr().solve(b); + std::cout << "The solution is:\n" << x << std::endl; + // + // Compute the error in the solution by using the norms of Ax - b and b: + // + complex_type::value_type relative_error = (A*x - b).norm() / b.norm(); + std::cout << "The relative error is: " << relative_error << std::endl; + return 0; +} +//] + +/* +//[eigen_out +Here is the matrix A: +(2,3) (-1,-2) +(-1,-4) (3,6) +Here is the right hand side b: +1 2 +3 1 +The solution is: +(0.6,-0.6) (0.7,-0.7) +(0.64,-0.68) (0.58,-0.46) +The relative error is: 2.63132e-34 +//] +*/ diff --git a/src/boost/libs/multiprecision/example/float128_snips.cpp b/src/boost/libs/multiprecision/example/float128_snips.cpp new file mode 100644 index 00000000..5d059252 --- /dev/null +++ b/src/boost/libs/multiprecision/example/float128_snips.cpp @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2013 John Maddock. 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 + +//[float128_eg +#include <boost/multiprecision/float128.hpp> +#include <boost/math/special_functions/gamma.hpp> +#include <iostream> + +int main() +{ + using namespace boost::multiprecision; + + // Operations at 128-bit precision and full numeric_limits support: + float128 b = 2; + // There are 113-bits of precision: + std::cout << std::numeric_limits<float128>::digits << std::endl; + // Or 34 decimal places: + std::cout << std::numeric_limits<float128>::digits10 << std::endl; + // We can use any C++ std lib function, lets print all the digits as well: + std::cout << std::setprecision(std::numeric_limits<float128>::max_digits10) + << log(b) << std::endl; // print log(2) = 0.693147180559945309417232121458176575 + // We can also use any function from Boost.Math: + std::cout << boost::math::tgamma(b) << std::endl; + // And since we have an extended exponent range we can generate some really large + // numbers here (4.02387260077093773543702433923004111e+2564): + std::cout << boost::math::tgamma(float128(1000)) << std::endl; + // + // We can declare constants using GCC or Intel's native types, and the Q suffix, + // these can be declared constexpr if required: + /*<-*/ +#ifndef BOOST_NO_CXX11_CONSTEXPR + /*->*/ + constexpr float128 pi = 3.1415926535897932384626433832795028841971693993751058Q; + /*<-*/ +#endif + /*->*/ + return 0; +} +//] + diff --git a/src/boost/libs/multiprecision/example/floating_point_examples.cpp b/src/boost/libs/multiprecision/example/floating_point_examples.cpp new file mode 100644 index 00000000..f34e278f --- /dev/null +++ b/src/boost/libs/multiprecision/example/floating_point_examples.cpp @@ -0,0 +1,697 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2012 John Maddock. 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/constants/constants.hpp> +#include <boost/multiprecision/cpp_dec_float.hpp> +#include <boost/math/special_functions/gamma.hpp> +#include <boost/math/special_functions/bessel.hpp> +#include <iostream> +#include <iomanip> + +#if !defined(BOOST_NO_CXX11_HDR_ARRAY) && !defined(BOOST_NO_CXX11_LAMBDAS) && !(defined(CI_SUPPRESS_KNOWN_ISSUES) && defined(__GNUC__) && defined(_WIN32)) + +#include <array> + +//[AOS1 + +/*`Generic numeric programming employs templates to use the same code for different +floating-point types and functions. Consider the area of a circle a of radius r, given by + +[:['a = [pi] * r[super 2]]] + +The area of a circle can be computed in generic programming using Boost.Math +for the constant [pi] as shown below: + +*/ + +//=#include <boost/math/constants/constants.hpp> + +template<typename T> +inline T area_of_a_circle(T r) +{ + using boost::math::constants::pi; + return pi<T>() * r * r; +} + +/*` +It is possible to use `area_of_a_circle()` with built-in floating-point types as +well as floating-point types from Boost.Multiprecision. In particular, consider a +system with 4-byte single-precision float, 8-byte double-precision double and also the +`cpp_dec_float_50` data type from Boost.Multiprecision with 50 decimal digits +of precision. + +We can compute and print the approximate area of a circle with radius 123/100 for +`float`, `double` and `cpp_dec_float_50` with the program below. + +*/ + +//] + +//[AOS3 + +/*`In the next example we'll look at calling both standard library and Boost.Math functions from within generic code. +We'll also show how to cope with template arguments which are expression-templates rather than number types.*/ + +//] + +//[JEL + +/*` +In this example we'll show several implementations of the +[@http://mathworld.wolfram.com/LambdaFunction.html Jahnke and Emden Lambda function], +each implementation a little more sophisticated than the last. + +The Jahnke-Emden Lambda function is defined by the equation: + +[:['JahnkeEmden(v, z) = [Gamma](v+1) * J[sub v](z) / (z / 2)[super v]]] + +If we were to implement this at double precision using Boost.Math's facilities for the Gamma and Bessel +function calls it would look like this: + +*/ + +double JEL1(double v, double z) +{ + return boost::math::tgamma(v + 1) * boost::math::cyl_bessel_j(v, z) / std::pow(z / 2, v); +} + +/*` +Calling this function as: + + std::cout << std::scientific << std::setprecision(std::numeric_limits<double>::digits10); + std::cout << JEL1(2.5, 0.5) << std::endl; + +Yields the output: + +[pre 9.822663964796047e-001] + +Now let's implement the function again, but this time using the multiprecision type +`cpp_dec_float_50` as the argument type: + +*/ + +boost::multiprecision::cpp_dec_float_50 + JEL2(boost::multiprecision::cpp_dec_float_50 v, boost::multiprecision::cpp_dec_float_50 z) +{ + return boost::math::tgamma(v + 1) * boost::math::cyl_bessel_j(v, z) / boost::multiprecision::pow(z / 2, v); +} + +/*` +The implementation is almost the same as before, but with one key difference - we can no longer call +`std::pow`, instead we must call the version inside the `boost::multiprecision` namespace. In point of +fact, we could have omitted the namespace prefix on the call to `pow` since the right overload would +have been found via [@http://en.wikipedia.org/wiki/Argument-dependent_name_lookup +argument dependent lookup] in any case. + +Note also that the first argument to `pow` along with the argument to `tgamma` in the above code +are actually expression templates. The `pow` and `tgamma` functions will handle these arguments +just fine. + +Here's an example of how the function may be called: + + std::cout << std::scientific << std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10); + std::cout << JEL2(cpp_dec_float_50(2.5), cpp_dec_float_50(0.5)) << std::endl; + +Which outputs: + +[pre 9.82266396479604757017335009796882833995903762577173e-01] + +Now that we've seen some non-template examples, lets repeat the code again, but this time as a template +that can be called either with a builtin type (`float`, `double` etc), or with a multiprecision type: + +*/ + +template <class Float> +Float JEL3(Float v, Float z) +{ + using std::pow; + return boost::math::tgamma(v + 1) * boost::math::cyl_bessel_j(v, z) / pow(z / 2, v); +} + +/*` + +Once again the code is almost the same as before, but the call to `pow` has changed yet again. +We need the call to resolve to either `std::pow` (when the argument is a builtin type), or +to `boost::multiprecision::pow` (when the argument is a multiprecision type). We do that by +making the call unqualified so that versions of `pow` defined in the same namespace as type +`Float` are found via argument dependent lookup, while the `using std::pow` directive makes +the standard library versions visible for builtin floating point types. + +Let's call the function with both `double` and multiprecision arguments: + + std::cout << std::scientific << std::setprecision(std::numeric_limits<double>::digits10); + std::cout << JEL3(2.5, 0.5) << std::endl; + std::cout << std::scientific << std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10); + std::cout << JEL3(cpp_dec_float_50(2.5), cpp_dec_float_50(0.5)) << std::endl; + +Which outputs: + +[pre +9.822663964796047e-001 +9.82266396479604757017335009796882833995903762577173e-01 +] + +Unfortunately there is a problem with this version: if we were to call it like this: + + boost::multiprecision::cpp_dec_float_50 v(2), z(0.5); + JEL3(v + 0.5, z); + +Then we would get a long and inscrutable error message from the compiler: the problem here is that the first +argument to `JEL3` is not a number type, but an expression template. We could obviously add a typecast to +fix the issue: + + JEL(cpp_dec_float_50(v + 0.5), z); + +However, if we want the function JEL to be truly reusable, then a better solution might be preferred. +To achieve this we can borrow some code from Boost.Math which calculates the return type of mixed-argument +functions, here's how the new code looks now: + +*/ + +template <class Float1, class Float2> +typename boost::math::tools::promote_args<Float1, Float2>::type + JEL4(Float1 v, Float2 z) +{ + using std::pow; + return boost::math::tgamma(v + 1) * boost::math::cyl_bessel_j(v, z) / pow(z / 2, v); +} + +/*` + +As you can see the two arguments to the function are now separate template types, and +the return type is computed using the `promote_args` metafunction from Boost.Math. + +Now we can call: + + std::cout << std::scientific << std::setprecision(std::numeric_limits<cpp_dec_float_100>::digits10); + std::cout << JEL4(cpp_dec_float_100(2) + 0.5, cpp_dec_float_100(0.5)) << std::endl; + +And get 100 digits of output: + +[pre 9.8226639647960475701733500979688283399590376257717309069410413822165082248153638454147004236848917775e-01] + +As a bonus, we can now call the function not just with expression templates, but with other mixed types as well: +for example `float` and `double` or `int` and `double`, and the correct return type will be computed in each case. + +Note that while in this case we didn't have to change the body of the function, in the general case +any function like this which creates local variables internally would have to use `promote_args` +to work out what type those variables should be, for example: + + template <class Float1, class Float2> + typename boost::math::tools::promote_args<Float1, Float2>::type + JEL5(Float1 v, Float2 z) + { + using std::pow; + typedef typename boost::math::tools::promote_args<Float1, Float2>::type variable_type; + variable_type t = pow(z / 2, v); + return boost::math::tgamma(v + 1) * boost::math::cyl_bessel_j(v, z) / t; + } + +*/ + +//] + +//[ND1 + +/*` +In this example we'll add even more power to generic numeric programming using not only different +floating-point types but also function objects as template parameters. Consider +some well-known central difference rules for numerically computing the first derivative +of a function ['f[prime](x)] with ['x [isin] [real]]: + +[equation floating_point_eg1] + +Where the difference terms ['m[sub n]] are given by: + +[equation floating_point_eg2] + +and ['dx] is the step-size of the derivative. + +The third formula in Equation 1 is a three-point central difference rule. It calculates +the first derivative of ['f[prime](x)] to ['O(dx[super 6])], where ['dx] is the given step-size. +For example, if +the step-size is 0.01 this derivative calculation has about 6 decimal digits of precision - +just about right for the 7 decimal digits of single-precision float. +Let's make a generic template subroutine using this three-point central difference +rule. In particular: +*/ + +template<typename value_type, typename function_type> + value_type derivative(const value_type x, const value_type dx, function_type func) +{ + // Compute d/dx[func(*first)] using a three-point + // central difference rule of O(dx^6). + + const value_type dx1 = dx; + const value_type dx2 = dx1 * 2; + const value_type dx3 = dx1 * 3; + + const value_type m1 = (func(x + dx1) - func(x - dx1)) / 2; + const value_type m2 = (func(x + dx2) - func(x - dx2)) / 4; + const value_type m3 = (func(x + dx3) - func(x - dx3)) / 6; + + const value_type fifteen_m1 = 15 * m1; + const value_type six_m2 = 6 * m2; + const value_type ten_dx1 = 10 * dx1; + + return ((fifteen_m1 - six_m2) + m3) / ten_dx1; +} + +/*`The `derivative()` template function can be used to compute the first derivative +of any function to ['O(dx[super 6])]. For example, consider the first derivative of ['sin(x)] evaluated +at ['x = [pi]/3]. In other words, + +[equation floating_point_eg3] + +The code below computes the derivative in Equation 3 for float, double and boost's +multiple-precision type cpp_dec_float_50. +*/ + +//] + +//[GI1 + +/*` +Similar to the generic derivative example, we can calculate integrals in a similar manner: +*/ + +template<typename value_type, typename function_type> +inline value_type integral(const value_type a, + const value_type b, + const value_type tol, + function_type func) +{ + unsigned n = 1U; + + value_type h = (b - a); + value_type I = (func(a) + func(b)) * (h / 2); + + for(unsigned k = 0U; k < 8U; k++) + { + h /= 2; + + value_type sum(0); + for(unsigned j = 1U; j <= n; j++) + { + sum += func(a + (value_type((j * 2) - 1) * h)); + } + + const value_type I0 = I; + I = (I / 2) + (h * sum); + + const value_type ratio = I0 / I; + const value_type delta = ratio - 1; + const value_type delta_abs = ((delta < 0) ? -delta : delta); + + if((k > 1U) && (delta_abs < tol)) + { + break; + } + + n *= 2U; + } + + return I; +} + +/*` +The following sample program shows how the function can be called, we begin +by defining a function object, which when integrated should yield the Bessel J +function: +*/ + +template<typename value_type> +class cyl_bessel_j_integral_rep +{ +public: + cyl_bessel_j_integral_rep(const unsigned N, + const value_type& X) : n(N), x(X) { } + + value_type operator()(const value_type& t) const + { + // pi * Jn(x) = Int_0^pi [cos(x * sin(t) - n*t) dt] + return cos(x * sin(t) - (n * t)); + } + +private: + const unsigned n; + const value_type x; +}; + + +//] + +//[POLY + +/*` +In this example we'll look at polynomial evaluation, this is not only an important +use case, but it's one that `number` performs particularly well at because the +expression templates ['completely eliminate all temporaries] from a +[@http://en.wikipedia.org/wiki/Horner%27s_method Horner polynomial +evaluation scheme]. + +The following code evaluates `sin(x)` as a polynomial, accurate to at least 64 decimal places: + +*/ + +using boost::multiprecision::cpp_dec_float; +typedef boost::multiprecision::number<cpp_dec_float<64> > mp_type; + +mp_type mysin(const mp_type& x) +{ + // Approximation of sin(x * pi/2) for -1 <= x <= 1, using an order 63 polynomial. + static const std::array<mp_type, 32U> coefs = + {{ + mp_type("+1.5707963267948966192313216916397514420985846996875529104874722961539082031431044993140174126711"), //"), + mp_type("-0.64596409750624625365575656389794573337969351178927307696134454382929989411386887578263960484"), // ^3 + mp_type("+0.07969262624616704512050554949047802252091164235106119545663865720995702920146198554317279"), // ^5 + mp_type("-0.0046817541353186881006854639339534378594950280185010575749538605102665157913157426229824"), // ^7 + mp_type("+0.00016044118478735982187266087016347332970280754062061156858775174056686380286868007443"), // ^9 + mp_type("-3.598843235212085340458540018208389404888495232432127661083907575106196374913134E-6"), // ^11 + mp_type("+5.692172921967926811775255303592184372902829756054598109818158853197797542565E-8"), // ^13 + mp_type("-6.688035109811467232478226335783138689956270985704278659373558497256423498E-10"), // ^15 + mp_type("+6.066935731106195667101445665327140070166203261129845646380005577490472E-12"), // ^17 + mp_type("-4.377065467313742277184271313776319094862897030084226361576452003432E-14"), // ^19 + mp_type("+2.571422892860473866153865950420487369167895373255729246889168337E-16"), // ^21 + mp_type("-1.253899540535457665340073300390626396596970180355253776711660E-18"), // ^23 + mp_type("+5.15645517658028233395375998562329055050964428219501277474E-21"), // ^25 + mp_type("-1.812399312848887477410034071087545686586497030654642705E-23"), // ^27 + mp_type("+5.50728578652238583570585513920522536675023562254864E-26"), // ^29 + mp_type("-1.461148710664467988723468673933026649943084902958E-28"), // ^31 + mp_type("+3.41405297003316172502972039913417222912445427E-31"), // ^33 + mp_type("-7.07885550810745570069916712806856538290251E-34"), // ^35 + mp_type("+1.31128947968267628970845439024155655665E-36"), // ^37 + mp_type("-2.18318293181145698535113946654065918E-39"), // ^39 + mp_type("+3.28462680978498856345937578502923E-42"), // ^41 + mp_type("-4.48753699028101089490067137298E-45"), // ^43 + mp_type("+5.59219884208696457859353716E-48"), // ^45 + mp_type("-6.38214503973500471720565E-51"), // ^47 + mp_type("+6.69528558381794452556E-54"), // ^49 + mp_type("-6.47841373182350206E-57"), // ^51 + mp_type("+5.800016389666445E-60"), // ^53 + mp_type("-4.818507347289E-63"), // ^55 + mp_type("+3.724683686E-66"), // ^57 + mp_type("-2.6856479E-69"), // ^59 + mp_type("+1.81046E-72"), // ^61 + mp_type("-1.133E-75"), // ^63 + }}; + + const mp_type v = x * 2 / boost::math::constants::pi<mp_type>(); + const mp_type x2 = (v * v); + // + // Polynomial evaluation follows, if mp_type allocates memory then + // just one such allocation occurs - to initialize the variable "sum" - + // and no temporaries are created at all. + // + const mp_type sum = ((((((((((((((((((((((((((((((( + coefs[31U] + * x2 + coefs[30U]) + * x2 + coefs[29U]) + * x2 + coefs[28U]) + * x2 + coefs[27U]) + * x2 + coefs[26U]) + * x2 + coefs[25U]) + * x2 + coefs[24U]) + * x2 + coefs[23U]) + * x2 + coefs[22U]) + * x2 + coefs[21U]) + * x2 + coefs[20U]) + * x2 + coefs[19U]) + * x2 + coefs[18U]) + * x2 + coefs[17U]) + * x2 + coefs[16U]) + * x2 + coefs[15U]) + * x2 + coefs[14U]) + * x2 + coefs[13U]) + * x2 + coefs[12U]) + * x2 + coefs[11U]) + * x2 + coefs[10U]) + * x2 + coefs[9U]) + * x2 + coefs[8U]) + * x2 + coefs[7U]) + * x2 + coefs[6U]) + * x2 + coefs[5U]) + * x2 + coefs[4U]) + * x2 + coefs[3U]) + * x2 + coefs[2U]) + * x2 + coefs[1U]) + * x2 + coefs[0U]) + * v; + + return sum; +} + +/*` +Calling the function like so: + + mp_type pid4 = boost::math::constants::pi<mp_type>() / 4; + std::cout << std::setprecision(std::numeric_limits< ::mp_type>::digits10) << std::scientific; + std::cout << mysin(pid4) << std::endl; + +Yields the expected output: + +[pre 7.0710678118654752440084436210484903928483593768847403658833986900e-01] + +*/ + +//] + + +int main() +{ + using namespace boost::multiprecision; + std::cout << std::scientific << std::setprecision(std::numeric_limits<double>::digits10); + std::cout << JEL1(2.5, 0.5) << std::endl; + std::cout << std::scientific << std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10); + std::cout << JEL2(cpp_dec_float_50(2.5), cpp_dec_float_50(0.5)) << std::endl; + std::cout << std::scientific << std::setprecision(std::numeric_limits<double>::digits10); + std::cout << JEL3(2.5, 0.5) << std::endl; + std::cout << std::scientific << std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10); + std::cout << JEL3(cpp_dec_float_50(2.5), cpp_dec_float_50(0.5)) << std::endl; + std::cout << std::scientific << std::setprecision(std::numeric_limits<cpp_dec_float_100>::digits10); + std::cout << JEL4(cpp_dec_float_100(2) + 0.5, cpp_dec_float_100(0.5)) << std::endl; + + //[AOS2 + +/*=#include <iostream> +#include <iomanip> +#include <boost/multiprecision/cpp_dec_float.hpp> + +using boost::multiprecision::cpp_dec_float_50; + +int main(int, char**) +{*/ + const float r_f(float(123) / 100); + const float a_f = area_of_a_circle(r_f); + + const double r_d(double(123) / 100); + const double a_d = area_of_a_circle(r_d); + + const cpp_dec_float_50 r_mp(cpp_dec_float_50(123) / 100); + const cpp_dec_float_50 a_mp = area_of_a_circle(r_mp); + + // 4.75292 + std::cout + << std::setprecision(std::numeric_limits<float>::digits10) + << a_f + << std::endl; + + // 4.752915525616 + std::cout + << std::setprecision(std::numeric_limits<double>::digits10) + << a_d + << std::endl; + + // 4.7529155256159981904701331745635599135018975843146 + std::cout + << std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10) + << a_mp + << std::endl; +/*=}*/ + + //] + + //[ND2 +/*= +#include <iostream> +#include <iomanip> +#include <boost/multiprecision/cpp_dec_float.hpp> +#include <boost/math/constants/constants.hpp> + + +int main(int, char**) +{*/ + using boost::math::constants::pi; + using boost::multiprecision::cpp_dec_float_50; + // + // We'll pass a function pointer for the function object passed to derivative, + // the typecast is needed to select the correct overload of std::sin: + // + const float d_f = derivative( + pi<float>() / 3, + 0.01F, + static_cast<float(*)(float)>(std::sin) + ); + + const double d_d = derivative( + pi<double>() / 3, + 0.001, + static_cast<double(*)(double)>(std::sin) + ); + // + // In the cpp_dec_float_50 case, the sin function is multiply overloaded + // to handle expression templates etc. As a result it's hard to take its + // address without knowing about its implementation details. We'll use a + // C++11 lambda expression to capture the call. + // We also need a typecast on the first argument so we don't accidentally pass + // an expression template to a template function: + // + const cpp_dec_float_50 d_mp = derivative( + cpp_dec_float_50(pi<cpp_dec_float_50>() / 3), + cpp_dec_float_50(1.0E-9), + [](const cpp_dec_float_50& x) -> cpp_dec_float_50 + { + return sin(x); + } + ); + + // 5.000029e-001 + std::cout + << std::setprecision(std::numeric_limits<float>::digits10) + << d_f + << std::endl; + + // 4.999999999998876e-001 + std::cout + << std::setprecision(std::numeric_limits<double>::digits10) + << d_d + << std::endl; + + // 4.99999999999999999999999999999999999999999999999999e-01 + std::cout + << std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10) + << d_mp + << std::endl; +//=} + + /*` + The expected value of the derivative is 0.5. This central difference rule in this + example is ill-conditioned, meaning it suffers from slight loss of precision. With that + in mind, the results agree with the expected value of 0.5.*/ + + //] + + //[ND3 + + /*` + We can take this a step further and use our derivative function to compute + a partial derivative. For example if we take the incomplete gamma function + ['P(a, z)], and take the derivative with respect to /z/ at /(2,2)/ then we + can calculate the result as shown below, for good measure we'll compare with + the "correct" result obtained from a call to ['gamma_p_derivative], the results + agree to approximately 44 digits: + */ + + cpp_dec_float_50 gd = derivative( + cpp_dec_float_50(2), + cpp_dec_float_50(1.0E-9), + [](const cpp_dec_float_50& x) ->cpp_dec_float_50 + { + return boost::math::gamma_p(2, x); + } + ); + // 2.70670566473225383787998989944968806815263091819151e-01 + std::cout + << std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10) + << gd + << std::endl; + // 2.70670566473225383787998989944968806815253190143120e-01 + std::cout << boost::math::gamma_p_derivative(cpp_dec_float_50(2), cpp_dec_float_50(2)) << std::endl; + //] + + //[GI2 + + /* The function can now be called as follows: */ +/*=int main(int, char**) +{*/ + using boost::math::constants::pi; + typedef boost::multiprecision::cpp_dec_float_50 mp_type; + + const float j2_f = + integral(0.0F, + pi<float>(), + 0.01F, + cyl_bessel_j_integral_rep<float>(2U, 1.23F)) / pi<float>(); + + const double j2_d = + integral(0.0, + pi<double>(), + 0.0001, + cyl_bessel_j_integral_rep<double>(2U, 1.23)) / pi<double>(); + + const mp_type j2_mp = + integral(mp_type(0), + pi<mp_type>(), + mp_type(1.0E-20), + cyl_bessel_j_integral_rep<mp_type>(2U, mp_type(123) / 100)) / pi<mp_type>(); + + // 0.166369 + std::cout + << std::setprecision(std::numeric_limits<float>::digits10) + << j2_f + << std::endl; + + // 0.166369383786814 + std::cout + << std::setprecision(std::numeric_limits<double>::digits10) + << j2_d + << std::endl; + + // 0.16636938378681407351267852431513159437103348245333 + std::cout + << std::setprecision(std::numeric_limits<mp_type>::digits10) + << j2_mp + << std::endl; + + // + // Print true value for comparison: + // 0.166369383786814073512678524315131594371033482453329 + std::cout << boost::math::cyl_bessel_j(2, mp_type(123) / 100) << std::endl; +//=} + + //] + + std::cout << std::setprecision(std::numeric_limits< ::mp_type>::digits10) << std::scientific; + std::cout << mysin(boost::math::constants::pi< ::mp_type>() / 4) << std::endl; + std::cout << boost::multiprecision::sin(boost::math::constants::pi< ::mp_type>() / 4) << std::endl; + + return 0; +} + +/* + +Program output: + +9.822663964796047e-001 +9.82266396479604757017335009796882833995903762577173e-01 +9.822663964796047e-001 +9.82266396479604757017335009796882833995903762577173e-01 +9.8226639647960475701733500979688283399590376257717309069410413822165082248153638454147004236848917775e-01 +4.752916e+000 +4.752915525615998e+000 +4.75291552561599819047013317456355991350189758431460e+00 +5.000029e-001 +4.999999999998876e-001 +4.99999999999999999999999999999999999999999999999999e-01 +2.70670566473225383787998989944968806815263091819151e-01 +2.70670566473225383787998989944968806815253190143120e-01 +7.0710678118654752440084436210484903928483593768847403658833986900e-01 +7.0710678118654752440084436210484903928483593768847403658833986900e-01 +*/ + +#else + +int main() { return 0; } + +#endif diff --git a/src/boost/libs/multiprecision/example/gauss_laguerre_quadrature.cpp b/src/boost/libs/multiprecision/example/gauss_laguerre_quadrature.cpp new file mode 100644 index 00000000..1ac329a4 --- /dev/null +++ b/src/boost/libs/multiprecision/example/gauss_laguerre_quadrature.cpp @@ -0,0 +1,521 @@ +// Copyright Nick Thompson, 2017 +// 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) + +#include <cmath> +#include <cstdint> +#include <functional> +#include <iomanip> +#include <iostream> +#include <numeric> +#include <boost/math/constants/constants.hpp> +#include <boost/math/special_functions/cbrt.hpp> +#include <boost/math/special_functions/factorials.hpp> +#include <boost/math/special_functions/gamma.hpp> +#include <boost/math/tools/roots.hpp> +#include <boost/noncopyable.hpp> + +#define CPP_BIN_FLOAT 1 +#define CPP_DEC_FLOAT 2 +#define CPP_MPFR_FLOAT 3 + +//#define MP_TYPE CPP_BIN_FLOAT +#define MP_TYPE CPP_DEC_FLOAT +//#define MP_TYPE CPP_MPFR_FLOAT + +namespace +{ + struct digits_characteristics + { + static const int digits10 = 300; + static const int guard_digits = 6; + }; +} + +#if (MP_TYPE == CPP_BIN_FLOAT) + #include <boost/multiprecision/cpp_bin_float.hpp> + namespace mp = boost::multiprecision; + typedef mp::number<mp::cpp_bin_float<digits_characteristics::digits10 + digits_characteristics::guard_digits>, mp::et_off> mp_type; +#elif (MP_TYPE == CPP_DEC_FLOAT) + #include <boost/multiprecision/cpp_dec_float.hpp> + namespace mp = boost::multiprecision; + typedef mp::number<mp::cpp_dec_float<digits_characteristics::digits10 + digits_characteristics::guard_digits>, mp::et_off> mp_type; +#elif (MP_TYPE == CPP_MPFR_FLOAT) + #include <boost/multiprecision/mpfr.hpp> + namespace mp = boost::multiprecision; + typedef mp::number<mp::mpfr_float_backend<digits_characteristics::digits10 + digits_characteristics::guard_digits>, mp::et_off> mp_type; +#else +#error MP_TYPE is undefined +#endif + +template<typename T> +class laguerre_function_object +{ +public: + laguerre_function_object(const int n, const T a) : order(n), + alpha(a), + p1 (0), + d2 (0) { } + + laguerre_function_object(const laguerre_function_object& other) : order(other.order), + alpha(other.alpha), + p1 (other.p1), + d2 (other.d2) { } + + ~laguerre_function_object() { } + + T operator()(const T& x) const + { + // Calculate (via forward recursion): + // * the value of the Laguerre function L(n, alpha, x), called (p2), + // * the value of the derivative of the Laguerre function (d2), + // * and the value of the corresponding Laguerre function of + // previous order (p1). + + // Return the value of the function (p2) in order to be used as a + // function object with Boost.Math root-finding. Store the values + // of the Laguerre function derivative (d2) and the Laguerre function + // of previous order (p1) in class members for later use. + + p1 = T(0); + T p2 = T(1); + d2 = T(0); + + T j_plus_alpha(alpha); + T two_j_plus_one_plus_alpha_minus_x(1 + alpha - x); + + int j; + + const T my_two(2); + + for(j = 0; j < order; ++j) + { + const T p0(p1); + + // Set the value of the previous Laguerre function. + p1 = p2; + + // Use a recurrence relation to compute the value of the Laguerre function. + p2 = ((two_j_plus_one_plus_alpha_minus_x * p1) - (j_plus_alpha * p0)) / (j + 1); + + ++j_plus_alpha; + two_j_plus_one_plus_alpha_minus_x += my_two; + } + + // Set the value of the derivative of the Laguerre function. + d2 = ((p2 * j) - (j_plus_alpha * p1)) / x; + + // Return the value of the Laguerre function. + return p2; + } + + const T& previous () const { return p1; } + const T& derivative() const { return d2; } + + static bool root_tolerance(const T& a, const T& b) + { + using std::abs; + + // The relative tolerance here is: ((a - b) * 2) / (a + b). + return (abs((a - b) * 2) < ((a + b) * boost::math::tools::epsilon<T>())); + } + +private: + const int order; + const T alpha; + mutable T p1; + mutable T d2; + + laguerre_function_object(); + + const laguerre_function_object& operator=(const laguerre_function_object&); +}; + +template<typename T> +class guass_laguerre_abscissas_and_weights : private boost::noncopyable +{ +public: + guass_laguerre_abscissas_and_weights(const int n, const T a) : order(n), + alpha(a), + valid(true), + xi (), + wi () + { + if(alpha < -20.0F) + { + // TBD: If we ever boostify this, throw a range error here. + // If so, then also document it in the docs. + std::cout << "Range error: the order of the Laguerre function must exceed -20.0." << std::endl; + } + else + { + calculate(); + } + } + + virtual ~guass_laguerre_abscissas_and_weights() { } + + const std::vector<T>& abscissas() const { return xi; } + const std::vector<T>& weights () const { return wi; } + + bool get_valid() const { return valid; } + +private: + const int order; + const T alpha; + bool valid; + + std::vector<T> xi; + std::vector<T> wi; + + void calculate() + { + using std::abs; + + std::cout << "finding approximate roots..." << std::endl; + + std::vector<boost::math::tuple<T, T> > root_estimates; + + root_estimates.reserve(static_cast<typename std::vector<boost::math::tuple<T, T> >::size_type>(order)); + + const laguerre_function_object<T> laguerre_object(order, alpha); + + // Set the initial values of the step size and the running step + // to be used for finding the estimate of the first root. + T step_size = 0.01F; + T step = step_size; + + T first_laguerre_root = 0.0F; + + bool first_laguerre_root_has_been_found = true; + + if(alpha < -1.0F) + { + // Iteratively step through the Laguerre function using a + // small step-size in order to find a rough estimate of + // the first zero. + + bool this_laguerre_value_is_negative = (laguerre_object(mp_type(0)) < 0); + + static const int j_max = 10000; + + int j; + + for(j = 0; (j < j_max) && (this_laguerre_value_is_negative != (laguerre_object(step) < 0)); ++j) + { + // Increment the step size until the sign of the Laguerre function + // switches. This indicates a zero-crossing, signalling the next root. + step += step_size; + } + + if(j >= j_max) + { + first_laguerre_root_has_been_found = false; + } + else + { + // We have found the first zero-crossing. Put a loose bracket around + // the root using a window. Here, we know that the first root lies + // between (x - step_size) < root < x. + + // Before storing the approximate root, perform a couple of + // bisection steps in order to tighten up the root bracket. + boost::uintmax_t a_couple_of_iterations = 3U; + const std::pair<T, T> + first_laguerre_root = boost::math::tools::bisect(laguerre_object, + step - step_size, + step, + laguerre_function_object<T>::root_tolerance, + a_couple_of_iterations); + + static_cast<void>(a_couple_of_iterations); + } + } + else + { + // Calculate an estimate of the 1st root of a generalized Laguerre + // function using either a Taylor series or an expansion in Bessel + // function zeros. The Bessel function zeros expansion is from Tricomi. + + // Here, we obtain an estimate of the first zero of J_alpha(x). + + T j_alpha_m1; + + if(alpha < 1.4F) + { + // For small alpha, use a short series obtained from Mathematica(R). + // Series[BesselJZero[v, 1], {v, 0, 3}] + // N[%, 12] + j_alpha_m1 = ((( 0.09748661784476F + * alpha - 0.17549359276115F) + * alpha + 1.54288974259931F) + * alpha + 2.40482555769577F); + } + else + { + // For larger alpha, use the first line of Eqs. 10.21.40 in the NIST Handbook. + const T alpha_pow_third(boost::math::cbrt(alpha)); + const T alpha_pow_minus_two_thirds(T(1) / (alpha_pow_third * alpha_pow_third)); + + j_alpha_m1 = alpha * ((((( + 0.043F + * alpha_pow_minus_two_thirds - 0.0908F) + * alpha_pow_minus_two_thirds - 0.00397F) + * alpha_pow_minus_two_thirds + 1.033150F) + * alpha_pow_minus_two_thirds + 1.8557571F) + * alpha_pow_minus_two_thirds + 1.0F); + } + + const T vf = ((order * 4.0F) + (alpha * 2.0F) + 2.0F); + const T vf2 = vf * vf; + const T j_alpha_m1_sqr = j_alpha_m1 * j_alpha_m1; + + first_laguerre_root = (j_alpha_m1_sqr * (-0.6666666666667F + ((0.6666666666667F * alpha) * alpha) + (0.3333333333333F * j_alpha_m1_sqr) + vf2)) / (vf2 * vf); + } + + if(first_laguerre_root_has_been_found) + { + bool this_laguerre_value_is_negative = (laguerre_object(mp_type(0)) < 0); + + // Re-set the initial value of the step-size based on the + // estimate of the first root. + step_size = first_laguerre_root / 2; + step = step_size; + + // Step through the Laguerre function using a step-size + // of dynamic width in order to find the zero crossings + // of the Laguerre function, providing rough estimates + // of the roots. Refine the brackets with a few bisection + // steps, and store the results as bracketed root estimates. + + while(static_cast<int>(root_estimates.size()) < order) + { + // Increment the step size until the sign of the Laguerre function + // switches. This indicates a zero-crossing, signalling the next root. + step += step_size; + + if(this_laguerre_value_is_negative != (laguerre_object(step) < 0)) + { + // We have found the next zero-crossing. + + // Change the running sign of the Laguerre function. + this_laguerre_value_is_negative = (!this_laguerre_value_is_negative); + + // We have found the first zero-crossing. Put a loose bracket around + // the root using a window. Here, we know that the first root lies + // between (x - step_size) < root < x. + + // Before storing the approximate root, perform a couple of + // bisection steps in order to tighten up the root bracket. + boost::uintmax_t a_couple_of_iterations = 3U; + const std::pair<T, T> + root_estimate_bracket = boost::math::tools::bisect(laguerre_object, + step - step_size, + step, + laguerre_function_object<T>::root_tolerance, + a_couple_of_iterations); + + static_cast<void>(a_couple_of_iterations); + + // Store the refined root estimate as a bracketed range in a tuple. + root_estimates.push_back(boost::math::tuple<T, T>(root_estimate_bracket.first, + root_estimate_bracket.second)); + + if(root_estimates.size() >= static_cast<std::size_t>(2U)) + { + // Determine the next step size. This is based on the distance between + // the previous two roots, whereby the estimates of the previous roots + // are computed by taking the average of the lower and upper range of + // the root-estimate bracket. + + const T r0 = ( boost::math::get<0>(*(root_estimates.rbegin() + 1U)) + + boost::math::get<1>(*(root_estimates.rbegin() + 1U))) / 2; + + const T r1 = ( boost::math::get<0>(*root_estimates.rbegin()) + + boost::math::get<1>(*root_estimates.rbegin())) / 2; + + const T distance_between_previous_roots = r1 - r0; + + step_size = distance_between_previous_roots / 3; + } + } + } + + const T norm_g = + ((alpha == 0) ? T(-1) + : -boost::math::tgamma(alpha + order) / boost::math::factorial<T>(order - 1)); + + xi.reserve(root_estimates.size()); + wi.reserve(root_estimates.size()); + + // Calculate the abscissas and weights to full precision. + for(std::size_t i = static_cast<std::size_t>(0U); i < root_estimates.size(); ++i) + { + std::cout << "calculating abscissa and weight for index: " << i << std::endl; + + // Calculate the abscissas using iterative root-finding. + + // Select the maximum allowed iterations, being at least 20. + // The determination of the maximum allowed iterations is + // based on the number of decimal digits in the numerical + // type T. + const int my_digits10 = static_cast<int>(static_cast<float>(boost::math::tools::digits<T>()) * 0.301F); + const boost::uintmax_t number_of_iterations_allowed = (std::max)(20, my_digits10 / 2); + + boost::uintmax_t number_of_iterations_used = number_of_iterations_allowed; + + // Perform the root-finding using ACM TOMS 748 from Boost.Math. + const std::pair<T, T> + laguerre_root_bracket = boost::math::tools::toms748_solve(laguerre_object, + boost::math::get<0>(root_estimates[i]), + boost::math::get<1>(root_estimates[i]), + laguerre_function_object<T>::root_tolerance, + number_of_iterations_used); + + // Based on the result of *each* root-finding operation, re-assess + // the validity of the Guass-Laguerre abscissas and weights object. + valid &= (number_of_iterations_used < number_of_iterations_allowed); + + // Compute the Laguerre root as the average of the values from + // the solved root bracket. + const T laguerre_root = ( laguerre_root_bracket.first + + laguerre_root_bracket.second) / 2; + + // Calculate the weight for this Laguerre root. Here, we calculate + // the derivative of the Laguerre function and the value of the + // previous Laguerre function on the x-axis at the value of this + // Laguerre root. + static_cast<void>(laguerre_object(laguerre_root)); + + // Store the abscissa and weight for this index. + xi.push_back(laguerre_root); + wi.push_back(norm_g / ((laguerre_object.derivative() * order) * laguerre_object.previous())); + } + } + } +}; + +namespace +{ + template<typename T> + struct gauss_laguerre_ai + { + public: + gauss_laguerre_ai(const T X) : x(X) + { + using std::exp; + using std::sqrt; + + zeta = ((sqrt(x) * x) * 2) / 3; + + const T zeta_times_48_pow_sixth = sqrt(boost::math::cbrt(zeta * 48)); + + factor = 1 / ((sqrt(boost::math::constants::pi<T>()) * zeta_times_48_pow_sixth) * (exp(zeta) * gamma_of_five_sixths())); + } + + gauss_laguerre_ai(const gauss_laguerre_ai& other) : x (other.x), + zeta (other.zeta), + factor(other.factor) { } + + T operator()(const T& t) const + { + using std::sqrt; + + return factor / sqrt(boost::math::cbrt(2 + (t / zeta))); + } + + private: + const T x; + T zeta; + T factor; + + static const T& gamma_of_five_sixths() + { + static const T value = boost::math::tgamma(T(5) / 6); + + return value; + } + + const gauss_laguerre_ai& operator=(const gauss_laguerre_ai&); + }; + + template<typename T> + T gauss_laguerre_airy_ai(const T x) + { + static const float digits_factor = static_cast<float>(std::numeric_limits<mp_type>::digits10) / 300.0F; + static const int laguerre_order = static_cast<int>(600.0F * digits_factor); + + static const guass_laguerre_abscissas_and_weights<T> abscissas_and_weights(laguerre_order, -T(1) / 6); + + T airy_ai_result; + + if(abscissas_and_weights.get_valid()) + { + const gauss_laguerre_ai<T> this_gauss_laguerre_ai(x); + + airy_ai_result = + std::inner_product(abscissas_and_weights.abscissas().begin(), + abscissas_and_weights.abscissas().end(), + abscissas_and_weights.weights().begin(), + T(0), + std::plus<T>(), + [&this_gauss_laguerre_ai](const T& this_abscissa, const T& this_weight) -> T + { + return this_gauss_laguerre_ai(this_abscissa) * this_weight; + }); + } + else + { + // TBD: Consider an error message. + airy_ai_result = T(0); + } + + return airy_ai_result; + } +} + +int main() +{ + // Use Gauss-Laguerre integration to compute airy_ai(120 / 7). + + // 9 digits + // 3.89904210e-22 + + // 10 digits + // 3.899042098e-22 + + // 50 digits. + // 3.8990420982303275013276114626640705170145070824318e-22 + + // 100 digits. + // 3.899042098230327501327611462664070517014507082431797677146153303523108862015228 + // 864136051942933142648e-22 + + // 200 digits. + // 3.899042098230327501327611462664070517014507082431797677146153303523108862015228 + // 86413605194293314264788265460938200890998546786740097437064263800719644346113699 + // 77010905030516409847054404055843899790277e-22 + + // 300 digits. + // 3.899042098230327501327611462664070517014507082431797677146153303523108862015228 + // 86413605194293314264788265460938200890998546786740097437064263800719644346113699 + // 77010905030516409847054404055843899790277083960877617919088116211775232728792242 + // 9346416823281460245814808276654088201413901972239996130752528e-22 + + // 500 digits. + // 3.899042098230327501327611462664070517014507082431797677146153303523108862015228 + // 86413605194293314264788265460938200890998546786740097437064263800719644346113699 + // 77010905030516409847054404055843899790277083960877617919088116211775232728792242 + // 93464168232814602458148082766540882014139019722399961307525276722937464859521685 + // 42826483602153339361960948844649799257455597165900957281659632186012043089610827 + // 78871305322190941528281744734605934497977375094921646511687434038062987482900167 + // 45127557400365419545e-22 + + // Mathematica(R) or Wolfram's Alpha: + // N[AiryAi[120 / 7], 300] + std::cout << std::setprecision(digits_characteristics::digits10) + << gauss_laguerre_airy_ai(mp_type(120) / 7) + << std::endl; +} diff --git a/src/boost/libs/multiprecision/example/gmp_snips.cpp b/src/boost/libs/multiprecision/example/gmp_snips.cpp new file mode 100644 index 00000000..f41e77bf --- /dev/null +++ b/src/boost/libs/multiprecision/example/gmp_snips.cpp @@ -0,0 +1,117 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2011 John Maddock. 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/multiprecision/gmp.hpp> +#include <boost/math/special_functions/gamma.hpp> +#include <iostream> + +void t1() +{ + //[mpz_eg +//=#include <boost/multiprecision/gmp.hpp> +//=#include <iostream> +//= +//=int main() +//={ + using namespace boost::multiprecision; + + mpz_int v = 1; + + // Do some arithmetic: + for(unsigned i = 1; i <= 1000; ++i) + v *= i; + + std::cout << v << std::endl; // prints 1000! + + // Access the underlying representation: + mpz_t z; + mpz_init(z); + mpz_set(z, v.backend().data()); + mpz_clear(z); +//= return 0; +//=} +//] +} + +void t2() +{ +//[mpf_eg +//=#include <boost/multiprecision/gmp.hpp> +//=#include <boost/math/special_functions/gamma.hpp> +//=#include <iostream> +//= +//=int main() +//={ + using namespace boost::multiprecision; + + // Operations at variable precision and limited standard library support: + mpf_float a = 2; + mpf_float::default_precision(1000); + std::cout << mpf_float::default_precision() << std::endl; + std::cout << sqrt(a) << std::endl; // print root-2 + + // Operations at fixed precision and full standard library support: + mpf_float_100 b = 2; + std::cout << std::numeric_limits<mpf_float_100>::digits << std::endl; + // We can use any C++ std lib function: + std::cout << log(b) << std::endl; // print log(2) + // We can also use any function from Boost.Math: + std::cout << boost::math::tgamma(b) << std::endl; + // These even work when the argument is an expression template: + std::cout << boost::math::tgamma(b * b) << std::endl; + + // Access the underlying representation: + mpf_t f; + mpf_init(f); + mpf_set(f, a.backend().data()); + mpf_clear(f); +//= return 0; +//=} +//] +} + +void t3() +{ +//[mpq_eg +//=#include <boost/multiprecision/gmp.hpp> +//=#include <boost/multiprecision/gmp.hpp> +//=#include <iostream> +//= +//=int main() +//={ + using namespace boost::multiprecision; + + mpq_rational v = 1; + + // Do some arithmetic: + for(unsigned i = 1; i <= 1000; ++i) + v *= i; + v /= 10; + + std::cout << v << std::endl; // prints 1000! / 10 + std::cout << numerator(v) << std::endl; + std::cout << denominator(v) << std::endl; + + mpq_rational w(2, 3); // component wise constructor + std::cout << w << std::endl; // prints 2/3 + + // Access the underlying data: + mpq_t q; + mpq_init(q); + mpq_set(q, v.backend().data()); + mpq_clear(q); +//= return 0; +//=} +//] +} + +int main() +{ + t1(); + t2(); + t3(); + return 0; +} + diff --git a/src/boost/libs/multiprecision/example/hashing_examples.cpp b/src/boost/libs/multiprecision/example/hashing_examples.cpp new file mode 100644 index 00000000..a0c3fb50 --- /dev/null +++ b/src/boost/libs/multiprecision/example/hashing_examples.cpp @@ -0,0 +1,77 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2012 John Maddock. 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/multiprecision/cpp_int.hpp> +#include <boost/random.hpp> +#include <boost/functional/hash.hpp> +#include <unordered_set> +#include <city.h> + +//[hash1 + +/*` +All of the types in this library support hashing via boost::hash or std::hash. +That means we can use multiprecision types directly in hashed containers such as std::unordered_set: +*/ +//] + +void t1() +{ + //[hash2 + using namespace boost::multiprecision; + using namespace boost::random; + + mt19937 mt; + uniform_int_distribution<uint256_t> ui; + + std::unordered_set<uint256_t> set; + // Put 1000 random values into the container: + for(unsigned i = 0; i < 1000; ++i) + set.insert(ui(mt)); + + //] +} + +//[hash3 + +/*` +Or we can define our own hash function, for example in this case based on +Google's CityHash: +*/ + +struct cityhash +{ + std::size_t operator()(const boost::multiprecision::uint256_t& val)const + { + // create a hash from all the limbs of the argument, this function is probably x64 specific, + // and requires that we access the internals of the data type: + std::size_t result = CityHash64(reinterpret_cast<const char*>(val.backend().limbs()), val.backend().size() * sizeof(val.backend().limbs()[0])); + // modify the returned hash based on sign: + return val < 0 ? ~result : result; + } +}; + +//] + +void t2() +{ +//[hash4 + +/*`As before insert some values into a container, this time using our custom hasher:*/ + + std::unordered_set<uint256_t, cityhash> set2; + for(unsigned i = 0; i < 1000; ++i) + set2.insert(ui(mt)); + +//] +} + +int main() +{ + t1(); + t2(); + return 0; +} + diff --git a/src/boost/libs/multiprecision/example/hypergeometric_luke_algorithms.cpp b/src/boost/libs/multiprecision/example/hypergeometric_luke_algorithms.cpp new file mode 100644 index 00000000..4fb4e13b --- /dev/null +++ b/src/boost/libs/multiprecision/example/hypergeometric_luke_algorithms.cpp @@ -0,0 +1,801 @@ + +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2013 - 2014. +// 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) +// +// This work is based on an earlier work: +// "Algorithm 910: A Portable C++ Multiple-Precision System for Special-Function Calculations", +// in ACM TOMS, {VOL 37, ISSUE 4, (February 2011)} (C) ACM, 2011. http://doi.acm.org/10.1145/1916461.1916469 +// + +#include <algorithm> +#include <cstdint> +#include <deque> +#include <functional> +#include <iostream> +#include <limits> +#include <numeric> +#include <vector> +#include <boost/math/constants/constants.hpp> +#include <boost/noncopyable.hpp> + +//#define USE_CPP_BIN_FLOAT +#define USE_CPP_DEC_FLOAT +//#define USE_MPFR + +#if !defined(DIGIT_COUNT) +#define DIGIT_COUNT 100 +#endif + +#if !defined(BOOST_NO_CXX11_HDR_CHRONO) + #include <chrono> + #define STD_CHRONO std::chrono +#else + #include <boost/chrono.hpp> + #define STD_CHRONO boost::chrono +#endif + +#if defined(USE_CPP_BIN_FLOAT) + #include <boost/multiprecision/cpp_bin_float.hpp> + typedef boost::multiprecision::number<boost::multiprecision::cpp_bin_float<DIGIT_COUNT + 10> > mp_type; +#elif defined(USE_CPP_DEC_FLOAT) + #include <boost/multiprecision/cpp_dec_float.hpp> + typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<DIGIT_COUNT + 10> > mp_type; +#elif defined(USE_MPFR) + #include <boost/multiprecision/mpfr.hpp> + typedef boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<DIGIT_COUNT + 10> > mp_type; +#else + #error no multiprecision floating type is defined +#endif + +template <class clock_type> +struct stopwatch +{ +public: + typedef typename clock_type::duration duration_type; + + stopwatch() : m_start(clock_type::now()) { } + + stopwatch(const stopwatch& other) : m_start(other.m_start) { } + + stopwatch& operator=(const stopwatch& other) + { + m_start = other.m_start; + return *this; + } + + ~stopwatch() { } + + duration_type elapsed() const + { + return (clock_type::now() - m_start); + } + + void reset() + { + m_start = clock_type::now(); + } + +private: + typename clock_type::time_point m_start; +}; + +namespace my_math +{ + template<class T> T chebyshev_t(const std::int32_t n, const T& x); + + template<class T> T chebyshev_t(const std::uint32_t n, const T& x, std::vector<T>* vp); + + template<class T> bool isneg(const T& x) { return (x < T(0)); } + + template<class T> const T& zero() { static const T value_zero(0); return value_zero; } + template<class T> const T& one () { static const T value_one (1); return value_one; } + template<class T> const T& two () { static const T value_two (2); return value_two; } +} + +namespace orthogonal_polynomial_series +{ + template<typename T> static inline T orthogonal_polynomial_template(const T& x, const std::uint32_t n, std::vector<T>* const vp = static_cast<std::vector<T>*>(0u)) + { + // Compute the value of an orthogonal chebyshev polinomial. + // Use stable upward recursion. + + if(vp != nullptr) + { + vp->clear(); + vp->reserve(static_cast<std::size_t>(n + 1u)); + } + + T y0 = my_math::one<T>(); + + if(vp != nullptr) { vp->push_back(y0); } + + if(n == static_cast<std::uint32_t>(0u)) + { + return y0; + } + + T y1 = x; + + if(vp != nullptr) { vp->push_back(y1); } + + if(n == static_cast<std::uint32_t>(1u)) + { + return y1; + } + + T a = my_math::two <T>(); + T b = my_math::zero<T>(); + T c = my_math::one <T>(); + + T yk; + + // Calculate higher orders using the recurrence relation. + // The direction of stability is upward recursion. + for(std::int32_t k = static_cast<std::int32_t>(2); k <= static_cast<std::int32_t>(n); ++k) + { + yk = (((a * x) + b) * y1) - (c * y0); + + y0 = y1; + y1 = yk; + + if(vp != nullptr) { vp->push_back(yk); } + } + + return yk; + } +} + +template<class T> T my_math::chebyshev_t(const std::int32_t n, const T& x) +{ + if(my_math::isneg(x)) + { + const bool b_negate = ((n % static_cast<std::int32_t>(2)) != static_cast<std::int32_t>(0)); + + const T y = chebyshev_t(n, -x); + + return (!b_negate ? y : -y); + } + + if(n < static_cast<std::int32_t>(0)) + { + const std::int32_t nn = static_cast<std::int32_t>(-n); + + return chebyshev_t(nn, x); + } + else + { + return orthogonal_polynomial_series::orthogonal_polynomial_template(x, static_cast<std::uint32_t>(n)); + } +} + +template<class T> T my_math::chebyshev_t(const std::uint32_t n, const T& x, std::vector<T>* const vp) { return orthogonal_polynomial_series::orthogonal_polynomial_template(x, static_cast<std::int32_t>(n), vp); } + +namespace util +{ + template <class T> float digit_scale() + { + const int d = ((std::max)(std::numeric_limits<T>::digits10, 15)); + return static_cast<float>(d) / 300.0F; + } +} + +namespace examples +{ + namespace nr_006 + { + template<typename T> class hypergeometric_pfq_base : private boost::noncopyable + { + public: + virtual ~hypergeometric_pfq_base() { } + + virtual void ccoef() const = 0; + + virtual T series() const + { + using my_math::chebyshev_t; + + // Compute the Chebyshev coefficients. + // Get the values of the shifted Chebyshev polynomials. + std::vector<T> chebyshev_t_shifted_values; + const T z_shifted = ((Z / W) * static_cast<std::int32_t>(2)) - static_cast<std::int32_t>(1); + + chebyshev_t(static_cast<std::uint32_t>(C.size()), + z_shifted, + &chebyshev_t_shifted_values); + + // Luke: C ---------- COMPUTE SCALE FACTOR ---------- + // Luke: C + // Luke: C ---------- SCALE THE COEFFICIENTS ---------- + // Luke: C + + // The coefficient scaling is preformed after the Chebyshev summation, + // and it is carried out with a single division operation. + bool b_neg = false; + + const T scale = std::accumulate(C.begin(), + C.end(), + T(0), + [&b_neg](T scale_sum, const T& ck) -> T + { + ((!b_neg) ? (scale_sum += ck) : (scale_sum -= ck)); + b_neg = (!b_neg); + return scale_sum; + }); + + // Compute the result of the series expansion using unscaled coefficients. + const T sum = std::inner_product(C.begin(), + C.end(), + chebyshev_t_shifted_values.begin(), + T(0)); + + // Return the properly scaled result. + return sum / scale; + } + + protected: + const T Z; + const T W; + mutable std::deque<T> C; + + hypergeometric_pfq_base(const T& z, + const T& w) : Z(z), + W(w), + C(0u) { } + + virtual std::int32_t N() const { return static_cast<std::int32_t>(util::digit_scale<T>() * 500.0F); } + }; + + template<typename T> class ccoef4_hypergeometric_0f1 : public hypergeometric_pfq_base<T> + { + public: + ccoef4_hypergeometric_0f1(const T& c, + const T& z, + const T& w) : hypergeometric_pfq_base<T>(z, w), + CP(c) { } + + virtual ~ccoef4_hypergeometric_0f1() { } + + virtual void ccoef() const + { + // See Luke 1977 page 80. + const std::int32_t N1 = static_cast<std::int32_t>(this->N() + static_cast<std::int32_t>(1)); + const std::int32_t N2 = static_cast<std::int32_t>(this->N() + static_cast<std::int32_t>(2)); + + // Luke: C ---------- START COMPUTING COEFFICIENTS USING ---------- + // Luke: C ---------- BACKWARD RECURRENCE SCHEME ---------- + // Luke: C + T A3(0); + T A2(0); + T A1(boost::math::tools::root_epsilon<T>()); + + hypergeometric_pfq_base<T>::C.resize(1u, A1); + + std::int32_t X1 = N2; + + T C1 = T(1) - CP; + + const T Z1 = T(4) / hypergeometric_pfq_base<T>::W; + + for(std::int32_t k = static_cast<std::int32_t>(0); k < N1; ++k) + { + const T DIVFAC = T(1) / X1; + + --X1; + + // The terms have been slightly re-arranged resulting in lower complexity. + // Parentheses have been added to avoid reliance on operator precedence. + const T term = (A2 - ((A3 * DIVFAC) * X1)) + + ((A2 * X1) * ((1 + (C1 + X1)) * Z1)) + + ((A1 * X1) * ((DIVFAC - (C1 * Z1)) + (X1 * Z1))); + + hypergeometric_pfq_base<T>::C.push_front(term); + + A3 = A2; + A2 = A1; + A1 = hypergeometric_pfq_base<T>::C.front(); + } + + hypergeometric_pfq_base<T>::C.front() /= static_cast<std::int32_t>(2); + } + + private: + const T CP; + }; + + template<typename T> class ccoef1_hypergeometric_1f0 : public hypergeometric_pfq_base<T> + { + public: + ccoef1_hypergeometric_1f0(const T& a, + const T& z, + const T& w) : hypergeometric_pfq_base<T>(z, w), + AP(a) { } + + virtual ~ccoef1_hypergeometric_1f0() { } + + virtual void ccoef() const + { + // See Luke 1977 page 67. + const std::int32_t N1 = static_cast<std::int32_t>(N() + static_cast<std::int32_t>(1)); + const std::int32_t N2 = static_cast<std::int32_t>(N() + static_cast<std::int32_t>(2)); + + // Luke: C ---------- START COMPUTING COEFFICIENTS USING ---------- + // Luke: C ---------- BACKWARD RECURRENCE SCHEME ---------- + // Luke: C + T A2(0); + T A1(boost::math::tools::root_epsilon<T>()); + + hypergeometric_pfq_base<T>::C.resize(1u, A1); + + std::int32_t X1 = N2; + + T V1 = T(1) - AP; + + // Here, we have corrected what appears to be an error in Luke's code. + + // Luke's original code listing has: + // AFAC = 2 + FOUR/W + // But it appears as though the correct form is: + // AFAC = 2 - FOUR/W. + + const T AFAC = 2 - (T(4) / hypergeometric_pfq_base<T>::W); + + for(std::int32_t k = static_cast<std::int32_t>(0); k < N1; ++k) + { + --X1; + + // The terms have been slightly re-arranged resulting in lower complexity. + // Parentheses have been added to avoid reliance on operator precedence. + const T term = -(((X1 * AFAC) * A1) + ((X1 + V1) * A2)) / (X1 - V1); + + hypergeometric_pfq_base<T>::C.push_front(term); + + A2 = A1; + A1 = hypergeometric_pfq_base<T>::C.front(); + } + + hypergeometric_pfq_base<T>::C.front() /= static_cast<std::int32_t>(2); + } + + private: + const T AP; + + virtual std::int32_t N() const { return static_cast<std::int32_t>(util::digit_scale<T>() * 1600.0F); } + }; + + template<typename T> class ccoef3_hypergeometric_1f1 : public hypergeometric_pfq_base<T> + { + public: + ccoef3_hypergeometric_1f1(const T& a, + const T& c, + const T& z, + const T& w) : hypergeometric_pfq_base<T>(z, w), + AP(a), + CP(c) { } + + virtual ~ccoef3_hypergeometric_1f1() { } + + virtual void ccoef() const + { + // See Luke 1977 page 74. + const std::int32_t N1 = static_cast<std::int32_t>(this->N() + static_cast<std::int32_t>(1)); + const std::int32_t N2 = static_cast<std::int32_t>(this->N() + static_cast<std::int32_t>(2)); + + // Luke: C ---------- START COMPUTING COEFFICIENTS USING ---------- + // Luke: C ---------- BACKWARD RECURRENCE SCHEME ---------- + // Luke: C + T A3(0); + T A2(0); + T A1(boost::math::tools::root_epsilon<T>()); + + hypergeometric_pfq_base<T>::C.resize(1u, A1); + + std::int32_t X = N1; + std::int32_t X1 = N2; + + T XA = X + AP; + T X3A = (X + 3) - AP; + + const T Z1 = T(4) / hypergeometric_pfq_base<T>::W; + + for(std::int32_t k = static_cast<std::int32_t>(0); k < N1; ++k) + { + --X; + --X1; + --XA; + --X3A; + + const T X3A_over_X2 = X3A / static_cast<std::int32_t>(X + 2); + + // The terms have been slightly re-arranged resulting in lower complexity. + // Parentheses have been added to avoid reliance on operator precedence. + const T PART1 = A1 * (((X + CP) * Z1) - X3A_over_X2); + const T PART2 = A2 * (Z1 * ((X + 3) - CP) + (XA / X1)); + const T PART3 = A3 * X3A_over_X2; + + const T term = (((PART1 + PART2) + PART3) * X1) / XA; + + hypergeometric_pfq_base<T>::C.push_front(term); + + A3 = A2; + A2 = A1; + A1 = hypergeometric_pfq_base<T>::C.front(); + } + + hypergeometric_pfq_base<T>::C.front() /= static_cast<std::int32_t>(2); + } + + private: + const T AP; + const T CP; + }; + + template<typename T> class ccoef6_hypergeometric_1f2 : public hypergeometric_pfq_base<T> + { + public: + ccoef6_hypergeometric_1f2(const T& a, + const T& b, + const T& c, + const T& z, + const T& w) : hypergeometric_pfq_base<T>(z, w), + AP(a), + BP(b), + CP(c) { } + + virtual ~ccoef6_hypergeometric_1f2() { } + + virtual void ccoef() const + { + // See Luke 1977 page 85. + const std::int32_t N1 = static_cast<std::int32_t>(this->N() + static_cast<std::int32_t>(1)); + + // Luke: C ---------- START COMPUTING COEFFICIENTS USING ---------- + // Luke: C ---------- BACKWARD RECURRENCE SCHEME ---------- + // Luke: C + T A4(0); + T A3(0); + T A2(0); + T A1(boost::math::tools::root_epsilon<T>()); + + hypergeometric_pfq_base<T>::C.resize(1u, A1); + + std::int32_t X = N1; + T PP = X + AP; + + const T Z1 = T(4) / hypergeometric_pfq_base<T>::W; + + for(std::int32_t k = static_cast<std::int32_t>(0); k < N1; ++k) + { + --X; + --PP; + + const std::int32_t TWO_X = static_cast<std::int32_t>(X * 2); + const std::int32_t X_PLUS_1 = static_cast<std::int32_t>(X + 1); + const std::int32_t X_PLUS_3 = static_cast<std::int32_t>(X + 3); + const std::int32_t X_PLUS_4 = static_cast<std::int32_t>(X + 4); + + const T QQ = T(TWO_X + 3) / static_cast<std::int32_t>(TWO_X + static_cast<std::int32_t>(5)); + const T SS = (X + BP) * (X + CP); + + // The terms have been slightly re-arranged resulting in lower complexity. + // Parentheses have been added to avoid reliance on operator precedence. + const T PART1 = A1 * (((PP - (QQ * (PP + 1))) * 2) + (SS * Z1)); + const T PART2 = (A2 * (X + 2)) * ((((TWO_X + 1) * PP) / X_PLUS_1) - ((QQ * 4) * (PP + 1)) + (((TWO_X + 3) * (PP + 2)) / X_PLUS_3) + ((Z1 * 2) * (SS - (QQ * (X_PLUS_1 + BP)) * (X_PLUS_1 + CP)))); + const T PART3 = A3 * ((((X_PLUS_3 - AP) - (QQ * (X_PLUS_4 - AP))) * 2) + (((QQ * Z1) * (X_PLUS_4 - BP)) * (X_PLUS_4 - CP))); + const T PART4 = ((A4 * QQ) * (X_PLUS_4 - AP)) / X_PLUS_3; + + const T term = (((PART1 - PART2) + (PART3 - PART4)) * X_PLUS_1) / PP; + + hypergeometric_pfq_base<T>::C.push_front(term); + + A4 = A3; + A3 = A2; + A2 = A1; + A1 = hypergeometric_pfq_base<T>::C.front(); + } + + hypergeometric_pfq_base<T>::C.front() /= static_cast<std::int32_t>(2); + } + + private: + const T AP; + const T BP; + const T CP; + }; + + template<typename T> class ccoef2_hypergeometric_2f1 : public hypergeometric_pfq_base<T> + { + public: + ccoef2_hypergeometric_2f1(const T& a, + const T& b, + const T& c, + const T& z, + const T& w) : hypergeometric_pfq_base<T>(z, w), + AP(a), + BP(b), + CP(c) { } + + virtual ~ccoef2_hypergeometric_2f1() { } + + virtual void ccoef() const + { + // See Luke 1977 page 59. + const std::int32_t N1 = static_cast<std::int32_t>(N() + static_cast<std::int32_t>(1)); + const std::int32_t N2 = static_cast<std::int32_t>(N() + static_cast<std::int32_t>(2)); + + // Luke: C ---------- START COMPUTING COEFFICIENTS USING ---------- + // Luke: C ---------- BACKWARD RECURRENCE SCHEME ---------- + // Luke: C + T A3(0); + T A2(0); + T A1(boost::math::tools::root_epsilon<T>()); + + hypergeometric_pfq_base<T>::C.resize(1u, A1); + + std::int32_t X = N1; + std::int32_t X1 = N2; + std::int32_t X3 = static_cast<std::int32_t>((X * 2) + 3); + + T X3A = (X + 3) - AP; + T X3B = (X + 3) - BP; + + const T Z1 = T(4) / hypergeometric_pfq_base<T>::W; + + for(std::int32_t k = static_cast<std::int32_t>(0); k < N1; ++k) + { + --X; + --X1; + --X3A; + --X3B; + X3 -= 2; + + const std::int32_t X_PLUS_2 = static_cast<std::int32_t>(X + 2); + + const T XAB = T(1) / ((X + AP) * (X + BP)); + + // The terms have been slightly re-arranged resulting in lower complexity. + // Parentheses have been added to avoid reliance on operator precedence. + const T PART1 = (A1 * X1) * (2 - (((AP + X1) * (BP + X1)) * ((T(X3) / X_PLUS_2) * XAB)) + ((CP + X) * (XAB * Z1))); + const T PART2 = (A2 * XAB) * ((X3A * X3B) - (X3 * ((X3A + X3B) - 1)) + (((3 - CP) + X) * (X1 * Z1))); + const T PART3 = (A3 * X1) * (X3A / X_PLUS_2) * (X3B * XAB); + + const T term = (PART1 + PART2) - PART3; + + hypergeometric_pfq_base<T>::C.push_front(term); + + A3 = A2; + A2 = A1; + A1 = hypergeometric_pfq_base<T>::C.front(); + } + + hypergeometric_pfq_base<T>::C.front() /= static_cast<std::int32_t>(2); + } + + private: + const T AP; + const T BP; + const T CP; + + virtual std::int32_t N() const { return static_cast<std::int32_t>(util::digit_scale<T>() * 1600.0F); } + }; + + template<class T> T luke_ccoef4_hypergeometric_0f1(const T& a, const T& x); + template<class T> T luke_ccoef1_hypergeometric_1f0(const T& a, const T& x); + template<class T> T luke_ccoef3_hypergeometric_1f1(const T& a, const T& b, const T& x); + template<class T> T luke_ccoef6_hypergeometric_1f2(const T& a, const T& b, const T& c, const T& x); + template<class T> T luke_ccoef2_hypergeometric_2f1(const T& a, const T& b, const T& c, const T& x); + } +} + +template<class T> +T examples::nr_006::luke_ccoef4_hypergeometric_0f1(const T& a, const T& x) +{ + const ccoef4_hypergeometric_0f1<T> hypergeometric_0f1_object(a, x, T(-20)); + + hypergeometric_0f1_object.ccoef(); + + return hypergeometric_0f1_object.series(); +} + +template<class T> +T examples::nr_006::luke_ccoef1_hypergeometric_1f0(const T& a, const T& x) +{ + const ccoef1_hypergeometric_1f0<T> hypergeometric_1f0_object(a, x, T(-20)); + + hypergeometric_1f0_object.ccoef(); + + return hypergeometric_1f0_object.series(); +} + +template<class T> +T examples::nr_006::luke_ccoef3_hypergeometric_1f1(const T& a, const T& b, const T& x) +{ + const ccoef3_hypergeometric_1f1<T> hypergeometric_1f1_object(a, b, x, T(-20)); + + hypergeometric_1f1_object.ccoef(); + + return hypergeometric_1f1_object.series(); +} + +template<class T> +T examples::nr_006::luke_ccoef6_hypergeometric_1f2(const T& a, const T& b, const T& c, const T& x) +{ + const ccoef6_hypergeometric_1f2<T> hypergeometric_1f2_object(a, b, c, x, T(-20)); + + hypergeometric_1f2_object.ccoef(); + + return hypergeometric_1f2_object.series(); +} + +template<class T> +T examples::nr_006::luke_ccoef2_hypergeometric_2f1(const T& a, const T& b, const T& c, const T& x) +{ + const ccoef2_hypergeometric_2f1<T> hypergeometric_2f1_object(a, b, c, x, T(-20)); + + hypergeometric_2f1_object.ccoef(); + + return hypergeometric_2f1_object.series(); +} + +int main() +{ + stopwatch<STD_CHRONO::high_resolution_clock> my_stopwatch; + float total_time = 0.0F; + + std::vector<mp_type> hypergeometric_0f1_results(20U); + std::vector<mp_type> hypergeometric_1f0_results(20U); + std::vector<mp_type> hypergeometric_1f1_results(20U); + std::vector<mp_type> hypergeometric_2f1_results(20U); + std::vector<mp_type> hypergeometric_1f2_results(20U); + + const mp_type a(mp_type(3) / 7); + const mp_type b(mp_type(2) / 3); + const mp_type c(mp_type(1) / 4); + + std::int_least16_t i; + + std::cout << "test hypergeometric_0f1." << std::endl; + i = 1U; + my_stopwatch.reset(); + + // Generate a table of values of Hypergeometric0F1. + // Compare with the Mathematica command: + // Table[N[HypergeometricPFQ[{}, {3/7}, -(i*EulerGamma)], 100], {i, 1, 20, 1}] + std::for_each(hypergeometric_0f1_results.begin(), + hypergeometric_0f1_results.end(), + [&i, &a](mp_type& new_value) + { + const mp_type x(-(boost::math::constants::euler<mp_type>() * i)); + + new_value = examples::nr_006::luke_ccoef4_hypergeometric_0f1(a, x); + + ++i; + }); + + total_time += STD_CHRONO::duration_cast<STD_CHRONO::duration<float> >(my_stopwatch.elapsed()).count(); + + // Print the values of Hypergeometric0F1. + std::for_each(hypergeometric_0f1_results.begin(), + hypergeometric_0f1_results.end(), + [](const mp_type& h) + { + std::cout << std::setprecision(DIGIT_COUNT) << h << std::endl; + }); + + std::cout << "test hypergeometric_1f0." << std::endl; + i = 1U; + my_stopwatch.reset(); + + // Generate a table of values of Hypergeometric1F0. + // Compare with the Mathematica command: + // Table[N[HypergeometricPFQ[{3/7}, {}, -(i*EulerGamma)], 100], {i, 1, 20, 1}] + std::for_each(hypergeometric_1f0_results.begin(), + hypergeometric_1f0_results.end(), + [&i, &a](mp_type& new_value) + { + const mp_type x(-(boost::math::constants::euler<mp_type>() * i)); + + new_value = examples::nr_006::luke_ccoef1_hypergeometric_1f0(a, x); + + ++i; + }); + + total_time += STD_CHRONO::duration_cast<STD_CHRONO::duration<float> >(my_stopwatch.elapsed()).count(); + + // Print the values of Hypergeometric1F0. + std::for_each(hypergeometric_1f0_results.begin(), + hypergeometric_1f0_results.end(), + [](const mp_type& h) + { + std::cout << std::setprecision(DIGIT_COUNT) << h << std::endl; + }); + + std::cout << "test hypergeometric_1f1." << std::endl; + i = 1U; + my_stopwatch.reset(); + + // Generate a table of values of Hypergeometric1F1. + // Compare with the Mathematica command: + // Table[N[HypergeometricPFQ[{3/7}, {2/3}, -(i*EulerGamma)], 100], {i, 1, 20, 1}] + std::for_each(hypergeometric_1f1_results.begin(), + hypergeometric_1f1_results.end(), + [&i, &a, &b](mp_type& new_value) + { + const mp_type x(-(boost::math::constants::euler<mp_type>() * i)); + + new_value = examples::nr_006::luke_ccoef3_hypergeometric_1f1(a, b, x); + + ++i; + }); + + total_time += STD_CHRONO::duration_cast<STD_CHRONO::duration<float> >(my_stopwatch.elapsed()).count(); + + // Print the values of Hypergeometric1F1. + std::for_each(hypergeometric_1f1_results.begin(), + hypergeometric_1f1_results.end(), + [](const mp_type& h) + { + std::cout << std::setprecision(DIGIT_COUNT) << h << std::endl; + }); + + std::cout << "test hypergeometric_1f2." << std::endl; + i = 1U; + my_stopwatch.reset(); + + // Generate a table of values of Hypergeometric1F2. + // Compare with the Mathematica command: + // Table[N[HypergeometricPFQ[{3/7}, {2/3, 1/4}, -(i*EulerGamma)], 100], {i, 1, 20, 1}] + std::for_each(hypergeometric_1f2_results.begin(), + hypergeometric_1f2_results.end(), + [&i, &a, &b, &c](mp_type& new_value) + { + const mp_type x(-(boost::math::constants::euler<mp_type>() * i)); + + new_value = examples::nr_006::luke_ccoef6_hypergeometric_1f2(a, b, c, x); + + ++i; + }); + + total_time += STD_CHRONO::duration_cast<STD_CHRONO::duration<float> >(my_stopwatch.elapsed()).count(); + + // Print the values of Hypergeometric1F2. + std::for_each(hypergeometric_1f2_results.begin(), + hypergeometric_1f2_results.end(), + [](const mp_type& h) + { + std::cout << std::setprecision(DIGIT_COUNT) << h << std::endl; + }); + + std::cout << "test hypergeometric_2f1." << std::endl; + i = 1U; + my_stopwatch.reset(); + + // Generate a table of values of Hypergeometric2F1. + // Compare with the Mathematica command: + // Table[N[HypergeometricPFQ[{3/7, 2/3}, {1/4}, -(i * EulerGamma)], 100], {i, 1, 20, 1}] + std::for_each(hypergeometric_2f1_results.begin(), + hypergeometric_2f1_results.end(), + [&i, &a, &b, &c](mp_type& new_value) + { + const mp_type x(-(boost::math::constants::euler<mp_type>() * i)); + + new_value = examples::nr_006::luke_ccoef2_hypergeometric_2f1(a, b, c, x); + + ++i; + }); + + total_time += STD_CHRONO::duration_cast<STD_CHRONO::duration<float> >(my_stopwatch.elapsed()).count(); + + // Print the values of Hypergeometric2F1. + std::for_each(hypergeometric_2f1_results.begin(), + hypergeometric_2f1_results.end(), + [](const mp_type& h) + { + std::cout << std::setprecision(DIGIT_COUNT) << h << std::endl; + }); + + std::cout << "Total execution time = " << std::setprecision(3) << total_time << "s" << std::endl; +} diff --git a/src/boost/libs/multiprecision/example/integer_examples.cpp b/src/boost/libs/multiprecision/example/integer_examples.cpp new file mode 100644 index 00000000..5c2f8147 --- /dev/null +++ b/src/boost/libs/multiprecision/example/integer_examples.cpp @@ -0,0 +1,232 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2012 John Maddock. 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/multiprecision/cpp_int.hpp> +#include <iostream> +#include <iomanip> +#include <vector> + +// Includes Quickbook code snippets as comments. + +//[FAC1 + +/*` +In this simple example, we'll write a routine to print out all of the factorials +which will fit into a 128-bit integer. At the end of the routine we do some +fancy iostream formatting of the results: +*/ +/*= +#include <boost/multiprecision/cpp_int.hpp> +#include <iostream> +#include <iomanip> +#include <vector> +*/ + +void print_factorials() +{ + using boost::multiprecision::cpp_int; + // + // Print all the factorials that will fit inside a 128-bit integer. + // + // Begin by building a big table of factorials, once we know just how + // large the largest is, we'll be able to "pretty format" the results. + // + // Calculate the largest number that will fit inside 128 bits, we could + // also have used numeric_limits<int128_t>::max() for this value: + cpp_int limit = (cpp_int(1) << 128) - 1; + // + // Our table of values: + std::vector<cpp_int> results; + // + // Initial values: + unsigned i = 1; + cpp_int factorial = 1; + // + // Cycle through the factorials till we reach the limit: + while(factorial < limit) + { + results.push_back(factorial); + ++i; + factorial *= i; + } + // + // Lets see how many digits the largest factorial was: + unsigned digits = results.back().str().size(); + // + // Now print them out, using right justification, while we're at it + // we'll indicate the limit of each integer type, so begin by defining + // the limits for 16, 32, 64 etc bit integers: + cpp_int limits[] = { + (cpp_int(1) << 16) - 1, + (cpp_int(1) << 32) - 1, + (cpp_int(1) << 64) - 1, + (cpp_int(1) << 128) - 1, + }; + std::string bit_counts[] = { "16", "32", "64", "128" }; + unsigned current_limit = 0; + for(unsigned j = 0; j < results.size(); ++j) + { + if(limits[current_limit] < results[j]) + { + std::string message = "Limit of " + bit_counts[current_limit] + " bit integers"; + std::cout << std::setfill('.') << std::setw(digits+1) << std::right << message << std::setfill(' ') << std::endl; + ++current_limit; + } + std::cout << std::setw(digits + 1) << std::right << results[j] << std::endl; + } +} + +/*` +The output from this routine is: +[pre + 1 + 2 + 6 + 24 + 120 + 720 + 5040 + 40320 +................Limit of 16 bit integers + 362880 + 3628800 + 39916800 + 479001600 +................Limit of 32 bit integers + 6227020800 + 87178291200 + 1307674368000 + 20922789888000 + 355687428096000 + 6402373705728000 + 121645100408832000 + 2432902008176640000 +................Limit of 64 bit integers + 51090942171709440000 + 1124000727777607680000 + 25852016738884976640000 + 620448401733239439360000 + 15511210043330985984000000 + 403291461126605635584000000 + 10888869450418352160768000000 + 304888344611713860501504000000 + 8841761993739701954543616000000 + 265252859812191058636308480000000 + 8222838654177922817725562880000000 + 263130836933693530167218012160000000 + 8683317618811886495518194401280000000 + 295232799039604140847618609643520000000 +] +*/ + +//] + +//[BITOPS + +/*` +In this example we'll show how individual bits within an integer may be manipulated, +we'll start with an often needed calculation of ['2[super n] - 1], which we could obviously +implement like this: +*/ + +using boost::multiprecision::cpp_int; + +cpp_int b1(unsigned n) +{ + cpp_int r(1); + return (r << n) - 1; +} + +/*` +Calling: + + std::cout << std::hex << std::showbase << b1(200) << std::endl; + +Yields as expected: + +[pre 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF] + +However, we could equally just set the n'th bit in the result, like this: +*/ + +cpp_int b2(unsigned n) +{ + cpp_int r(0); + return --bit_set(r, n); +} + +/*` +Note how the `bit_set` function sets the specified bit in its argument and then returns a reference to the result - +which we can then simply decrement. The result from a call to `b2` is the same as that to `b1`. + +We can equally test bits, so for example the n'th bit of the result returned from `b2` shouldn't be set +unless we increment it first: + + BOOST_ASSERT(!bit_test(b1(200), 200)); // OK + BOOST_ASSERT(bit_test(++b1(200), 200)); // OK + +And of course if we flip the n'th bit after increment, then we should get back to zero: + + BOOST_ASSERT(!bit_flip(++b1(200), 200)); // OK +*/ + +//] + +int main() +{ + print_factorials(); + + std::cout << std::hex << std::showbase << b1(200) << std::endl; + std::cout << std::hex << std::showbase << b2(200) << std::endl; + BOOST_ASSERT(!bit_test(b1(200), 200)); // OK + BOOST_ASSERT(bit_test(++b1(200), 200)); // OK + BOOST_ASSERT(!bit_flip(++b1(200), 200)); // OK + return 0; +} + +/* + +Program output: + + 1 + 2 + 6 + 24 + 120 + 720 + 5040 + 40320 +................Limit of 16 bit integers + 362880 + 3628800 + 39916800 + 479001600 +................Limit of 32 bit integers + 6227020800 + 87178291200 + 1307674368000 + 20922789888000 + 355687428096000 + 6402373705728000 + 121645100408832000 + 2432902008176640000 +................Limit of 64 bit integers + 51090942171709440000 + 1124000727777607680000 + 25852016738884976640000 + 620448401733239439360000 + 15511210043330985984000000 + 403291461126605635584000000 + 10888869450418352160768000000 + 304888344611713860501504000000 + 8841761993739701954543616000000 + 265252859812191058636308480000000 + 8222838654177922817725562880000000 + 263130836933693530167218012160000000 + 8683317618811886495518194401280000000 + 295232799039604140847618609643520000000 + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + */ diff --git a/src/boost/libs/multiprecision/example/logged_adaptor.cpp b/src/boost/libs/multiprecision/example/logged_adaptor.cpp new file mode 100644 index 00000000..f204cf39 --- /dev/null +++ b/src/boost/libs/multiprecision/example/logged_adaptor.cpp @@ -0,0 +1,119 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2013 John Maddock. 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 + +//[logged_adaptor + +#include <boost/multiprecision/mpfi.hpp> +#include <boost/multiprecision/logged_adaptor.hpp> +#include <iostream> +#include <iomanip> +// +// Begin by overloading log_postfix_event so we can capture each arithmetic event as it happens: +// +namespace boost{ namespace multiprecision{ + +template <unsigned D> +inline void log_postfix_event(const mpfi_float_backend<D>& val, const char* event_description) +{ + // Print out the (relative) diameter of the interval: + using namespace boost::multiprecision; + number<mpfr_float_backend<D> > diam; + mpfi_diam(diam.backend().data(), val.data()); + std::cout << "Diameter was " << diam << " after operation: " << event_description << std::endl; +} +template <unsigned D, class T> +inline void log_postfix_event(const mpfi_float_backend<D>&, const T&, const char* event_description) +{ + // This version is never called in this example. +} + +}} + + +int main() +{ + using namespace boost::multiprecision; + typedef number<logged_adaptor<mpfi_float_backend<17> > > logged_type; + // + // Test case deliberately introduces cancellation error, relative size of interval + // gradually gets larger after each operation: + // + logged_type a = 1; + a /= 10; + + for(unsigned i = 0; i < 13; ++i) + { + logged_type b = a * 9; + b /= 10; + a -= b; + } + std::cout << "Final value was: " << a << std::endl; + return 0; +} + +//] + +/* +//[logged_adaptor_output + +Diameter was nan after operation: Default construct +Diameter was 0 after operation: Assignment from arithmetic type +Diameter was 4.33681e-18 after operation: /= +Diameter was nan after operation: Default construct +Diameter was 7.70988e-18 after operation: * +Diameter was 9.63735e-18 after operation: /= +Diameter was 1.30104e-16 after operation: -= +Diameter was nan after operation: Default construct +Diameter was 1.30104e-16 after operation: * +Diameter was 1.38537e-16 after operation: /= +Diameter was 2.54788e-15 after operation: -= +Diameter was nan after operation: Default construct +Diameter was 2.54788e-15 after operation: * +Diameter was 2.54863e-15 after operation: /= +Diameter was 4.84164e-14 after operation: -= +Diameter was nan after operation: Default construct +Diameter was 4.84164e-14 after operation: * +Diameter was 4.84221e-14 after operation: /= +Diameter was 9.19962e-13 after operation: -= +Diameter was nan after operation: Default construct +Diameter was 9.19962e-13 after operation: * +Diameter was 9.19966e-13 after operation: /= +Diameter was 1.74793e-11 after operation: -= +Diameter was nan after operation: Default construct +Diameter was 1.74793e-11 after operation: * +Diameter was 1.74793e-11 after operation: /= +Diameter was 3.32107e-10 after operation: -= +Diameter was nan after operation: Default construct +Diameter was 3.32107e-10 after operation: * +Diameter was 3.32107e-10 after operation: /= +Diameter was 6.31003e-09 after operation: -= +Diameter was nan after operation: Default construct +Diameter was 6.31003e-09 after operation: * +Diameter was 6.31003e-09 after operation: /= +Diameter was 1.19891e-07 after operation: -= +Diameter was nan after operation: Default construct +Diameter was 1.19891e-07 after operation: * +Diameter was 1.19891e-07 after operation: /= +Diameter was 2.27792e-06 after operation: -= +Diameter was nan after operation: Default construct +Diameter was 2.27792e-06 after operation: * +Diameter was 2.27792e-06 after operation: /= +Diameter was 4.32805e-05 after operation: -= +Diameter was nan after operation: Default construct +Diameter was 4.32805e-05 after operation: * +Diameter was 4.32805e-05 after operation: /= +Diameter was 0.00082233 after operation: -= +Diameter was nan after operation: Default construct +Diameter was 0.00082233 after operation: * +Diameter was 0.00082233 after operation: /= +Diameter was 0.0156243 after operation: -= +Diameter was nan after operation: Default construct +Diameter was 0.0156243 after operation: * +Diameter was 0.0156243 after operation: /= +Diameter was 0.296861 after operation: -= +Final value was: {8.51569e-15,1.14843e-14} + +//] +*/ diff --git a/src/boost/libs/multiprecision/example/mixed_integer_arithmetic.cpp b/src/boost/libs/multiprecision/example/mixed_integer_arithmetic.cpp new file mode 100644 index 00000000..c1ab5b5c --- /dev/null +++ b/src/boost/libs/multiprecision/example/mixed_integer_arithmetic.cpp @@ -0,0 +1,55 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2012 John Maddock. 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 + +// +// Compare arithmetic results using fixed_int to GMP results. +// + +#ifdef _MSC_VER +# define _SCL_SECURE_NO_WARNINGS +#endif + +//[mixed_eg +#include <boost/multiprecision/cpp_int.hpp> + +int main() +{ + using namespace boost::multiprecision; + + boost::uint64_t i = (std::numeric_limits<boost::uint64_t>::max)(); + boost::uint64_t j = 1; + + uint128_t ui128; + uint256_t ui256; + // + // Start by performing arithmetic on 64-bit integers to yield 128-bit results: + // + std::cout << std::hex << std::showbase << i << std::endl; + std::cout << std::hex << std::showbase << add(ui128, i, j) << std::endl; + std::cout << std::hex << std::showbase << multiply(ui128, i, i) << std::endl; + // + // The try squaring a 128-bit integer to yield a 256-bit result: + // + ui128 = (std::numeric_limits<uint128_t>::max)(); + std::cout << std::hex << std::showbase << multiply(ui256, ui128, ui128) << std::endl; + + return 0; +} +//] + +/* + +Program output: + +//[mixed_output + +0xffffffffffffffff +0x10000000000000000 +0xFFFFFFFFFFFFFFFE0000000000000001 +0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE00000000000000000000000000000001 + +//] +*/ + diff --git a/src/boost/libs/multiprecision/example/mpc_examples.cpp b/src/boost/libs/multiprecision/example/mpc_examples.cpp new file mode 100644 index 00000000..30f9a0bf --- /dev/null +++ b/src/boost/libs/multiprecision/example/mpc_examples.cpp @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2018 Nick Thompson. 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 + +/*`This example demonstrates the usage of the MPC backend for multiprecision complex numbers. +In the following, we will show how using MPC backend allows for the same operations as the C++ standard library complex numbers. +*/ + +//[mpc_eg +#include <iostream> +#include <complex> +#include <boost/multiprecision/mpc.hpp> + +template<class Complex> +void complex_number_examples() +{ + Complex z1{0, 1}; + std::cout << std::setprecision(std::numeric_limits<typename Complex::value_type>::digits10); + std::cout << std::scientific << std::fixed; + std::cout << "Print a complex number: " << z1 << std::endl; + std::cout << "Square it : " << z1*z1 << std::endl; + std::cout << "Real part : " << z1.real() << " = " << real(z1) << std::endl; + std::cout << "Imaginary part : " << z1.imag() << " = " << imag(z1) << std::endl; + using std::abs; + std::cout << "Absolute value : " << abs(z1) << std::endl; + std::cout << "Argument : " << arg(z1) << std::endl; + std::cout << "Norm : " << norm(z1) << std::endl; + std::cout << "Complex conjugate : " << conj(z1) << std::endl; + std::cout << "Projection onto Riemann sphere: " << proj(z1) << std::endl; + typename Complex::value_type r = 1; + typename Complex::value_type theta = 0.8; + using std::polar; + std::cout << "Polar coordinates (phase = 0) : " << polar(r) << std::endl; + std::cout << "Polar coordinates (phase !=0) : " << polar(r, theta) << std::endl; + + std::cout << "\nElementary special functions:\n"; + using std::exp; + std::cout << "exp(z1) = " << exp(z1) << std::endl; + using std::log; + std::cout << "log(z1) = " << log(z1) << std::endl; + using std::log10; + std::cout << "log10(z1) = " << log10(z1) << std::endl; + using std::pow; + std::cout << "pow(z1, z1) = " << pow(z1, z1) << std::endl; + using std::sqrt; + std::cout << "Take its square root : " << sqrt(z1) << std::endl; + using std::sin; + std::cout << "sin(z1) = " << sin(z1) << std::endl; + using std::cos; + std::cout << "cos(z1) = " << cos(z1) << std::endl; + using std::tan; + std::cout << "tan(z1) = " << tan(z1) << std::endl; + using std::asin; + std::cout << "asin(z1) = " << asin(z1) << std::endl; + using std::acos; + std::cout << "acos(z1) = " << acos(z1) << std::endl; + using std::atan; + std::cout << "atan(z1) = " << atan(z1) << std::endl; + using std::sinh; + std::cout << "sinh(z1) = " << sinh(z1) << std::endl; + using std::cosh; + std::cout << "cosh(z1) = " << cosh(z1) << std::endl; + using std::tanh; + std::cout << "tanh(z1) = " << tanh(z1) << std::endl; + using std::asinh; + std::cout << "asinh(z1) = " << asinh(z1) << std::endl; + using std::acosh; + std::cout << "acosh(z1) = " << acosh(z1) << std::endl; + using std::atanh; + std::cout << "atanh(z1) = " << atanh(z1) << std::endl; +} + +int main() +{ + std::cout << "First, some operations we usually perform with std::complex:\n"; + complex_number_examples<std::complex<double>>(); + std::cout << "\nNow the same operations performed using the MPC backend:\n"; + complex_number_examples<boost::multiprecision::mpc_complex_50>(); + + return 0; +} +//] + +/* + +//[mpc_out + +Print a complex number: (0.00000000000000000000000000000000000000000000000000,1.00000000000000000000000000000000000000000000000000) +Square it : -1.00000000000000000000000000000000000000000000000000 +Real part : 0.00000000000000000000000000000000000000000000000000 = 0.00000000000000000000000000000000000000000000000000 +Imaginary part : 1.00000000000000000000000000000000000000000000000000 = 1.00000000000000000000000000000000000000000000000000 +Absolute value : 1.00000000000000000000000000000000000000000000000000 +Argument : 1.57079632679489661923132169163975144209858469968755 +Norm : 1.00000000000000000000000000000000000000000000000000 +Complex conjugate : (0.00000000000000000000000000000000000000000000000000,-1.00000000000000000000000000000000000000000000000000) +Projection onto Riemann sphere: (0.00000000000000000000000000000000000000000000000000,1.00000000000000000000000000000000000000000000000000) +Polar coordinates (phase = 0) : 1.00000000000000000000000000000000000000000000000000 +Polar coordinates (phase !=0) : (0.69670670934716538906374002277244853473117519431538,0.71735609089952279256716781570337728075604730751255) + +Elementary special functions: +exp(z1) = (0.54030230586813971740093660744297660373231042061792,0.84147098480789650665250232163029899962256306079837) +log(z1) = (0.00000000000000000000000000000000000000000000000000,1.57079632679489661923132169163975144209858469968755) +log10(z1) = (0.00000000000000000000000000000000000000000000000000,0.68218817692092067374289181271567788510506374186196) +pow(z1, z1) = 0.20787957635076190854695561983497877003387784163177 +Take its square root : (0.70710678118654752440084436210484903928483593768847,0.70710678118654752440084436210484903928483593768847) +sin(z1) = (0.00000000000000000000000000000000000000000000000000,1.17520119364380145688238185059560081515571798133410) +cos(z1) = 1.54308063481524377847790562075706168260152911236587 +tan(z1) = (0.00000000000000000000000000000000000000000000000000,0.76159415595576488811945828260479359041276859725794) +asin(z1) = (0.00000000000000000000000000000000000000000000000000,0.88137358701954302523260932497979230902816032826163) +acos(z1) = (1.57079632679489661923132169163975144209858469968755,-0.88137358701954302523260932497979230902816032826163) +atan(z1) = (0.00000000000000000000000000000000000000000000000000,inf) +sinh(z1) = (0.00000000000000000000000000000000000000000000000000,0.84147098480789650665250232163029899962256306079837) +cosh(z1) = 0.54030230586813971740093660744297660373231042061792 +tanh(z1) = (0.00000000000000000000000000000000000000000000000000,1.55740772465490223050697480745836017308725077238152) +asinh(z1) = (0.00000000000000000000000000000000000000000000000000,1.57079632679489661923132169163975144209858469968755) +acosh(z1) = (0.88137358701954302523260932497979230902816032826163,1.57079632679489661923132169163975144209858469968755) +atanh(z1) = (0.00000000000000000000000000000000000000000000000000,0.78539816339744830961566084581987572104929234984378) + +//] +*/ diff --git a/src/boost/libs/multiprecision/example/mpfi_snips.cpp b/src/boost/libs/multiprecision/example/mpfi_snips.cpp new file mode 100644 index 00000000..b36e22b5 --- /dev/null +++ b/src/boost/libs/multiprecision/example/mpfi_snips.cpp @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2011 John Maddock. 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 + +//[mpfi_eg +#include <boost/multiprecision/mpfi.hpp> +#include <boost/math/special_functions/gamma.hpp> +#include <iostream> + +int main() +{ + using namespace boost::multiprecision; + + // Operations at variable precision and no numeric_limits support: + mpfi_float a = 2; + mpfi_float::default_precision(1000); + std::cout << mpfi_float::default_precision() << std::endl; + std::cout << sqrt(a) << std::endl; // print root-2 + + // Operations at fixed precision and full numeric_limits support: + mpfi_float_100 b = 2; + std::cout << std::numeric_limits<mpfi_float_100>::digits << std::endl; + // We can use any C++ std lib function: + std::cout << log(b) << std::endl; // print log(2) + + // Access the underlying data: + mpfi_t r; + mpfi_init(r); + mpfi_set(r, b.backend().data()); + + // Construct some explicit intervals and perform set operations: + mpfi_float_50 i1(1, 2), i2(1.5, 2.5); + std::cout << intersect(i1, i2) << std::endl; + std::cout << hull(i1, i2) << std::endl; + std::cout << overlap(i1, i2) << std::endl; + std::cout << subset(i1, i2) << std::endl; + mpfi_clear(r); + return 0; +} +//] + diff --git a/src/boost/libs/multiprecision/example/mpfr_precision.cpp b/src/boost/libs/multiprecision/example/mpfr_precision.cpp new file mode 100644 index 00000000..eb559cbe --- /dev/null +++ b/src/boost/libs/multiprecision/example/mpfr_precision.cpp @@ -0,0 +1,252 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2018 John Maddock. 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 + +//[mpfr_variable + +/*` +This example illustrates the use of variable-precision arithmetic with +the `mpfr_float` number type. We'll calculate the median of the +beta distribution to an absurdly high precision and compare the +accuracy and times taken for various methods. That is, we want +to calculate the value of `x` for which ['I[sub x](a, b) = 0.5]. + +Ultimately we'll use Newtons method and set the precision of +mpfr_float to have just enough digits at each iteration. + +The full source of the this program is in [@../../example/mpfr_precision.cpp] + +We'll skip over the #includes and using declations, and go straight to +some support code, first off a simple stopwatch for performance measurement: + +*/ + +//=template <class clock_type> +//=struct stopwatch { /*details \*/ }; + +/*` +We'll use `stopwatch<std::chono::high_resolution_clock>` as our performance measuring device. + +We also have a small utility class for controlling the current precision of mpfr_float: + + struct scoped_precision + { + unsigned p; + scoped_precision(unsigned new_p) : p(mpfr_float::default_precision()) + { + mpfr_float::default_precision(new_p); + } + ~scoped_precision() + { + mpfr_float::default_precision(p); + } + }; + +*/ +//<- +#include <boost/multiprecision/mpfr.hpp> +#include <boost/math/special_functions/beta.hpp> +#include <boost/math/special_functions/relative_difference.hpp> +#include <iostream> +#include <chrono> + +using boost::multiprecision::mpfr_float; +using boost::math::ibeta_inv; +using namespace boost::math::policies; + +template <class clock_type> +struct stopwatch +{ +public: + typedef typename clock_type::duration duration_type; + + stopwatch() : m_start(clock_type::now()) { } + + stopwatch(const stopwatch& other) : m_start(other.m_start) { } + + stopwatch& operator=(const stopwatch& other) + { + m_start = other.m_start; + return *this; + } + + ~stopwatch() { } + + float elapsed() const + { + return float(std::chrono::nanoseconds((clock_type::now() - m_start)).count()) / 1e9f; + } + + void reset() + { + m_start = clock_type::now(); + } + +private: + typename clock_type::time_point m_start; +}; + +struct scoped_precision +{ + unsigned p; + scoped_precision(unsigned new_p) : p(mpfr_float::default_precision()) + { + mpfr_float::default_precision(new_p); + } + ~scoped_precision() + { + mpfr_float::default_precision(p); + } +}; +//-> + +/*` +We'll begin with a reference method that simply calls the Boost.Math function `ibeta_inv` and uses the +full working precision of the arguments throughout. Our reference function takes 3 arguments: + +* The 2 parameters `a` and `b` of the beta distribution, and +* The number of decimal digits precision to achieve in the result. + +We begin by setting the default working precision to that requested, and then, since we don't know where +our arguments `a` and `b` have been or what precision they have, we make a copy of them - note that since +copying also copies the precision as well as the value, we have to set the precision expicitly with a +second argument to the copy. Then we can simply return the result of `ibeta_inv`: +*/ +mpfr_float beta_distribution_median_method_1(mpfr_float const& a_, mpfr_float const& b_, unsigned digits10) +{ + scoped_precision sp(digits10); + mpfr_float half(0.5), a(a_, digits10), b(b_, digits10); + return ibeta_inv(a, b, half); +} +/*` +You be wondering why we needed to change the precision of our variables `a` and `b` as well as setting the default - +there are in fact two ways in which this can go wrong if we don't do that: + +* The variables have too much precision - this will cause all arithmetic operations involving those types to be +promoted to the higher precision wasting precious calculation time. +* The variables have too little precision - this will cause expressions involving only those variables to be +calculated at the lower precision - for example if we calculate `exp(a)` internally, this will be evaluated at +the precision of `a`, and not the current default. + +Since our reference method carries out all calculations at the full precision requested, an obvious refinement +would be to calculate a first approximation to `double` precision and then to use Newton steps to refine it further. + +Our function begins the same as before: set the new default precision and then make copies of our arguments +at the correct precision. We then call `ibeta_inv` with all double precision arguments, promote the result +to an `mpfr_float` and perform Newton steps to obtain the result. Note that our termination condition is somewhat +cude: we simply assume that we have approximately 14 digits correct from the double-precision approximation and +that the precision doubles with each step. We also cheat, and use an internal Boost.Math function that calculates +['I[sub x](a, b)] and it's derivative in one go: + +*/ +mpfr_float beta_distribution_median_method_2(mpfr_float const& a_, mpfr_float const& b_, unsigned digits10) +{ + scoped_precision sp(digits10); + mpfr_float half(0.5), a(a_, digits10), b(b_, digits10); + mpfr_float guess = ibeta_inv((double)a, (double)b, 0.5); + unsigned current_digits = 14; + mpfr_float f, f1; + while (current_digits < digits10) + { + f = boost::math::detail::ibeta_imp(a, b, guess, boost::math::policies::policy<>(), false, true, &f1) - half; + guess -= f / f1; + current_digits *= 2; + } + return guess; +} +/*` +Before we refine the method further, it might be wise to take stock and see how method's 1 and 2 compare. +We'll ask them both for 1500 digit precision, and compare against the value produced by `ibeta_inv` at 1700 digits. +Here's what the results look like: + +[pre +Method 1 time = 0.611647 +Relative error: 2.99991e-1501 +Method 2 time = 0.646746 +Relative error: 7.55843e-1501 +] + +Clearly they are both equally accurate, but Method 1 is actually faster and our plan for improved performance +hasn't actually worked. It turns out that we're not actually comparing like with like, because `ibeta_inv` uses +Halley iteration internally which churns out more digits of precision rather more rapidly than Newton iteration. +So the time we save by refining an initial `double` approximation, then loose it again by taking more iterations +to get to the result. + +Time for a more refined approach. It follows the same form as Method 2, but now we set the working precision +within the Newton iteration loop, to just enough digits to cover the expected precision at each step. That means +we also create new copies of our arguments at the correct precision within the loop, and likewise change the precision +of the current `guess` each time through: + +*/ + +mpfr_float beta_distribution_median_method_3(mpfr_float const& a_, mpfr_float const& b_, unsigned digits10) +{ + mpfr_float guess = ibeta_inv((double)a_, (double)b_, 0.5); + unsigned current_digits = 14; + mpfr_float f(0, current_digits), f1(0, current_digits), delta(1); + while (current_digits < digits10) + { + current_digits *= 2; + scoped_precision sp((std::min)(current_digits, digits10)); + mpfr_float a(a_, mpfr_float::default_precision()), b(b_, mpfr_float::default_precision()); + guess.precision(mpfr_float::default_precision()); + f = boost::math::detail::ibeta_imp(a, b, guess, boost::math::policies::policy<>(), false, true, &f1) - 0.5f; + guess -= f / f1; + } + return guess; +} + +/*` +The new performance results look much more promising: + +[pre +Method 1 time = 0.591244 +Relative error: 2.99991e-1501 +Method 2 time = 0.622679 +Relative error: 7.55843e-1501 +Method 3 time = 0.143393 +Relative error: 4.03898e-1501 +] + +This time we're 4x faster than `ibeta_inv`, and no doubt that could be improved a little more by carefully +optimising the number of iterations and the method (Halley vs Newton) taken. + +Finally, here's the driver code for the above methods: + +*/ + +int main() +{ + try { + mpfr_float a(10), b(20); + + mpfr_float true_value = beta_distribution_median_method_1(a, b, 1700); + + stopwatch<std::chrono::high_resolution_clock> my_stopwatch; + + mpfr_float v1 = beta_distribution_median_method_1(a, b, 1500); + float hp_time = my_stopwatch.elapsed(); + std::cout << "Method 1 time = " << hp_time << std::endl; + std::cout << "Relative error: " << boost::math::relative_difference(v1, true_value) << std::endl; + + my_stopwatch.reset(); + mpfr_float v2 = beta_distribution_median_method_2(a, b, 1500); + hp_time = my_stopwatch.elapsed(); + std::cout << "Method 2 time = " << hp_time << std::endl; + std::cout << "Relative error: " << boost::math::relative_difference(v2, true_value) << std::endl; + + my_stopwatch.reset(); + mpfr_float v3 = beta_distribution_median_method_3(a, b, 1500); + hp_time = my_stopwatch.elapsed(); + std::cout << "Method 3 time = " << hp_time << std::endl; + std::cout << "Relative error: " << boost::math::relative_difference(v3, true_value) << std::endl; + } + catch (const std::exception& e) + { + std::cout << "Found exception with message: " << e.what() << std::endl; + } + return 0; +} +//] + diff --git a/src/boost/libs/multiprecision/example/mpfr_snips.cpp b/src/boost/libs/multiprecision/example/mpfr_snips.cpp new file mode 100644 index 00000000..e0ac6aeb --- /dev/null +++ b/src/boost/libs/multiprecision/example/mpfr_snips.cpp @@ -0,0 +1,40 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2011 John Maddock. 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 + +//[mpfr_eg +#include <boost/multiprecision/mpfr.hpp> +#include <boost/math/special_functions/gamma.hpp> +#include <iostream> + +int main() +{ + using namespace boost::multiprecision; + + // Operations at variable precision and no numeric_limits support: + mpfr_float a = 2; + mpfr_float::default_precision(1000); + std::cout << mpfr_float::default_precision() << std::endl; + std::cout << sqrt(a) << std::endl; // print root-2 + + // Operations at fixed precision and full numeric_limits support: + mpfr_float_100 b = 2; + std::cout << std::numeric_limits<mpfr_float_100>::digits << std::endl; + // We can use any C++ std lib function: + std::cout << log(b) << std::endl; // print log(2) + // We can also use any function from Boost.Math: + std::cout << boost::math::tgamma(b) << std::endl; + // These even work when the argument is an expression template: + std::cout << boost::math::tgamma(b * b) << std::endl; + + // Access the underlying data: + mpfr_t r; + mpfr_init(r); + mpfr_set(r, b.backend().data(), GMP_RNDN); + mpfr_clear(r); + return 0; +} +//] + + diff --git a/src/boost/libs/multiprecision/example/numeric_limits_snips.cpp b/src/boost/libs/multiprecision/example/numeric_limits_snips.cpp new file mode 100644 index 00000000..e114f0a2 --- /dev/null +++ b/src/boost/libs/multiprecision/example/numeric_limits_snips.cpp @@ -0,0 +1,470 @@ +// Copyright Paul A. Bristow 2013 +// Copyright John Maddock 2013 +// Copyright Christopher Kormanyos + +// 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) + +// Examples of numeric_limits usage as snippets for multiprecision documentation. + +// Includes text as Quickbook comments. + +#include <iostream> +#include <iomanip> +#include <string> +#include <sstream> +#include <limits> // numeric_limits +#include <iomanip> +#include <locale> +#include <boost/assert.hpp> + +#include <boost/math/constants/constants.hpp> +#include <boost/math/special_functions/nonfinite_num_facets.hpp> + +#include <boost/math/special_functions/factorials.hpp> +#include <boost/math/special_functions/next.hpp> +#include <boost/math/tools/precision.hpp> +#include <boost/multiprecision/cpp_dec_float.hpp> // is decimal. +#include <boost/multiprecision/cpp_bin_float.hpp> // is binary. + +#define BOOST_TEST_MAIN +#include <boost/test/unit_test.hpp> // Boost.Test +#include <boost/test/floating_point_comparison.hpp> + +static long double const log10Two = 0.30102999566398119521373889472449L; // log10(2.) + +template <typename T> +int max_digits10() +{ + int significand_digits = std::numeric_limits<T>::digits; + // BOOST_CONSTEXPR_OR_CONST int significand_digits = std::numeric_limits<T>::digits; + return static_cast<int>(ceil(1 + significand_digits * log10Two)); +} // template <typename T> int max_digits10() + +// Used to test max_digits10<>() function below. +//#define BOOST_NO_CXX11_NUMERIC_LIMITS + +BOOST_AUTO_TEST_CASE(test_numeric_limits_snips) +{ +#if !(defined(CI_SUPPRESS_KNOWN_ISSUES) && defined(BOOST_MSVC) && (BOOST_MSVC == 1600)) + try + { + +// Example of portable way to get `std::numeric_limits<T>::max_digits10`. +//[max_digits10_1 + +/*`For example, to be portable (including obselete platforms) for type `T` where `T` may be: + `float`, `double`, `long double`, `128-bit quad type`, `cpp_bin_float_50` ... +*/ + + typedef float T; + +#if defined BOOST_NO_CXX11_NUMERIC_LIMITS + // No max_digits10 implemented. + std::cout.precision(max_digits10<T>()); +#else + #if(_MSC_VER <= 1600) + // Wrong value for std::numeric_limits<float>::max_digits10. + std::cout.precision(max_digits10<T>()); + #else // Use the C++11 max_digits10. + std::cout.precision(std::numeric_limits<T>::max_digits10); + #endif +#endif + + std::cout << "std::cout.precision(max_digits10) = " << std::cout.precision() << std::endl; // 9 + + double x = 1.2345678901234567889; + + std::cout << "x = " << x << std::endl; // + +/*`which should output: + + std::cout.precision(max_digits10) = 9 + x = 1.23456789 +*/ + +//] [/max_digits10_1] + + { +//[max_digits10_2 + + double write = 2./3; // Any arbitrary value that cannot be represented exactly. + double read = 0; + std::stringstream s; + s.precision(std::numeric_limits<double>::digits10); // or `float64_t` for 64-bit IEE754 double. + s << write; + s >> read; + if(read != write) + { + std::cout << std::setprecision(std::numeric_limits<double>::digits10) + << read << " != " << write << std::endl; + } + +//] [/max_digits10_2] + // 0.666666666666667 != 0.666666666666667 + } + + { +//[max_digits10_3 + + double pi = boost::math::double_constants::pi; + std::cout.precision(std::numeric_limits<double>::max_digits10); + std::cout << pi << std::endl; // 3.1415926535897931 + +//] [/max_digits10_3] + } + { +//[max_digits10_4 +/*`and similarly for a much higher precision type: +*/ + + using namespace boost::multiprecision; + + typedef number<cpp_dec_float<50> > cpp_dec_float_50; // 50 decimal digits. + + using boost::multiprecision::cpp_dec_float_50; + + cpp_dec_float_50 pi = boost::math::constants::pi<cpp_dec_float_50>(); + std::cout.precision(std::numeric_limits<cpp_dec_float_50>::max_digits10); + std::cout << pi << std::endl; + // 3.141592653589793238462643383279502884197169399375105820974944592307816406 +//] [/max_digits10_4] + } + + { +//[max_digits10_5 + + for (int i = 2; i < 15; i++) + { + std::cout << std::setw(std::numeric_limits<int>::max_digits10) + << boost::math::factorial<double>(i) << std::endl; + } + +//] [/max_digits10_5] + } + + } + catch(std::exception ex) + { + std::cout << "Caught Exception " << ex.what() << std::endl; + } + + { +//[max_digits10_6 + + typedef double T; + + bool denorm = std::numeric_limits<T>::denorm_min() < (std::numeric_limits<T>::min)(); + BOOST_ASSERT(denorm); + +//] [/max_digits10_6] + } + + { + unsigned char c = 255; + std::cout << "char c = " << (int)c << std::endl; + } + + { +//[digits10_1 + std::cout + << std::setw(std::numeric_limits<short>::digits10 +1 +1) // digits10+1, and +1 for sign. + << std::showpos << (std::numeric_limits<short>::max)() // +32767 + << std::endl + << std::setw(std::numeric_limits<short>::digits10 +1 +1) + << (std::numeric_limits<short>::min)() << std::endl; // -32767 +//] [/digits10_1] + } + + { +//[digits10_2 + std::cout + << std::setw(std::numeric_limits<unsigned short>::digits10 +1 +1) // digits10+1, and +1 for sign. + << std::showpos << (std::numeric_limits<unsigned short>::max)() // 65535 + << std::endl + << std::setw(std::numeric_limits<unsigned short>::digits10 +1 +1) // digits10+1, and +1 for sign. + << (std::numeric_limits<unsigned short>::min)() << std::endl; // 0 +//] [/digits10_2] + } + + std::cout <<std::noshowpos << std::endl; + + { +//[digits10_3 + std::cout.precision(std::numeric_limits<double>::max_digits10); + double d = 1e15; + double dp1 = d+1; + std::cout << d << "\n" << dp1 << std::endl; + // 1000000000000000 + // 1000000000000001 + std::cout << dp1 - d << std::endl; // 1 +//] [/digits10_3] + } + + { +//[digits10_4 + std::cout.precision(std::numeric_limits<double>::max_digits10); + double d = 1e16; + double dp1 = d+1; + std::cout << d << "\n" << dp1 << std::endl; + // 10000000000000000 + // 10000000000000000 + std::cout << dp1 - d << std::endl; // 0 !!! +//] [/digits10_4] + } + + { +//[epsilon_1 + std::cout.precision(std::numeric_limits<double>::max_digits10); + double d = 1.; + double eps = std::numeric_limits<double>::epsilon(); + double dpeps = d+eps; + std::cout << std::showpoint // Ensure all trailing zeros are shown. + << d << "\n" // 1.0000000000000000 + << dpeps << std::endl; // 2.2204460492503131e-016 + std::cout << dpeps - d // 1.0000000000000002 + << std::endl; +//] [epsilon_1] + } + + { +//[epsilon_2 + double one = 1.; + double nad = boost::math::float_next(one); + std::cout << nad << "\n" // 1.0000000000000002 + << nad - one // 2.2204460492503131e-016 + << std::endl; +//] [epsilon_2] + } + { +//[epsilon_3 + std::cout.precision(std::numeric_limits<double>::max_digits10); + double d = 1.; + double eps = std::numeric_limits<double>::epsilon(); + double dpeps = d + eps/2; + + std::cout << std::showpoint // Ensure all trailing zeros are shown. + << dpeps << "\n" // 1.0000000000000000 + << eps/2 << std::endl; // 1.1102230246251565e-016 + std::cout << dpeps - d // 0.00000000000000000 + << std::endl; +//] [epsilon_3] + } + + { + typedef double RealType; +//[epsilon_4 +/*`A tolerance might be defined using this version of epsilon thus: +*/ + RealType tolerance = boost::math::tools::epsilon<RealType>() * 2; +//] [epsilon_4] + } + + { +//[digits10_5 + -(std::numeric_limits<double>::max)() == std::numeric_limits<double>::lowest(); +//] [/digits10_5] +// warning C4553: '==': result of expression not used; did you intend '='? is spurious. + } + + { +//[denorm_min_1 + std::cout.precision(std::numeric_limits<double>::max_digits10); + if (std::numeric_limits<double>::has_denorm == std::denorm_present) + { + double d = std::numeric_limits<double>::denorm_min(); + + std::cout << d << std::endl; // 4.9406564584124654e-324 + + int exponent; + + double significand = frexp(d, &exponent); + std::cout << "exponent = " << std::hex << exponent << std::endl; // fffffbcf + std::cout << "significand = " << std::hex << significand << std::endl; // 0.50000000000000000 + } + else + { + std::cout << "No denormalization. " << std::endl; + } +//] [denorm_min_1] + } + + { +//[round_error_1 + double round_err = std::numeric_limits<double>::epsilon() // 2.2204460492503131e-016 + * std::numeric_limits<double>::round_error(); // 1/2 + std::cout << round_err << std::endl; // 1.1102230246251565e-016 +//] [/round_error_1] + } + + { + typedef double T; +//[tolerance_1 +/*`For example, if we want a tolerance that might suit about 9 arithmetical operations, +say sqrt(9) = 3, we could define: +*/ + + T tolerance = 3 * std::numeric_limits<T>::epsilon(); + +/*`This is very widely used in Boost.Math testing +with Boost.Test's macro `BOOST_CHECK_CLOSE_FRACTION` +*/ + + T expected = 1.0; + T calculated = 1.0 + std::numeric_limits<T>::epsilon(); + + BOOST_CHECK_CLOSE_FRACTION(expected, calculated, tolerance); + +//] [/tolerance_1] + } + +#if !(defined(CI_SUPPRESS_KNOWN_ISSUES) && defined(__GNUC__) && defined(_WIN32)) + { +//[tolerance_2 + + using boost::multiprecision::number; + using boost::multiprecision::cpp_dec_float; + using boost::multiprecision::et_off; + + typedef number<cpp_dec_float<50>, et_off > cpp_dec_float_50; // 50 decimal digits. +/*`[note that Boost.Test does not yet allow floating-point comparisons with expression templates on, +so the default expression template parameter has been replaced by `et_off`.] +*/ + + cpp_dec_float_50 tolerance = 3 * std::numeric_limits<cpp_dec_float_50>::epsilon(); + cpp_dec_float_50 expected = boost::math::constants::two_pi<cpp_dec_float_50>(); + cpp_dec_float_50 calculated = 2 * boost::math::constants::pi<cpp_dec_float_50>(); + + BOOST_CHECK_CLOSE_FRACTION(expected, calculated, tolerance); + +//] [/tolerance_2] + } + + { +//[tolerance_3 + + using boost::multiprecision::cpp_bin_float_quad; + + cpp_bin_float_quad tolerance = 3 * std::numeric_limits<cpp_bin_float_quad>::epsilon(); + cpp_bin_float_quad expected = boost::math::constants::two_pi<cpp_bin_float_quad>(); + cpp_bin_float_quad calculated = 2 * boost::math::constants::pi<cpp_bin_float_quad>(); + + BOOST_CHECK_CLOSE_FRACTION(expected, calculated, tolerance); + +//] [/tolerance_3] + } + + { +//[tolerance_4 + + using boost::multiprecision::cpp_bin_float_oct; + + cpp_bin_float_oct tolerance = 3 * std::numeric_limits<cpp_bin_float_oct>::epsilon(); + cpp_bin_float_oct expected = boost::math::constants::two_pi<cpp_bin_float_oct>(); + cpp_bin_float_oct calculated = 2 * boost::math::constants::pi<cpp_bin_float_oct>(); + + BOOST_CHECK_CLOSE_FRACTION(expected, calculated, tolerance); + +//] [/tolerance_4] + } + + { +//[nan_1] + +/*`NaN can be used with binary multiprecision types like `cpp_bin_float_quad`: +*/ + using boost::multiprecision::cpp_bin_float_quad; + + if (std::numeric_limits<cpp_bin_float_quad>::has_quiet_NaN == true) + { + cpp_bin_float_quad tolerance = 3 * std::numeric_limits<cpp_bin_float_quad>::epsilon(); + + cpp_bin_float_quad NaN = std::numeric_limits<cpp_bin_float_quad>::quiet_NaN(); + std::cout << "cpp_bin_float_quad NaN is " << NaN << std::endl; // cpp_bin_float_quad NaN is nan + + cpp_bin_float_quad expected = NaN; + cpp_bin_float_quad calculated = 2 * NaN; + // Comparisons of NaN's always fail: + bool b = expected == calculated; + std::cout << b << std::endl; + BOOST_CHECK_NE(expected, expected); + BOOST_CHECK_NE(expected, calculated); + } + else + { + std::cout << "Type " << typeid(cpp_bin_float_quad).name() << " does not have NaNs!" << std::endl; + } + +//] [/nan_1] + } + + { +//[facet_1] + +/*` +See [@boost:/libs/math/example/nonfinite_facet_sstream.cpp] +and we also need + + #include <boost/math/special_functions/nonfinite_num_facets.hpp> + +Then we can equally well use a multiprecision type cpp_bin_float_quad: + +*/ + using boost::multiprecision::cpp_bin_float_quad; + + typedef cpp_bin_float_quad T; + + using boost::math::nonfinite_num_put; + using boost::math::nonfinite_num_get; + { + std::locale old_locale; + std::locale tmp_locale(old_locale, new nonfinite_num_put<char>); + std::locale new_locale(tmp_locale, new nonfinite_num_get<char>); + std::stringstream ss; + ss.imbue(new_locale); + T inf = std::numeric_limits<T>::infinity(); + ss << inf; // Write out. + BOOST_ASSERT(ss.str() == "inf"); + T r; + ss >> r; // Read back in. + BOOST_ASSERT(inf == r); // Confirms that the floating-point values really are identical. + std::cout << "infinity output was " << ss.str() << std::endl; + std::cout << "infinity input was " << r << std::endl; + } + +/*` +`` + infinity output was inf + infinity input was inf +`` +Similarly we can do the same with NaN (except that we cannot use `assert` (because any comparisons with NaN always return false). +*/ + { + std::locale old_locale; + std::locale tmp_locale(old_locale, new nonfinite_num_put<char>); + std::locale new_locale(tmp_locale, new nonfinite_num_get<char>); + std::stringstream ss; + ss.imbue(new_locale); + T n; + T NaN = std::numeric_limits<T>::quiet_NaN(); + ss << NaN; // Write out. + BOOST_ASSERT(ss.str() == "nan"); + std::cout << "NaN output was " << ss.str() << std::endl; + ss >> n; // Read back in. + std::cout << "NaN input was " << n << std::endl; + } +/*` +`` + NaN output was nan + NaN input was nan +`` +*/ +//] [/facet_1] + } + +#endif +#endif +} // BOOST_AUTO_TEST_CASE(test_numeric_limits_snips) + diff --git a/src/boost/libs/multiprecision/example/random_snips.cpp b/src/boost/libs/multiprecision/example/random_snips.cpp new file mode 100644 index 00000000..e295564b --- /dev/null +++ b/src/boost/libs/multiprecision/example/random_snips.cpp @@ -0,0 +1,315 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2011 John Maddock. 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/multiprecision/cpp_int.hpp> +#include <boost/multiprecision/cpp_bin_float.hpp> +#include <boost/random.hpp> +#include <boost/scoped_ptr.hpp> +#include <iostream> +#include <iomanip> + +void t1() +{ +//[random_eg1 +//=#include <boost/multiprecision/cpp_int.hpp> +//=#include <boost/random.hpp> +//= +//=int main() +//={ + using namespace boost::multiprecision; + using namespace boost::random; + + // + // Declare our random number generator type, the underlying generator + // is the Mersenne twister mt19937 engine, and we'll generate 256 bit + // random values, independent_bits_engine will make multiple calls + // to the underlying engine until we have the requested number of bits: + // + typedef independent_bits_engine<mt19937, 256, cpp_int> generator_type; + generator_type gen; + // + // Generate some values: + // + std::cout << std::hex << std::showbase; + for(unsigned i = 0; i < 10; ++i) + std::cout << gen() << std::endl; + // + // Alternatively if we wish to generate random values in a fixed-precision + // type, then we must use an unsigned type in order to adhere to the + // conceptual requirements of the generator: + // + typedef independent_bits_engine<mt19937, 512, uint512_t> generator512_type; + generator512_type gen512; + // + // Generate some 1024-bit unsigned values: + // + std::cout << std::hex << std::showbase; + for(unsigned i = 0; i < 10; ++i) + std::cout << gen512() << std::endl; + //= return 0; +//=} +//] +} + +// +// Output from t1() is: +//[random_eg1_out +/*`[pre +0xD091BB5C22AE9EF6E7E1FAEED5C31F792082352CF807B7DFE9D300053895AFE1 +0xA1E24BBA4EE4092B18F868638C16A625474BA8C43039CD1A8C006D5FFE2D7810 +0xF51F2AE7FF1816E4F702EF59F7BADAFA285954A1B9D09511F878C4B3FB2A0137 +0xF508E4AA1C1FE6527C419418CC50AA59CCDF2E5C4C0A1F3B2452A9DC01397D8D +0x6BF88C311CCA797AEA6DA4AEA3C78807CACE1969E0E0D4ADF5A14BAB80F00988 +0xA7DE9F4CCC450CBA0924668F5C7DC380D96089C53640AC4CEF1A2E6DAE6D9426 +0xADC1965B6613BA46C1FB41C2BD9B0ECDBE3DEDFC7989C8EE6468FD6E6C0DF032 +0xA7CD66342C826D8B2BD2E4124D4A2DBEB4BF6FA7CC1A89590826328251097330 +0x46E46CB0DF577EC20BD1E364262C556418DDA0C9FE7B45D9D2CE21C9D268409A +0xB1E049E1200BFA47512D6E73C3851EEEF341C0817D973E4808D17554A9E20D28 +0xD091BB5C22AE9EF6E7E1FAEED5C31F792082352CF807B7DFE9D300053895AFE1A1E24BBA4EE4092B18F868638C16A625474BA8C43039CD1A8C006D5FFE2D7810 +0xF51F2AE7FF1816E4F702EF59F7BADAFA285954A1B9D09511F878C4B3FB2A0137F508E4AA1C1FE6527C419418CC50AA59CCDF2E5C4C0A1F3B2452A9DC01397D8D +0x6BF88C311CCA797AEA6DA4AEA3C78807CACE1969E0E0D4ADF5A14BAB80F00988A7DE9F4CCC450CBA0924668F5C7DC380D96089C53640AC4CEF1A2E6DAE6D9426 +0xADC1965B6613BA46C1FB41C2BD9B0ECDBE3DEDFC7989C8EE6468FD6E6C0DF032A7CD66342C826D8B2BD2E4124D4A2DBEB4BF6FA7CC1A89590826328251097330 +0x46E46CB0DF577EC20BD1E364262C556418DDA0C9FE7B45D9D2CE21C9D268409AB1E049E1200BFA47512D6E73C3851EEEF341C0817D973E4808D17554A9E20D28 +0x70518CE6203AC30361ADD0AB35D0430CC3F8E8920D1C8509CB92388E095436BF2FD6E20868A29AF97D61330B753EC6FC7211EFEA7CD15133A574C4FFCB41F198 +0xB598EEF6EBBE7347C1332568CEBA5A7046A99459B4AD9F11AE00FEAA00B8B573A7B480B6B5F0B06C29A0EC27A4DAA0101E76A1C574BE91337F94C950C61F6ED6 +0xF5B1C7A192E195F8572384D4E0732C8895D41B68CEE496C3394BBD52048CD47CC05309BED23D2D63414DE9C5D2229F23818666A3F0A8B109B2F6B12769A48341 +0xE4123C566C548C8FF5941F6194B993AA8C1651342876763C237CE42EC300D11B263821CA3AEB820241EC0F84CF4AC36DD7393EE6FD0FC06A4118A30A551B54A4 +0xD074F86F4CC1C54A3E57A70303774CDAEDE43895379CE62759988939E8490DDC325410E1D9352F6A4047080AF47C081D9DB51A85C765D71F79297527FCCA2773 +] +*/ +//] + + +void t2() +{ + std::cout << std::dec; +//[random_eg2 +//=#include <boost/multiprecision/cpp_int.hpp> +//=#include <boost/random.hpp> +//= +//=int main() +//={ + using namespace boost::multiprecision; + using namespace boost::random; + + // + // Generate integers in a given range using uniform_int, + // the underlying generator is invoked multiple times + // to generate enough bits: + // + mt19937 mt; + uniform_int_distribution<cpp_int> ui(-(cpp_int(1) << 256), cpp_int(1) << 256); + // + // Generate the numbers: + // + for(unsigned i = 0; i < 10; ++i) + std::cout << ui(mt) << std::endl; + +//= return 0; +//=} +//] +} +//[random_eg2_out +/*` +Program output is + +[pre +25593993629538149833210527544371584707508847463356155903670894544241785158492 +12721121657520147247744796431842326146296294180809160027132416389225539366745 +106034929479008809862776424170460808190085984129117168803272987114325199071833 +86048861429530654936263414134573980939351899046345384016090167510299251354700 +-23473382144925885755951447143660880642389842563343761080591177733698450031250 +76840269649240973945508128641415259490679375154523618053296924666747244530145 +21638369166612496703991271955994563624044383325105383029306009417224944272131 +18829152205014764576551421737727569993966577957447887116062495161081023584880 +101521572847669971701030312596819435590097618913255156117898217707115132658117 +-97490271301923067621481012355971422109456300816856752380346627103308328292057 +] +*/ +//] + +void t3() +{ +//[random_eg3 +//=#include <boost/multiprecision/cpp_bin_float.hpp> +//=#include <boost/random.hpp> +//= +//=int main() +//={ + using namespace boost::multiprecision; + using namespace boost::random; + + mt19937 gen; + // + // Generate the values: + // + std::cout << std::setprecision(50); + for(unsigned i = 0; i < 20; ++i) + std::cout << generate_canonical<cpp_bin_float_50, std::numeric_limits<cpp_bin_float_50>::digits>(gen) << std::endl; +//= return 0; +//=} +//] +} + +//[random_eg3_out +/*` +Which produces the following output: + +[pre +0.96886777112423135248554451482797431507115448261086 +0.54722059636785192454525760726084778627750790023546 +0.99646132554800874317788284808573062871409279729804 +0.98110969177693891782396443737643892769773768718591 +0.29702944955795083040856753579705872634075574515969 +0.63976335709815275010379796044374742646738557798647 +0.79792861516022605265555700991255998690336456180995 +0.68135953856026596523755400091345037778580909233387 +0.47475868061723477935404326837783394169122045199915 +0.30191312687731969398296589840622989141067852863748 +0.87242882006730022427155209451091472382531795659709 +0.82190326480741096300318873712966555706035846579562 +0.49058903962146072778707295967429263659897501512813 +0.2102090745190061764133345429475530760261103345204 +0.4087311609617603484960794513055502599728804206333 +0.79397497154919267900450180642484943996546102712187 +0.70577425166871982574205252142383800792823003687121 +0.64396095652194035523385641523010248768636064728226 +0.5737546665965914620678634509134819579811035412969 +0.017773895576552474810236796736785695789752666554273 +] +*/ +//] + +void t4() +{ + std::cout << std::endl; +//[random_eg4 +//=#include <boost/multiprecision/cpp_bin_float.hpp> +//=#include <boost/multiprecision/cpp_int.hpp> +//=#include <boost/random.hpp> +//= +//=int main() +//={ + using namespace boost::multiprecision; + using namespace boost::random; + // + // Generate some distruted values: + // + uniform_real_distribution<cpp_bin_float_50> ur(-20, 20); + gamma_distribution<cpp_bin_float_50> gd(20); + independent_bits_engine<mt19937, std::numeric_limits<cpp_bin_float_50>::digits, cpp_int> gen; + // + // Generate some values: + // + std::cout << std::setprecision(50); + for(unsigned i = 0; i < 20; ++i) + std::cout << ur(gen) << std::endl; + for(unsigned i = 0; i < 20; ++i) + std::cout << gd(gen) << std::endl; +//= return 0; +//=} +//] +} + +//[random_eg4_out +/*` +Which produces the following output: + +[pre +-18.576837157065858312137736538355805944098004018928 +4.5605477000094480453928920098152026546185388161216 +-1.7611402252150150370944527411235180945558276280598 +-2.471338289511354190492328039842914272146783953149 +-7.4131520453411321647183692139916357315276121488316 +-9.192739117661751364518299455475684051782402347659 +7.0126880787149555595443325648941661436898526919013 +2.8554749162054097111723076181877881960039268668423 +14.390501287552165467965587841551705310012046701036 +-8.9747073123748752412086051960748002945548570524149 +-8.1305063133718605220959174700954037986278348616362 +9.5496899464463627949564295930962040525540578754312 +-15.309681742947663333436391348699943078942921692008 +2.0454914298189175280771944784358385982869708951824 +-10.069253024538932382193363493367304983742246396276 +13.449212808583153116670057807764145176004060370818 +-6.0065092542772507561228141992257782449634820245355 +15.00971466974838379824678369267201922989930663822 +16.158514812070905438581736305533045434508525979205 +-2.1531361299576399413547008719541457739794964378093 +19.398278792113040046930806838893737245011219380822 +12.965216582396067073600685365545292876001524716225 +19.561779374349650983983836397553672788578622096947 +15.982213641588944604037715576313848977716540941271 +23.96044616946856385664151481695038833903083043492 +21.054716943622792848187523422423642819628010070375 +18.596078774135209530930707331338838805575875990091 +19.539530839287848627426769425090194390388333335812 +17.176133236359396942946640290935498641489373354297 +16.228802394876800099035133760539461530246286999827 +23.63807160907473465631049083277558060813997674519 +12.838499607321990428122225501321564153572478845401 +16.878362445712403300584931374939967549572637230102 +20.646246409377134464856282996941395597420615529803 +16.602429236226052406561338766554127142762673418695 +21.680007865714197450495711030406314524681744024329 +21.038948660115771777833205901845639760348321521616 +30.494499676527802078320016654058105593076348727966 +18.704734464995637480940828829962787676146589788572 +22.502216997171061548799304902323434654678156658236 +] +*/ +//] + +void t5() +{ +//[random_eg5 +//=#include <boost/multiprecision/cpp_bin_float.hpp> +//=#include <boost/random.hpp> +//=#include <boost/scoped_ptr.hpp> +//= +//=int main() +//={ + using namespace boost::multiprecision; + using namespace boost::random; + // + // Generate some multiprecision values, note that the generator is so large + // that we have to allocate it on the heap, otherwise we may run out of + // stack space! We could avoid this by using a floating point type which + // allocates it's internal storage on the heap - cpp_bin_float will do + // this with the correct template parameters, as will the GMP or MPFR + // based reals. + // + typedef lagged_fibonacci_01_engine<cpp_bin_float_50, 48, 44497, 21034 > big_fib_gen; + boost::scoped_ptr<big_fib_gen> pgen(new big_fib_gen); + // + // Generate some values: + // + std::cout << std::setprecision(50); + for(unsigned i = 0; i < 20; ++i) + std::cout << (*pgen)() << std::endl; + // + // try again with a ranlux generator, this is not quite so large + // so we can use the heap this time: + // + typedef subtract_with_carry_01_engine<cpp_bin_float_50, std::numeric_limits<cpp_bin_float_50>::digits - 5, 10, 24 > ranlux_big_base_01; + typedef discard_block_engine< ranlux_big_base_01, 389, 24 > big_ranlux; + big_ranlux rg; + for(unsigned i = 0; i < 20; ++i) + std::cout << rg() << std::endl; +//= return 0; +//=} +//] +} + +int main() +{ + t1(); + t2(); + t3(); + t4(); + t5(); + return 0; +} + diff --git a/src/boost/libs/multiprecision/example/safe_prime.cpp b/src/boost/libs/multiprecision/example/safe_prime.cpp new file mode 100644 index 00000000..dbe40ef2 --- /dev/null +++ b/src/boost/libs/multiprecision/example/safe_prime.cpp @@ -0,0 +1,45 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2012 John Maddock. 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 + +//[safe_prime + +#include <boost/multiprecision/cpp_int.hpp> +#include <boost/multiprecision/miller_rabin.hpp> +#include <iostream> +#include <iomanip> + +int main() +{ + using namespace boost::random; + using namespace boost::multiprecision; + + typedef cpp_int int_type; + mt11213b base_gen(clock()); + independent_bits_engine<mt11213b, 256, int_type> gen(base_gen); + // + // We must use a different generator for the tests and number generation, otherwise + // we get false positives. + // + mt19937 gen2(clock()); + + for(unsigned i = 0; i < 100000; ++i) + { + int_type n = gen(); + if(miller_rabin_test(n, 25, gen2)) + { + // Value n is probably prime, see if (n-1)/2 is also prime: + std::cout << "We have a probable prime with value: " << std::hex << std::showbase << n << std::endl; + if(miller_rabin_test((n-1)/2, 25, gen2)) + { + std::cout << "We have a safe prime with value: " << std::hex << std::showbase << n << std::endl; + return 0; + } + } + } + std::cout << "Ooops, no safe primes were found - probably a bad choice of seed values!" << std::endl; + return 0; +} + +//] diff --git a/src/boost/libs/multiprecision/example/tommath_snips.cpp b/src/boost/libs/multiprecision/example/tommath_snips.cpp new file mode 100644 index 00000000..f3b817bd --- /dev/null +++ b/src/boost/libs/multiprecision/example/tommath_snips.cpp @@ -0,0 +1,84 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2011 John Maddock. 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/multiprecision/tommath.hpp> +#include <iostream> + +void t1() +{ +//[tommath_eg +//=#include <boost/multiprecision/tommath.hpp> +//=#include <iostream> +//= +//=int main() +//={ + boost::multiprecision::tom_int v = 1; + + // Do some arithmetic: + for(unsigned i = 1; i <= 1000; ++i) + v *= i; + + std::cout << v << std::endl; // prints 1000! + std::cout << std::hex << v << std::endl; // prints 1000! in hex format + + try{ + std::cout << std::hex << -v << std::endl; // Ooops! can't print a negative value in hex format! + } + catch(const std::runtime_error& e) + { + std::cout << e.what() << std::endl; + } + + try{ + // v is not a 2's complement type, bitwise operations are only supported + // on positive values: + v = -v & 2; + } + catch(const std::runtime_error& e) + { + std::cout << e.what() << std::endl; + } + +//= return 0; +//=} +//] +} + +void t3() +{ +//[mp_rat_eg +//=#include <boost/multiprecision/tommath.hpp> +//=#include <iostream> +//= +//=int main() +//={ + using namespace boost::multiprecision; + + tom_rational v = 1; + + // Do some arithmetic: + for(unsigned i = 1; i <= 1000; ++i) + v *= i; + v /= 10; + + std::cout << v << std::endl; // prints 1000! / 10 + std::cout << numerator(v) << std::endl; + std::cout << denominator(v) << std::endl; + + tom_rational w(2, 3); // Component wise constructor + std::cout << w << std::endl; // prints 2/3 + +//= return 0; +//=} +//] +} + +int main() +{ + t1(); + t3(); + return 0; +} + |