- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
给定此示例 C++ 代码片段:
void floatSurprise()
{
// these come from some sort of calculation
int a = 18680, b = 3323524, c = 121;
float m = float(a) / c;
// variant 1: calculate result from single expression
float r1 = b - (2.0f * m * a) + (m * m * c);
cout << "r1 = " << r1 << endl;
// variant 2: break up the expression into intermediate parts,
/// then calculate
float
r2_p1 = 2.0f * m * a,
r2_p2 = m * m * c,
r2 = b - r2_p1 + r2_p2;
cout << "r2 = " << r2 << endl;
}
输出是:
dev1 = 439703
dev2 = 439702
在调试器中查看时,值实际上分别为 439702.50 和 439702.25,这本身很有趣 - 不确定为什么 iostream 默认打印没有小数部分的 float 。 编辑: 这样做的原因是 cout 的默认精度设置太低,至少需要 cout << setprecision(7) 才能看到这个数量级的数字的小数点。
但我更感兴趣的是为什么我会得到不同的结果。我想这与舍入和 int 与所需的 float 输出类型的一些微妙相互作用有关,但我不能指手画脚。哪个值是正确的?
我很惊讶用这么简单的一段代码这么容易搬起石头砸自己的脚。任何见解将不胜感激!编译器为VC++2010。
EDIT2:我做了更多调查,使用电子表格为中间变量生成“正确”值,发现(通过跟踪)它们确实被修剪了,导致精度损失最终结果。我还发现了单个表达式的问题,因为我实际上使用了一个方便的函数来计算平方而不是那里的 m * m
:
template<typename T> inline T sqr(const T &arg) { return arg*arg; }
即使我问得很好,编译器显然没有内联它,而是单独计算值,在将值返回给表达式之前修剪结果,再次扭曲结果。哎哟。
最佳答案
你应该阅读我关于为什么在 C# 中会发生同样的事情的长长的回答:
(.1f+.2f==.3f) != (.1f+.2f).Equals(.3f) Why?
总结:首先,使用 float 只能得到大约七位小数的精度。如果您在整个计算过程中使用精确的算术对其进行正确运算,则正确答案约为 439702.51239669...因此,无论哪种情况,考虑到 float 的局限性,您都非常接近正确答案。
但这并不能解释为什么您使用看起来完全相同的计算得到不同的结果。答案是:允许编译器有很大的自由度来使你的数学更准确,显然你遇到了两种情况,优化器采用逻辑上相同的表达式并且没有将它们优化到相同的代码。
无论如何,请仔细阅读我关于 C# 的回答;其中的所有内容同样适用于 C++。
关于c++ - 为什么这两种代码变体会产生不同的浮点结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15490061/
COW 不是奶牛,是 Copy-On-Write 的缩写,这是一种是复制但也不完全是复制的技术。 一般来说复制就是创建出完全相同的两份,两份是独立的: 但是,有的时候复制这件事没多大必要
我是一名优秀的程序员,十分优秀!