我对MSVC ldexp行为感到有些惊讶(它发生在Visual Studio 2013中,但也适用于所有旧版本,至少到2003年......).
例如:
#include <math.h>
#include <stdio.h>
int main()
{
double g=ldexp(2.75,-1074);
double e=ldexp(3.0,-1074);
printf("g=%g e=%g \n",g,e);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
版画
g=9.88131e-324 e=1.4822e-323
Run Code Online (Sandbox Code Playgroud)
第一个g是奇怪的圆形...
它是2.75*fmin_denormalized,所以我绝对期望第二个结果e.
如果我评价2.75*ldexp(1.0,-1074)我正确得到与e相同的值.
我的期望是否太高,或者微软是否未能遵守某些标准?
第一个公式
m = (a + b) / 2
Run Code Online (Sandbox Code Playgroud)
很简单,但是有很大的溢出风险。此外,Burden and Faires的《第9版数值分析》指出:
当b-a接近机器的最大精度时,(a + b)/ 2可能返回一个中间点,该中间点甚至不在[a,b]区间内。
尽管没有提供进一步的解释。
第二个
m = a + (b - a) / 2
Run Code Online (Sandbox Code Playgroud)
也是正确的,溢出的可能性较小。但是对于浮点数,a和b几乎相等的值可能会导致重要性下降。
那么,哪种公式在实践中更好?另外,将理解对引用语句的解释。
使用 32 位浮点值,如果 - 在开始计算时 - 我不知道我将拥有多少个值(在以下示例中,我只是遍历一个向量,那么计算平均值的最佳(数字最准确)方法是什么)我会知道 coult,但让我们假设我最后只知道元素计数)?
我可以做例如
float result = 0.f;
for(float num: numbers) {
result += num;
}
num /= numbers.size();
Run Code Online (Sandbox Code Playgroud)
但随着结果变大,精度也会变大。对于较小的值,在某些时候result += num;实际上不会再改变结果。
我可以
float result = numbers[0]
for(int i=1, i<numbers.size(); i++) {
float frac = (i/float(i+1));
result = result * frac + numbers[i] * (1.0f-frac);
}
Run Code Online (Sandbox Code Playgroud)
但似乎我会应用累积错误来产生这种结果。
有没有更好的方法而不去 64bit double?