Тип / приведение составных операторов присваивания? (например, * = (звездочка равна)) - PullRequest
2 голосов
/ 17 марта 2012

Меня смущает эта часть примерного кода:

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 для gcc, которые отключают всеоптимизация.
Результат все тот же.

Может кто-нибудь объяснить мне, почему первый случай ведет себя так?Спасибо.

Ответы [ 4 ]

1 голос
/ 17 марта 2012

Проблема в преобразовании типов:

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 также воспроизведет поведение :

0 голосов
/ 17 марта 2012

Во втором случае вы берете f, который является float, и умножаете его на 100, что равно 301, затем вы помещаете это значение в ваш int i, десятичного знака нет, поэтому нет потери данных.

0 голосов
/ 17 марта 2012

Ошибка компилятора? Здесь все отлично работает: http://ideone.com/FlQCL

0 голосов
/ 17 марта 2012

Я могу только догадываться, что в первом примере временный результат имеет более высокую точность, чем float, и результат почти 301 (например, 300.999999999999). Во втором примере результат помещается в f (который является плавающей точкой) и округляется до 301.

Я не уверен в этом, но это похоже на справедливое предположение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...