- 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/
SQL 和一般开发的新手,我有一个表(COUNTRIES),其中包含字段(INDEX、NAME、POPULATION、AREA) 通常我添加一个客户端(Delphi)计算字段(DENSITY)和 On
我想使用 calc(100%-100px),但在我的 demo 中不起作用由于高度只接受像素,因此如何将此百分比值转换为像素。 最佳答案 以下将为您提供高度: $(window).height();
我正在尝试在 MySQL 中添加列并动态填充其他列。 例如我有一张表“数字”并具有第 1 列、第 2 列、第 3 列,这些总数应填充在第 4 列中 最佳答案 除非我误解了你的问题,否则你不只是在寻找:
我想返回简单计算的结果,但我不确定如何执行此操作。我的表格如下: SELECT COUNT(fb.engineer_id) AS `total_feedback`, SUM(fb.ra
我一直在尝试做这个程序,但我被卡住了,我仍然是一个初学者,任何帮助将不胜感激。我需要程序来做 打印一个 10 X 10 的表格,其中表格中的每个条目都是行号和列号的总和 包含一个累加器,用于计算所有表
这个计算背后一定有一些逻辑。但我无法得到它。普通数学不会导致这种行为。谁能帮我解释一下原因 printf ("float %f\n", 2/7 * 100.0); 结果打印 1.000000 为什么会
我想计算从 0 到 (n)^{1/2} - 1 的数字的 AND每个数字从 0 到 (n)^{1/2} - 1 .我想在 O(n) 中执行此操作时间,不能使用 XOR、OR、AND 运算。 具体来说,
如何在 Excel 中将公式放入自定义数字格式?例如(出于说明目的随机示例), 假设我有以下数据: 输入 输出 在不编辑单元格中的实际数据的情况下,我想显示单元格中的值除以 2,并保留两位小数: 有没
每次我在 Flutter 应用程序中调用计算()时,我都会看到内存泄漏,据我所知,这基本上只是一种生成隔离的便捷方法。我的应用程序内存占用增加并且在 GC 之后永远不会减少。 我已将我的代码简化为仅调
我有数字特征观察 V1通过 V12用于目标变量 Wavelength .我想计算 Vx 之间的 RMSE列。数据格式如下。 每个变量“Vx”以 5 分钟的间隔进行测量。我想计算所有 Vx 变量的观测值
我正在寻找一种使用 C 语言计算文件中未知字符数的简单方法。谢谢你的帮助 最佳答案 POSIX 方式(可能是您想要的方式): off_t get_file_length( FILE *file ) {
我正在使用 Postgres,并且我正试图围绕如何在连续日期跨度中得出第一个开始日期的问题进行思考。例如 :- ID | Start Date | End Date =================
我有一个订单表格,我在其中使用 jQuery 计算插件来汇总总数。 此求和工作正常,但生成的“总和”存在问题。总之,我希望用逗号替换任何点。 代码的基础是; function ($this) {
我在使用 double 变量计算简单算术方程时遇到问题。 我有一个具有 double 属性 Value 的组件,我将此属性设置为 100。 然后我做一个简单的减法来检查这个值是否真的是 100: va
我在这里看到了一些关于 CRC 32 计算的其他问题。但没有一个让我满意,因此是这样。 openssl 库是否有任何用于计算 CRC32 的 api 支持?我已经在为 SHA1 使用 openssl,
当我在PHP日期计算中遇到问题时,我感到惊讶。 $add = '- 30 days'; echo date('Y-m-01', strtotime($add)); // result is 2017-
我正在使用 javascript 进行练习,我编写了这个脚本来计算 2 个变量的总和,然后在第三个方程中使用这个总和!关于如何完成这项工作的任何想法都将非常有用! First Number:
我有一个来自EAC的提示单和一个包含完整专辑的FLAC文件。 我正在尝试制作一些python脚本来播放文件,因为我需要能够设置在flac文件中开始的位置。 如何从CueSheet格式MM:SS:FF转
这个问题已经有答案了: Adding two numbers concatenates them instead of calculating the sum (24 个回答) 已关闭去年。 我有一个
4000 我需要上面字段 name="quantity" 和 id="price" 中的值,并使用 javascript 函数进行计算,并将其显示在字段 id= 中仅当我单击计算按钮时才显示“总
我是一名优秀的程序员,十分优秀!