Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.83/64: Рейтинг темы: голосов - 64, средняя оценка - 4.83
2 / 2 / 1
Регистрация: 11.03.2013
Сообщений: 64

Сравнение чисел с плавающей точкой

05.09.2014, 13:08. Показов 14123. Ответов 33
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Известно, что числа с плавающей точкой нельзя сравнивать с помощью ==. Однако, нет ли исключения из этого правила? Дело вот в чём. Если мы вводим значение такой переменной (которое заведомо не будет за пределами точности), а потом сравниваем с некоторыми такими же "чистыми" значениями с помощью ==, это будет адекватно? Можно ли так делать, и если нельзя, то почему?

Пример:

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
float a;
 
cin >> a;
 
if (a==1)
cout << "raz" << endl;
if (a==2)
cout << "dva" << endl;
 
//вроде ничего криминального не должно быть, если вводим, например, единицу
1
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
05.09.2014, 13:08
Ответы с готовыми решениями:

Написать защиту от ввода чисел с плавающей точкой, отрицательных чисел и символов
Привет всем! Вот пишу программу, преподаватель сказал чтобы написал защиту от ввода чисел с плавающей точкой, отрицательных, символов. В...

Умножения чисел с плавающей точкой
Доброго времени суток,нужна ваша помощь в умножение чисел с плавающей точкой. Суть программы:Умножение чисел в двоичном коде.Первое число...

Массив чисел с плавающей точкой
#include &lt;iostream&gt; #include &lt;ctime&gt; #include &lt;fstream&gt; using namespace std; int main() { float randomDigits_5 {}; ...

33
5500 / 4895 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
05.09.2014, 16:03
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Kastaneda Посмотреть сообщение
например
C++
1
2
3
if (a - b < 0.000001) {
    // равны
}
Наверное, все-таки, абсолютную величину разности нужно взять.
0
2 / 2 / 1
Регистрация: 11.03.2013
Сообщений: 64
05.09.2014, 16:35  [ТС]
Вообще это общеизвестный факт, что приведение делается к более широкому типу, наверное в любой книге для начинающих это есть.
Вообще это чётко проговаривается для присваивания и арифметических операций, но не для сравнения.

Иногда это работает, но делать так нельзя.
Что сие значит? Нельзя делать как ? Нельзя сравнивать ВЫЧИСЛЕННЫЕ величины - так это я в курсе. А введённое с клавиатуры сравнивать с написанным литералами - можно ? Вот в чём вопрос-то, про сравнение вычисленных я и так знаю. Меня интересует, ПОЧЕМУ можно/нельзя так делать.

Добавлено через 9 минут
Цитата Сообщение от SatanaXIII Посмотреть сообщение
Первая попавшаяся ссылка для прочтения, ведущему к пониманию: Особенно четвертый пункт.
Окда, изучаю 4-й пункт, хотя пришлось ради этого тащиться в кэш гугла - хабр лежит.

Таки получается, нельзя ?
0
 Аватар для Kastaneda
5232 / 3206 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
05.09.2014, 17:10
Цитата Сообщение от alsav22 Посмотреть сообщение
Наверное, все-таки, абсолютную величину разности нужно взять.
Ну да, естественно, я просто для примера написал.
0
И целого heap'а мало
 Аватар для Andrej
96 / 57 / 17
Регистрация: 31.07.2014
Сообщений: 291
05.09.2014, 17:53
Всё верно, нельзя числа с плавающей точкой тупым == (без перегрузок) сравнивать как инты.
В сяшном стиле это делается через FLT_EPSILON, DBL_EPSILON или LDBL_EPSILON из float.h:
C
1
2
3
4
5
6
7
8
9
10
...
double a = 34.0;
double b = 34.0;
if (abs(a - b) < DBL_EPSILON) {
    puts("they are equal!");
}
else {
    puts("they aren't equal :(");
}
...
В крестах есть std::numeric_limits:
C++
1
2
3
4
5
6
7
8
9
10
...
double a = 34.0;
double b = 34.0;
if (abs(a - b) < std::numeric_limits<double>::epsilon()) {
    std::cout << "they are equal!" << '\n';
}
else {
    std::cout << "they aren't equal!" << '\n';
}
...
1
Почетный модератор
Эксперт С++
 Аватар для SatanaXIII
