Eup*_*lle 6 c++ math boost distribution numerical-methods
有没有关于boost的erf函数背后算法的详细信息?该模块的文档不是很精确.我发现的是几种方法混合在一起.对我来说,它看起来像Abramowitz和Stegun的变种.
塞巴斯蒂安
Boost Math Toolkit的文档有很多参考文献,其中包括Abramowitz和Stegun.的叔-功能接口包含一个策略可用于控制数值精度(以及因此它的运行时间复杂度)的模板的参数.
#include <boost/math/special_functions/erf.hpp>
namespace boost{ namespace math{
template <class T>
calculated-result-type erf(T z);
template <class T, class Policy>
calculated-result-type erf(T z, const Policy&);
template <class T>
calculated-result-type erfc(T z);
template <class T, class Policy>
calculated-result-type erfc(T z, const Policy&);
}} // namespaces
Run Code Online (Sandbox Code Playgroud)
更新:
在下面提供的erf-function参考的"Implementation"部分的逐字副本下面:
履行
这些函数的所有版本首先使用通常的反射公式使其参数为正:
erf(-z) = 1 - erf(z);
erfc(-z) = 2 - erfc(z); // preferred when -z < -0.5
erfc(-z) = 1 + erf(z); // preferred when -0.5 <= -z < 0
Run Code Online (Sandbox Code Playgroud)
这些函数的通用版本是根据不完整的伽玛函数实现的.
当识别有效数(尾数)大小时(当前用于53,64和113位实数,加上通过提升加倍的单精度24位处理),则使用由JM设计的一系列有理近似.
对于z <= 0.5,则使用erf的有理逼近,基于观察到erf是奇函数,因此erf使用以下公式计算:
erf(z) = z * (C + R(z*z));
Run Code Online (Sandbox Code Playgroud)
其中有理逼近R(z*z)针对绝对误差进行了优化:只要其绝对误差与常数C相比足够小,那么在计算R(z*z)期间产生的任何舍入误差都将有效从结果中消失.结果,该区域中erf和erfc的误差非常低:最后一位在极少数情况下是不正确的.
对于z> 0.5,我们观察到在一小段时间[a,b],然后:
erfc(z) * exp(z*z) * z ~ c
Run Code Online (Sandbox Code Playgroud)
对于某些常数c.
因此,对于z> 0.5,我们使用以下公式计算erfc:
erfc(z) = exp(-z*z) * (C + R(z - B)) / z;
Run Code Online (Sandbox Code Playgroud)
R(z-B)再次针对绝对误差进行优化,并且常数C是在该范围的端点处取得的erfc(z)*exp(z*z)*z的平均值.再一次,只要R(z - B)中的绝对误差与c相比较小,那么c + R(z - B)将被正确舍入,结果中的误差将仅取决于exp的精度功能.实际上,除了极少数情况外,错误仅限于结果的最后一位.选择常数B使得有理逼近范围的左手端为0.
对于范围[a,+∞]上的大z,上述近似值被修改为:
erfc(z) = exp(-z*z) * (C + R(1 / z)) / z;
Run Code Online (Sandbox Code Playgroud)
理性近似以难以理解的细节来解释.如果您需要更多详细信息,可以随时查看源代码.
归档时间: |
|
查看次数: |
2061 次 |
最近记录: |