- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
标准 C 数学库不提供计算标准正态分布的 CDF 的函数 normcdf()
。但是,它确实提供了密切相关的函数:误差函数 erf()
和补充误差函数 erfc()
。计算 CDF 的最快方法通常是通过误差函数,使用预定义常量 M_SQRT1_2 来表示 √½:
double normcdf (double a)
{
return 0.5 + 0.5 * erf (M_SQRT1_2 * a);
}
显然,这会在负半平面中受到大量减法抵消的影响,不适用于大多数应用。由于使用 erfc()
可以很容易地避免取消问题,但是它的性能通常比 erf()
低一些,因此最常推荐的计算是:
double normcdf (double a)
{
return 0.5 * erfc (-M_SQRT1_2 * a);
}
一些测试表明,在负半平面中产生的最大 ulp 误差仍然相当大。使用精度为 0.51 ulps 的 erfc()
double 实现,可以观察到误差在 normcdf()
中高达 1705.44 ulps。这里的问题是 erfc()
输入中的计算误差被 erfc()
固有的指数缩放放大了(参见这个 answer求幂引起的误差放大的解释)。
以下论文展示了如何在将浮点操作数与任意精度常量(例如 √½)相乘时实现(几乎)正确舍入的乘积:
Nicolas Brisebarre 和 Jean-Michel Muller,“任意精度常数的正确舍入乘法”,IEEE 计算机交易,卷。 57, No. 2, February 2008, pp. 165-174
本文提倡的方法依赖于融合乘加运算,该运算可用于所有常见处理器架构的最新实现,并通过标准数学函数 fma()
在 C 中公开.这导致以下版本:
double normcdf (double a)
{
double SQRT_HALF_HI = 0x1.6a09e667f3bcd0p-01; // 7.0710678118654757e-01
double SQRT_HALF_LO = -0x1.bdd3413b264560p-55; // -4.8336466567264567e-17
return 0.5 * erfc (fma (-SQRT_HALF_HI, a, -SQRT_HALF_LO * a));
}
测试表明,与以前的版本相比,这将最大错误减少了大约一半。使用与以前相同的高精度 erfc()
实现,观察到的最大误差为 842.71 ulps。这与提供误差至多几个 ulp 的基本数学函数的通常目标相去甚远。
是否有一种有效的方法可以准确计算 normcdf()
,并且只使用标准 C 数学库中可用的函数?
最佳答案
解决问题中概述的方法的准确性限制的一种方法是限制使用 double-double 计算。这涉及计算 -sqrt (0.5) * a
作为一对 double
变量 h
和 l
头/尾时尚。乘积的高阶部分 h
被传递给 erfc()
,而低阶部分 l
则用于插值erfc()
结果,基于 h
处互补误差函数的局部斜率。
erfc(x) 的导数是 -2 * exp (-x * x)/√π。然而,人们希望避免 exp(-x * x) 的相当昂贵的计算。 known 对于 x > 0,erfc(x) ~= 2 * exp (-x * x)/(√π * (x + sqrt (x* x + 4/π))。因此,渐近地,erfc'(x) ~= -2 * x * erfc(x),它遵循|l| ≪|h|, erfc (h+l) ~= erfc (h) - 2 * h * l * erfc(h)。后一项的否定很容易被拉入 l
的计算中。一个到达以下 double 实现(使用 IEEE-754 binary64
):
double my_normcdf (double a)
{
double h, l, r;
const double SQRT_HALF_HI = 0x1.6a09e667f3bcd0p-01; // 7.0710678118654757e-01
const double SQRT_HALF_LO = -0x1.bdd3413b264560p-55; // -4.8336466567264567e-17
/* clamp input as normcdf(x) is either 0 or 1 asymptotically */
if (fabs (a) > 38.625) a = (a < 0.0) ? -38.625 : 38.625;
h = fma (-SQRT_HALF_HI, a, -SQRT_HALF_LO * a);
l = fma (SQRT_HALF_LO, a, fma (SQRT_HALF_HI, a, h));
r = erfc (h);
if (h > 0.0) r = fma (2.0 * h * l, r, r);
return 0.5 * r;
}
使用与之前相同的 erfc()
实现,观察到的最大误差为 1.96 ulps。对应的单精度实现(使用IEEE-754 binary32
)为:
float my_normcdff (float a)
{
float h, l, r;
const float SQRT_HALF_HI = 0x1.6a09e6p-01f; // 7.07106769e-1
const float SQRT_HALF_LO = 0x1.9fcef4p-27f; // 1.21016175e-8
/* clamp input as normcdf(x) is either 0 or 1 asymptotically */
if (fabsf (a) > 14.171875f) a = (a < 0.0f) ? -14.171875f : 14.171875f;
h = fmaf (-SQRT_HALF_HI, a, -SQRT_HALF_LO * a);
l = fmaf (SQRT_HALF_LO, a, fmaf (SQRT_HALF_HI, a, h));
r = erfcf (h);
if (h > 0.0f) r = fmaf (2.0f * h * l, r, r);
return 0.5f * r;
}
关于c - 使用C标准数学库精确计算标准正态分布的CDF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37891569/
感觉我在这里遗漏了一些明显的东西,所以提前道歉。无论如何,这是我尝试转换的一些数据a: acct_num year_prem prem exc 001 20
我正在尝试将表中的模式与用户话语 匹配。 string userUtterance = "I want identification number for number of customers";
当尝试在 Precise 上链接 gccgo 时,出现此链接错误: matt@matt-1005P:~/src/gopath/src/meme$ gccgo cmd/meme/main.go -o m
假设我有以下数据和命令: clc;clear; t = [0:0.1:1]; t_new = [0:0.01:1]; y = [1,2,1,3,2,2,4,5,6,1,0]; p = interp1(
假设我有以下数据和命令: clc;clear; t = [0:0.1:1]; t_new = [0:0.01:1]; y = [1,2,1,3,2,2,4,5,6,1,0]; p = interp1(
我总是想给精确匹配比只匹配前缀的分数更高的分数(例如,“ball”在与“ball*”匹配时应该比“ballistic”得到更高的分数)。 我当前(详细)的方法是在创建 PrefixQuery 时始终执
有什么解决方法可以让我在 Android 中使用 long 或 double 来寻找音频文件中的位置吗?目前 seekTo 只接受 ints 参数。我想更精确(比如在十分之一秒内) int resID
我的 replacingOccurrences 函数有问题。我有一个这样的字符串: let x = "john, johnny, johnney" 我需要做的只是删除“john” 所以我有这段代码:
我正在使用 BeautifulSoup 进行网页抓取。我有这段代码来提取 a 标签的值,但它似乎不起作用。显示错误: AttributeError: 'int' object has no attri
我要在带有标记顶点和标记有向边的图上寻找一种不精确的图匹配算法。我的任务是检测两个图表的变化以将它们显示给开发人员(想想颠覆差异)。我已经实现了基于禁忌搜索 ( this ) 的优化算法,但我无法让该
我有两个网站: example.com 和 yyy.com 他们都有类似的网络应用程序,但在不同的服务器上。我想让 Apache 将所有路径请求重定向到 example.com 与 完全相同的方式yy
因此,我尝试合并两个公司信息数据库(从现在起表 A 和表 B),其中最常见(且可靠)的单一引用点是网站 URL。表 A 已更新,表 B 待更新。 我已经从表 A 中提取了 URL,并使用 PHP 清理
我正在 http://classicorthodoxbible.com/new.html 上制作效果主要描述中的 Angular 色,包裹在自己的跨度中,从他们通常的休息地点移动到随机位置,然后通过指
我目前正在使用我的 Raspberry Pi 及其内置 UART 输入编写 MIDI 合成器。 在某个时间点,为了启用 MIDI 输入的实时回放,我必须设置一种环形缓冲区以与 OpenAL 一起使用,
在 C 中,当设置了一个 float 时, int main(int argc, char *argv[]) { float temp = 98.6f; printf("%f\n",
实现 MP3 无间隙循环的最佳可能性是什么?目前我正在使用 AVAudioPlayer 并将 .numberOfLoops() 属性设置为 -1 但可以听到,轨道重新启动。情况并非如此,例如使用 Tr
我想创建不一定是“正确”矩阵的“类矩阵”对象。但是,确切地说,“类矩阵”是什么意思? 示例 1 > image(1:9) Error in image.default(1:9) : argument
给定一个像这样的 XML 文档: john &title; 我想解析上面的 XML 文档并生成其所有实体已解析的副本。因此,给定上述 XMl 文档,解析器应输出: john
需要说明的是,这种方法不是我要找的: 事实上,此方法会调整 ImageField 的大小。我想将 Image 对象的大小调整为特定且精确的无比例分辨率。有什么办法吗? --编辑-- 对我来说,Ima
我正在尝试使用 TF2.0 eager 模式执行精确的 GP 回归,基于来自 https://colab.research.google.com/github/tensorflow/probabili
我是一名优秀的程序员,十分优秀!