我对这部分示例代码感到困惑:
float f = 3.01;
int i;
i = f * 100; // i == 300
i = f *= 100; // i == 301
我不知道为什么在第一种情况下小数部分会“丢失” 我也试过了:
(double) f * 100
f * 100.0
然后我尝试使用volatile和flags来解决所有优化问题 结果仍然相同。
有人可以向我解释为什么第一种情况会如此?谢谢。
答案 0 :(得分:1)
问题出在类型转换中:
int i = f * 100 ;
相当于
double tmp = f* 100.0;
int i = tmp;
与第二种情况的区别在于tmp是double
!是的,有一种情况,双重“不太精确”
为了说明这一点,我写了下面的程序:
int main()
{
float f = 3.01;
float mf = f * 100;
double md = f * 100;
int if_ = mf;
int id = md;
std::cout << f << ' ' << mf << ' ' << md << ' ' << ' ' << (mf - md) << ' ' << if_ << ' ' << id << '\n';
}
修改强>
在我的系统上,我的gcc 4.6.1
和cl 16.00
(MS VS 10
)得到的结果相同:
3.01 301 301 9.53674e-007 301 300
<强> EDIT2 强>
发现,启用优化-O2
可以消除问题。这解释了与IDEONE的区别。
这是另一个代码:
int main()
{
float f = 3.01;
float mf = f * 100;
return mf + (f*100);
//std::cout << f << ' ' << mf << ' ' << md << ' ' << ' ' << (mf - md) << ' ' << if_ << ' ' << id << '\n';
}
与-O0
movl $0x4040a3d7, %eax
movl %eax, 28(%esp)
flds 28(%esp)
flds LC1
fmulp %st, %st(1)
fstps 24(%esp)
flds 28(%esp)
flds LC1
fmulp %st, %st(1)
fadds 24(%esp)
fnstcw 14(%esp)
movw 14(%esp), %ax
movb $12, %ah
movw %ax, 12(%esp)
fldcw 12(%esp)
fistpl 8(%esp)
fldcw 14(%esp)
movl 8(%esp), %eax
我们只能看到一次显式转换为单精度指令(fspts
)。这符合我的猜测,临时评估来自double
,而不是float
。
使用-O2
程序集非常简单:
movl $602, %eax
最后
如果我们停用优化评估,我DEONE compiler reproduce behavior too:
答案 1 :(得分:0)
我只能猜测在第一个例子中,临时结果的精度高于float,结果几乎为301(例如300.999999999999)。在第二个例子中,结果放入f(浮点数)并舍入为301。
我不确定,但这似乎是一个公平的猜测。
答案 2 :(得分:0)
你的第二个案例是f,它是一个浮点数并乘以100,等于301,然后你将该值放入你的int i,没有小数位,所以没有数据丢失。
答案 3 :(得分:0)
编译器错误?它在这里工作正常:http://ideone.com/FlQCL