5851 / 2862 / 392
Регистрация: 01.11.2011
Сообщений: 6,906
05.09.2014, 18:03
Цитата Сообщение от mariko_11 Посмотреть сообщение
А введённое с клавиатуры сравнивать с написанным литералами
А введенное с клавиатуры оно ведь не в клавиатуре сохраняется. Оно, при записи в память, интерпретируется как с плавающей точкой со всеми выплывающими.
1
Модератор
Эксперт CЭксперт С++
 Аватар для sourcerer
5288 / 2376 / 342
Регистрация: 20.02.2013
Сообщений: 5,773
Записей в блоге: 20
05.09.2014, 18:05
Ух ты, а я, оказывается, совсем не в теме. Много нового узнал. Всем просветителям - благодарность и респект.
0
4949 / 2289 / 287
Регистрация: 01.03.2013
Сообщений: 5,991
Записей в блоге: 32
05.09.2014, 22:09
Цитата Сообщение от SatanaXIII Посмотреть сообщение
Оно, при записи в память, интерпретируется как с плавающей точкой со всеми выплывающими.
Только из этого имхо ничего не выплывает. Приведение типов что прочитанные символы с клавиатуры в IEEE переведет, что написанные в тексте кода. И если алгоритм переведения будет одинаков (а с чего ему быть разным?), то и результат будет одинаков в мантиссе вплоть до бита.
Но я бы ТС очень не рекомендовал строить логику программы, опираясь на эти предположения.
0
19506 / 10109 / 2464
Регистрация: 30.01.2014
Сообщений: 17,834
05.09.2014, 22:29
Цитата Сообщение от _Ivana Посмотреть сообщение
Только из этого имхо ничего не выплывает.
Некоторые числа не могут быть представлены точно в формате с плавающей точкой (IEEE 754). Например, число 0.005, или 0.1. Т.е. да, это точные числа, но в 10-й системе счисления, в 2й системе счисления (IEEE 754 описывает числа именно в системе по основанию 2) эти числа не имеют точного представления. Отсюда все эти погрешности. Вот неплохой материал по теме.
1
И целого heap'а мало
 Аватар для Andrej
96 / 57 / 17
Регистрация: 31.07.2014
Сообщений: 291
05.09.2014, 22:33
Кстати, ещё в IEEE 754 операции над вещественными не ассоциативны (для битоперекладчиков-параноиков).
0
19506 / 10109 / 2464
Регистрация: 30.01.2014
Сообщений: 17,834
05.09.2014, 22:39
_Ivana, вот к примеру, запусти такую программу:
C++
1
2
3
4
5
6
7
8
int main()
{
    float a = 0.005;
 
    int b = a * 1000.0f;
 
    std::cout << b << std::endl;
}
Она тебе выведет 4, потому что 0.005 - это бесконечная периодичная дробь в двоичной системе, которая приблизительно равна 0.0049999995. При умножении на 1000 мы получаем 4.9999995, а при преобразовании float->int просто отбрасывается дробная часть.
0
4949 / 2289 / 287
Регистрация: 01.03.2013
Сообщений: 5,991
Записей в блоге: 32
05.09.2014, 22:48
Да я не про вычисления, это все понятно. Я про единообразность перевода во флоаты, на что хочет опереться автор.

Не по теме:

ЗЫ битоперекладчики-параноики заспорили в соседнем разделе по С, высказались бы там что-ли :)

0
19506 / 10109 / 2464
Регистрация: 30.01.2014
Сообщений: 17,834
05.09.2014, 23:01
Цитата Сообщение от _Ivana Посмотреть сообщение
Я про единообразность перевода во флоаты, на что хочет опереться автор.
А, ага. Я значит как-то подругому тебя интерпретировал.
В принципе да, здесь не может быть строгой гарантии. Это implementation defined.
0
 Аватар для zarko97
279 / 39 / 13
Регистрация: 11.10.2015
Сообщений: 405
11.03.2017, 00:22
я так сравнивал:
C++
1
2
3
4
5
6
7
8
9
10
static auto equals
    (
        T_Coord  const  &  lhs_,
        T_Coord  const  &  rhs_
    )
        -> const bool
    {
        return T_Min * std::abs(lhs_ - rhs_)                                              <
               std::abs(lhs_ + rhs_) * T_Epsilon * std::numeric_limits<T_Coord>::epsilon();
    }
