erf.hpp

来自「Boost provides free peer-reviewed portab」· HPP 代码 · 共 1,085 行 · 第 1/3 页

HPP
1,085
字号
//  (C) Copyright John Maddock 2006.//  Use, modification and distribution are subject to the//  Boost Software License, Version 1.0. (See accompanying file//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)#ifndef BOOST_MATH_SPECIAL_ERF_HPP#define BOOST_MATH_SPECIAL_ERF_HPP#ifdef _MSC_VER#pragma once#endif#include <boost/math/special_functions/math_fwd.hpp>#include <boost/math/tools/config.hpp>#include <boost/math/special_functions/gamma.hpp>#include <boost/math/tools/roots.hpp>#include <boost/math/policies/error_handling.hpp>namespace boost{ namespace math{namespace detail{//// Asymptotic series for large z://template <class T>struct erf_asympt_series_t{   erf_asympt_series_t(T z) : xx(2 * -z * z), tk(1)   {      BOOST_MATH_STD_USING      result = -exp(-z * z) / sqrt(boost::math::constants::pi<T>());      result /= z;   }   typedef T result_type;   T operator()()   {      BOOST_MATH_STD_USING      T r = result;      result *= tk / xx;      tk += 2;      if( fabs(r) < fabs(result))         result = 0;      return r;   }private:   T result;   T xx;   int tk;};//// How large z has to be in order to ensure that the series converges://template <class T>inline float erf_asymptotic_limit_N(const T&){   return (std::numeric_limits<float>::max)();}inline float erf_asymptotic_limit_N(const mpl::int_<24>&){   return 2.8F;}inline float erf_asymptotic_limit_N(const mpl::int_<53>&){   return 4.3F;}inline float erf_asymptotic_limit_N(const mpl::int_<64>&){   return 4.8F;}inline float erf_asymptotic_limit_N(const mpl::int_<106>&){   return 6.5F;}inline float erf_asymptotic_limit_N(const mpl::int_<113>&){   return 6.8F;}template <class T, class Policy>inline T erf_asymptotic_limit(){   typedef typename policies::precision<T, Policy>::type precision_type;   typedef typename mpl::if_<      mpl::less_equal<precision_type, mpl::int_<24> >,      typename mpl::if_<         mpl::less_equal<precision_type, mpl::int_<0> >,         mpl::int_<0>,         mpl::int_<24>      >::type,      typename mpl::if_<         mpl::less_equal<precision_type, mpl::int_<53> >,         mpl::int_<53>,         typename mpl::if_<            mpl::less_equal<precision_type, mpl::int_<64> >,            mpl::int_<64>,            typename mpl::if_<               mpl::less_equal<precision_type, mpl::int_<106> >,               mpl::int_<106>,               typename mpl::if_<                  mpl::less_equal<precision_type, mpl::int_<113> >,                  mpl::int_<113>,                  mpl::int_<0>               >::type            >::type         >::type      >::type   >::type tag_type;   return erf_asymptotic_limit_N(tag_type());}template <class T, class Policy, class Tag>T erf_imp(T z, bool invert, const Policy& pol, const Tag& t){   BOOST_MATH_STD_USING   BOOST_MATH_INSTRUMENT_CODE("Generic erf_imp called");   if(z < 0)   {      if(!invert)         return -erf_imp(-z, invert, pol, t);      else         return 1 + erf_imp(-z, false, pol, t);   }   T result;   if(!invert && (z > detail::erf_asymptotic_limit<T, Policy>()))   {      detail::erf_asympt_series_t<T> s(z);      boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();      result = boost::math::tools::sum_series(s, policies::digits<T, Policy>(), max_iter, 1);      policies::check_series_iterations("boost::math::erf<%1%>(%1%, %1%)", max_iter, pol);   }   else   {      T x = z * z;      if(x < 0.6)      {         // Compute P:         result = z * exp(-x);         result /= sqrt(boost::math::constants::pi<T>());         if(result != 0)            result *= 2 * detail::lower_gamma_series(T(0.5f), x, pol);      }      else if(x < 1.1f)      {         // Compute Q:         invert = !invert;         result = tgamma_small_upper_part(T(0.5f), x, pol);         result /= sqrt(boost::math::constants::pi<T>());      }      else      {         // Compute Q:         invert = !invert;         result = z * exp(-x);         result /= sqrt(boost::math::constants::pi<T>());         result *= upper_gamma_fraction(T(0.5f), x, policies::digits<T, Policy>());      }   }   if(invert)      result = 1 - result;   return result;}template <class T, class Policy>T erf_imp(T z, bool invert, const Policy& pol, const mpl::int_<53>& t){   BOOST_MATH_STD_USING   BOOST_MATH_INSTRUMENT_CODE("53-bit precision erf_imp called");   if(z < 0)   {      if(!invert)         return -erf_imp(-z, invert, pol, t);      else if(z < -0.5)         return 2 - erf_imp(-z, invert, pol, t);      else         return 1 + erf_imp(-z, false, pol, t);   }   T result;   //   // Big bunch of selection statements now to pick   // which implementation to use,   // try to put most likely options first:   //   if(z < 0.5)   {      //      // We're going to calculate erf:      //      if(z == 0)      {         result = T(0);      }      else if(z < 1e-10)      {         result = static_cast<T>(z * 1.125f + z * 0.003379167095512573896158903121545171688L);      }      else      {         // Maximum Deviation Found:                     1.561e-17         // Expected Error Term:                         1.561e-17         // Maximum Relative Change in Control Points:   1.155e-04         // Max Error found at double precision =        2.961182e-17         static const T Y = 1.044948577880859375f;         static const T P[] = {                0.0834305892146531832907L,            -0.338165134459360935041L,            -0.0509990735146777432841L,            -0.00772758345802133288487L,            -0.000322780120964605683831L,         };         static const T Q[] = {                1L,            0.455004033050794024546L,            0.0875222600142252549554L,            0.00858571925074406212772L,            0.000370900071787748000569L,         };         result = z * (Y + tools::evaluate_polynomial(P, z * z) / tools::evaluate_polynomial(Q, z * z));      }   }   else if((z < 14) || ((z < 28) && invert))   {      //      // We'll be calculating erfc:      //      invert = !invert;      if(z < 1.5f)      {         // Maximum Deviation Found:                     3.702e-17         // Expected Error Term:                         3.702e-17         // Maximum Relative Change in Control Points:   2.845e-04         // Max Error found at double precision =        4.841816e-17         static const T Y = 0.405935764312744140625f;         static const T P[] = {                -0.098090592216281240205L,            0.178114665841120341155L,            0.191003695796775433986L,            0.0888900368967884466578L,            0.0195049001251218801359L,            0.00180424538297014223957L,         };         static const T Q[] = {                1L,            1.84759070983002217845L,            1.42628004845511324508L,            0.578052804889902404909L,            0.12385097467900864233L,            0.0113385233577001411017L,            0.337511472483094676155e-5L,         };         result = Y + tools::evaluate_polynomial(P, z - 0.5) / tools::evaluate_polynomial(Q, z - 0.5);         result *= exp(-z * z) / z;      }      else if(z < 2.5f)      {         // Max Error found at double precision =        6.599585e-18         // Maximum Deviation Found:                     3.909e-18         // Expected Error Term:                         3.909e-18         // Maximum Relative Change in Control Points:   9.886e-05         static const T Y = 0.50672817230224609375f;         static const T P[] = {                -0.0243500476207698441272L,            0.0386540375035707201728L,            0.04394818964209516296L,            0.0175679436311802092299L,            0.00323962406290842133584L,            0.000235839115596880717416L,         };         static const T Q[] = {                1L,            1.53991494948552447182L,            0.982403709157920235114L,            0.325732924782444448493L,            0.0563921837420478160373L,            0.00410369723978904575884L,         };         result = Y + tools::evaluate_polynomial(P, z - 1.5) / tools::evaluate_polynomial(Q, z - 1.5);         result *= exp(-z * z) / z;      }      else if(z < 4.5f)      {         // Maximum Deviation Found:                     1.512e-17         // Expected Error Term:                         1.512e-17         // Maximum Relative Change in Control Points:   2.222e-04         // Max Error found at double precision =        2.062515e-17         static const T Y = 0.5405750274658203125f;         static const T P[] = {                0.00295276716530971662634L,            0.0137384425896355332126L,            0.00840807615555585383007L,            0.00212825620914618649141L,            0.000250269961544794627958L,            0.113212406648847561139e-4L,         };         static const T Q[] = {                1L,            1.04217814166938418171L,            0.442597659481563127003L,            0.0958492726301061423444L,            0.0105982906484876531489L,            0.000479411269521714493907L,         };         result = Y + tools::evaluate_polynomial(P, z - 3.5) / tools::evaluate_polynomial(Q, z - 3.5);         result *= exp(-z * z) / z;      }      else      {         // Max Error found at double precision =        2.997958e-17         // Maximum Deviation Found:                     2.860e-17         // Expected Error Term:                         2.859e-17         // Maximum Relative Change in Control Points:   1.357e-05         static const T Y = 0.5579090118408203125f;         static const T P[] = {                0.00628057170626964891937L,            0.0175389834052493308818L,            -0.212652252872804219852L,            -0.687717681153649930619L,            -2.5518551727311523996L,            -3.22729451764143718517L,            -2.8175401114513378771L,         };         static const T Q[] = {                1L,            2.79257750980575282228L,            11.0567237927800161565L,            15.930646027911794143L,            22.9367376522880577224L,            13.5064170191802889145L,            5.48409182238641741584L,         };         result = Y + tools::evaluate_polynomial(P, 1 / z) / tools::evaluate_polynomial(Q, 1 / z);         result *= exp(-z * z) / z;      }   }   else   {      //      // Any value of z larger than 28 will underflow to zero:      //      result = 0;      invert = !invert;   }   if(invert)   {      result = 1 - result;   }   return result;} // template <class T, class L>T erf_imp(T z, bool invert, const L& l, const mpl::int_<53>& t)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?