复合赋值运算符的类型/转换? (例如* =(星等))

时间:2012-03-17 19:25:47

标签: c++ casting

我对这部分示例代码感到困惑:

float f = 3.01;
int i;
  • 案例1:i = f * 100; // i == 300
  • 案例2:i = f *= 100; // i == 301

我不知道为什么在第一种情况下小数部分会“丢失” 我也试过了:

(double) f * 100
f * 100.0

然后我尝试使用volatile和flags来解决所有优化问题 结果仍然相同。

有人可以向我解释为什么第一种情况会如此?谢谢。

4 个答案:

答案 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.1cl 16.00MS 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