Проблема в преобразовании типов:
int i = f * 100 ;
эквивалентно
double tmp = f* 100.0;
int i = tmp;
И разница со вторым случаем в том, что tmp double
! И да, есть случай, когда 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
И наконец
Если мы отключим оптимизацию оценки, компилятор I DEONE также воспроизведет поведение :