Eam*_*nne 9 c# c++ floating-point ieee-754
简而言之:我怎么能执行a+b这样的,因为截断造成的任何精度损失都是零而不是零?
我正在计算一系列浮点值的总和,用于计算集合的样本均值和方差.由于Var(X)= E(X 2) - E(X)2,它足以保持所有数字的运行计数,到目前为止所有数字的总和,以及到目前为止所有数字的平方和.
到现在为止还挺好.
但是,绝对要求E(X 2)> E(X)2,由于浮点精度并非总是如此.在伪代码中,问题是:
int count;
double sum, sumOfSquares;
...
double value = <current-value>;
double sqrVal = value*value;
count++;
sum += value; //slightly rounded down since value is truncated to fit into sum
sumOfSquares += sqrVal; //rounded down MORE since the order-of-magnitude
//difference between sqrVal and sumOfSquares is twice that between value and sum;
Run Code Online (Sandbox Code Playgroud)
对于变量序列,这不是一个大问题 - 你最终会略微低估方差,但这通常不是一个大问题.然而,对于具有非零均值的常数或几乎常数集合,它可能意味着E(X 2)<E(X)2,导致负计算方差,这违反了消费代码的期望.
现在,我知道Kahan Summation,这不是一个有吸引力的解决方案.首先,它使代码容易优化变幻莫测(取决于优化参数,代码可能会或可能不会出现此问题),其次,这个问题是不是真的由于精度-这是不够好-这是因为除了引入系统错误朝零.如果我可以执行该行
sumOfSquares += sqrVal;
Run Code Online (Sandbox Code Playgroud)
以确保sqrVal向上舍入而不是向下舍入到sumOfSquares的精度的方式,我有一个数值上合理的解决方案.但是我怎样才能做到这一点?
编辑:完成的问题 - 为什么按下输入标签字段的下拉列表无论如何提交问题?
IEEE提供四种舍入模式(朝向-inf,朝向+ inf,朝向0,色调).Toward + inf就是你想要的.C90或C++中没有标准控件.C99添加了头文件<fenv.h>,它也是某些C90和C++实现中的扩展.要尊重C99标准,您必须编写如下内容:
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int old_round_mode = fegetround();
int set_round_ok = fesetround(FE_UPWARD);
assert(set_round_ok == 0);
...
int set_round_ok = fesetround(old_round_mode);
assert(set_round_ok == 0);
Run Code Online (Sandbox Code Playgroud)
众所周知,您使用的算法在数值上不稳定并且存在精度问题.精确度对数据进行两次传递更好.
还有另一种单程算法可以重新排列计算.在伪代码中:
n = 0
mean = 0
M2 = 0
for x in data:
n = n + 1
delta = x - mean
mean = mean + delta/n
M2 = M2 + delta*(x - mean) # This expression uses the new value of mean
variance_n = M2/n # Sample variance
variance = M2/(n - 1) # Unbiased estimate of population variance
Run Code Online (Sandbox Code Playgroud)
(来源:http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance)
对于您使用通常算法指出的问题,这似乎表现得更好.
| 归档时间: |
|
| 查看次数: |
1827 次 |
| 最近记录: |