0
Эксперт С++
1069 / 848 / 60
Регистрация: 30.04.2011
Сообщений: 1,659
11.03.2017, 09:18
ИМХО, самый простой ответ на изначальный вопрос топикстартера (из практики):
1. целые значения плавающих типов можешь сравнивать как угодно.
2. Дробные значения можешь сравнивать на равенство-неравенство - только степени двойки (1/2, 1/4...)
3. Дробные значения - не степени двойки на равенство лучше не сравнивать, если значение получено в результате вычислений. Ты, конечно, можешь написать сравнение "==", но это как раз тот наиболее часто встречающийся случай, когда НЕ РЕКОМЕНДУЕТСЯ.
Ибо все дробные числа - не степени двойки, представлены в памяти НЕ ТОЧНО.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
11.03.2017, 09:18

Представление чисел с плавающей точкой
Никак не пойму почему в коде: double helper; bool cond; int dim_2; int dim_1; helper=0.0; ...

Форматирование чисел с плавающей точкой
Все знают про проблемы с представлением дробных чисел. Например: double test = .58; printf(&quot;%f\n&quot;, test); ...

Калькулятор чисел с плавающей точкой
double calculate(float x, char s, float y); int main() { float x,y; char s; x=y=0; cin&gt;&gt;x&gt;&gt;s&gt;&gt;y;

Проблема сравнения чисел с плавающей точкой
Добрый вечер, развивая тему к которой меня подтолкнул, Байт, посоветуйте ряд лайффаков на тему фикса (кроссплатформенность же ж ) ...

Округление положительных чисел с плавающей точкой
Добрый день ! Нужно округлить положительных чисел с плавающей точкой в большую сторону к числу кратному 5. то есть если есть...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
34
Ответ Создать тему
Новые блоги и статьи
BitTorrent (версия 7.11 English) и Меню Настройки
russiannick 15.11.2026
Пункты, отвечающие за отключение обновлений в BitTorrent версии 7. 11 (английской) Options Preferences General Language
Транслитерация текста с кириллицы на латиницу (вариант №4)
Maks 15.11.2026
Что-то я перемудрил с предыдущими версиями, в этот раз сделал всё проще, обратившись к функции "СтрокаЛатиницей" из типового общего модуля "СтроковыеФункцииКлиент". В данной функции нет апострофов,. . .
BitTorrent (версия 4.3.9) и Меню Настройки
russiannick 15.11.2026
В меню Настройки можно отключить автоматическое обновление программы. Карта этого меню приложена ниже. Нужный пункт выделен красным. Сервис Настройки Поведение
Транслитерация текста с кириллицы на латиницу (вариант №3)
Maks 15.11.2026
Обновленная версия предыдущей обработки. Изменения коснулись букв: Ъ, Ы, Ь, Э, отображения которых зависят от положения реквизита "Транслитерация имён". Изменено отображение буквы Й. Добавлена. . .
Транслитерация текста с кириллицы на латиницу (вариант №2)
Maks 13.11.2026
Обновленная версия ранее созданной обработки. Добавлено: - Проверка исходного текста на кириллицу, через обращение к стандартной функции "ТолькоКириллицаВСтроке" из общего модуля. . .
Часы с термометром и праздничным календарем
yariko 12.11.2026
Сегодня мы рассмотрим как можно сделать отличные многофункциональные часы. Итак, поставим конкретную задачу: разработать часы с календарем, двумя термодатчиками, выводом поздравительных сообщений. . .
Транслитерация текста с кириллицы на латиницу (вариант №1)
Maks 11.11.2026
Решил облегчить жизнь себе и коллегам админам при создании электронных почтовых ящиков для пользователей, в результате написал обработку "Транслитерация текста" с кириллицы на латиницу, а в ней. . .
Книги по геймдизайну, левел-дизайну, игровым механикам и проектированию игрового опыта
8Observer8 08.11.2026
Содержание блога | English Version 1. 2003 - 06 - Designing Virtual Worlds (1st Edition) Автор: Richard A. Bartle | Объем: 768 стр. Ссылки: Amazon . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru