Я работаю через начальный класс C ++, и в моей книге (Начиная с C ++ Early Objects 7-е издание) приведен очень плохой пример того, как проверить значение переменной с плавающей запятой.
Пример книги, о которой идет речь (имя файла pr4-04.cpp):
// This program demonstrates how to safely test a floating-point number
// to see if it is, for all practical purposes, equal to some value.
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
double result = .666667 * 6.0;
// 2/3 of 6 should be 4 and, if you print result, 4 is displayed.
cout << "result = " << result << endl;
// However, internally result is NOT precisely equal to 4.
// So test to see if it is "close" to 4.
if (abs(result - 4.0 < .0001))
cout << "result DOES equal 4!" << endl;
else
cout << "result DOES NOT equal 4!" << endl;
return 0;
}
И я использую g ++ в Ubuntu для компиляции моего кода следующим образом:
g++ pr4-04.cpp -o pr4-04 && ./pr4-04
И я получаю эту ошибку:
error: call of overloaded ‘abs(bool)’ is ambiguous
Я могу это исправить, изменив abs () на fabs (), но это все еще очень запутанно! Почему книга дает нам вещи, которые не будут компилироваться, или это только я? Почему cout «результата» дает 4 вместо 4.000002? Почему это значение изменяется, когда оно используется в операторе if {}?
Я понимаю, что мы не можем просто использовать == для проверки эквивалентности, но зачем мне использовать абсолютное значение? Я получаю один и тот же ответ, использую ли я его или нет. Так в чем смысл?
Не говоря уже о том, что это выглядит как очень плохой способ проверки на эквивалентность с плавающей запятой. Есть лучший способ сделать это? Эта тема кажется ужасно важной.
я нашел Эта тема здесь на stackoverflow, но их решение:
fabs(f1 - f2) < precision-requirement
fabs(f1 - f2) < max(fabs(f1), fabs(f2)) * percentage-precision-requirement
Не имеет особого смысла для меня в контексте моего опыта работы с C ++ на 4 главы. Я был бы очень признателен за помощь. Наша книга дала мне целых 6 предложений текста, чтобы объяснить все это.
Редактировать: Как предлагали некоторые, я пытался найти страницу с ошибками, но после 30 минут поиска учебника, Интернета и сайта моего курса я смог найти только этот загружаемый почтовый файл, который требовал логин -_-
Я также отлично скопировал код. Этого не было МОИ опечатка, я скопировал его прямо с компакт-диска с кодом на нем. Это также напечатано таким образом в книге.
if (abs(result - 4.0 < .0001))
Скобки неверны, вы, вероятно, имеете в виду: if (abs(result-4.0) < .0001)
,
Что касается того, почему он не компилируется, стандарт определяет в §26.8p8, что
В дополнение к двойным версиям математических функций в C ++ добавляются плавающие и длинные двойные перегруженные версии этих функций с одинаковой семантикой.
Выражение (result-4.0 < .0001)
дает bool
и нет перегрузки abs
это занимает bool
аргумент, но есть несколько версий abs
для которого аргумент неявно конвертируется из bool
, Компилятор не находит одну из последовательностей преобразования лучше, чем остальные, и выдает ошибку неоднозначности.
Проблема явно в линии
if (abs(result - 4.0 < .0001))
который должен быть написан как
if (abs(result - 4.0) < .0001)
Я бы предположил, что это простая опечатка. Сообщить об ошибке автору книги!
Кстати, оригинальный код компилируется в моей системе без каких-либо проблем, давая ожидаемый результат! То есть, даже если автор протестировал код, он, возможно, не заметил, что он проблематичен!
Также отвечая на вопрос, почему abs()
необходимо: некоторые десятичные числа округляются до значения с плавающей запятой, которое немного меньше ожидаемого результата, в то время как другие округляются до числа, которое немного больше. В каком направлении значения округлены (если вообще: некоторые десятичные числа могут быть представлены точно, используя двоичные числа с плавающей запятой), довольно сложно предсказать. Таким образом result
может быть немного больше или немного меньше, чем ожидание и разница, таким образом, положительная или отрицательная, соответственно.