Многострочные математические результаты отличаются от однострочных - PullRequest
0 голосов
/ 28 декабря 2018

У меня была проблема с какой-то математикой с плавающей запятой, и я обнаружил, что если я делаю свою математику в одной строке, я получаю -0, передаваемую в tan (), и если я делаю это через две строки, я получаю 0перешел в загар ().Посмотрите:

float theta = PI / 2.f;
float p = (PI / 2.f) - theta;
float result = tan(p);

Выше, p = -0, результат = -4.37 ...

float theta = PI / 2.f;
float p = PI / 2.f;
p -= theta;
float result = tan(p);

Выше, p = 0, результат = 0.

Может кто-нибудь объяснить разницу?Я предполагаю, что -0 является результатом такого результата в tan (), хотя я не могу найти в Google ничего, что объясняет почему.Почему один и тот же расчет, разбросанный по разным строкам, приводит к другому ответу?

Спасибо

Ответы [ 3 ]

0 голосов
/ 28 декабря 2018

То, что говорит @Naor, вероятно, правильно.но я бы хотел кое-что добавить.

Возможно, вы не получаете -4.37xx, но -4.37xxxe-xx, что является довольно небольшим отрицательным числом.

Поскольку вы всегда можете получить ошибки в математике с плавающей запятой,Я бы сказал, что менять код не нужно.Оба фрагмента верны.

0 голосов
/ 28 декабря 2018

Так вот, на мой взгляд, и происходит:

В обоих примерах PI - это определение, вероятно, определенное так:

#define 3.14 //and some more digits

В C ++ число, подобное этому,обрабатывается как double.

После предварительной обработки это выражение:

PI / 2.0f

будет обрабатываться как prvalue двойного типа.Это означает, что в этой строке скрыта еще одна операция:

float theta = PI / 2.f;

, которая является двойным преобразованием с плавающей точкой, что в данном случае определенно теряет некоторую точность.

В первом примере это также происходитздесь:

float p = (PI / 2.f) - theta;

но только после оценки всего выражения.Обратите внимание, что во время этой оценки (PI / 2.f) будет по-прежнему удваиваться, но theta будет преобразованным значением с плавающей запятой в двойную, что объясняет небольшую разницу в результате от 0,0.

В последнем примере вы сначала(PI / 2.f)

float p = PI / 2.f;

конвертировать *1023* в число с плавающей запятой, чтобы вычесть из него следующую строку с типом float theta.Что должно привести к 0.0, который, вероятно, компилятор все равно оптимизирован).

0 голосов
/ 28 декабря 2018

Это, вероятно, из-за типа PI .

Если вы используете double, он изменится на число с плавающей точкой, и тогда результат будет таким, как вы только что представляете.

Но если PI равен float, то оба сценария тестирования равны.

...