Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Неправильнгое сравнение двух чисел типа double  (Прочитано 43578 раз)
0 Пользователей и 3 Гостей смотрят эту тему.
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« : 08-05-2005 14:42 » new

Вы не поверите, но я неоднократно все проверил прежде чем написать об этом в форуме.
Я делал так:
Код:
if(itog<sum)
return false;
При этом double itog=20, sum=20;
Условие ложно, но при отладке условие возвращает true и соответственно происходит выход из функции с результатом false, что для меня не очень хорошо.

При этом делал так
Код:
if(itog>sum)
return false;
В этот раз условие вернуло ложь, значения и тип переменных тот же. Конечно условие должно вернуть ложь и это правильно, но почему не возвращает этого в первом случае?
А вот вам удар в печень
Код:
if(temp==sum)
return false;
double temp=20, sum=20;
Сравнение вернуло ЛОЖЬ. Я в осадке.
И единственное когда все работает как надо это когда переменные temp и sum типа long.
В чем дело и как это перебороть?
Записан

ещё один вопрос ...
Михалыч
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 08-05-2005 16:06 » 

Побереги печень Улыбаюсь Не все так смертельно...
temp и sum - задаются ручками (типа sum=20.0 и temp=20.0), или это результат вычисления чего-либо? Судя по названию переменной temp - видимо результат вычисления...
Классика - с переменными действительного типа надо крайне осторожно проводить такие сравнения при вычислениях. Результат 1/3 и 3/9 может быть разным где-нибудь "в последнем знаке" и его не увидеть никогда...
Может привести к определенной точности (ну например до 6 знака) а потом уж и сравнивать...
Записан

Поживем - увидим... Доживем - узнаем... Выживу - учту  Улыбаюсь
LP
Помогающий

ru
Offline Offline

« Ответ #2 : 08-05-2005 18:01 » 

Цитата
Может привести к определенной точности (ну например до 6 знака) а потом уж и сравнивать...

Наверное имеется ввиду стандартный прием:

Код:
#include <math.h>
...
if(fabs(temp-sum)<0.000001)
//при условии что число 0.000001 достаточно мало в условиях задачи

Но это при сравнении на равенство! А как же быть при сравнении на > или < ? Про такое не слышал  Жаль
Видимо придется выполнить два действия:

Код:
//сравнение на <
if((fabs(temp-sum)>0.000001)&&(itog<sum))
т.е. сначала убедиться что операнды не равны, а потом уже сравнивать
Записан

Если эта надпись уменьшается, значит ваш монитор уносят
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 08-05-2005 19:55 » 

Цитата
Побереги печень
Спасибо Улыбаюсь, я постараюсь.
Михалыч, я в первом посте не зря написал, что все досконально проверил. Поначалу эти переменные содержали результаты вычислений, при этом на первом этапе выполнения программы они все время одинаковы (я имею ввиду, что далее они будут содержать уже значения которые сложно прогнозировать, а вначале всегда одно и тоже) и равнялись 20. Т.е. в них содержалось целое число, несмотря что тип данных вещественный. Но потом, когда до меня начало доходить, что косяк в сравнении  я стал загонять сам в них значения, т.е. я перед сравнением написал temp=20; sum=20 и глюки повторились.
Я не первый кто с этим столкнулся, мой товарищ в прошлом году с этим сталкивался (он тогда заявил, что VC++ не сравнивает числа типа double, мы дико смеялись), но после того как переустановил VC++ (шестая версия) все стало нормально. Но мне это не помогло Жаль. Версия у меня тоже шестая.
Записан

ещё один вопрос ...
Hooter
Опытный

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 08-05-2005 21:28 » 

а visual studio service pack 5 поставил?
Записан
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 08-05-2005 21:37 » 

Нет.
У меня как-то вообще проблем такого рода раньше не было.
Записан

ещё один вопрос ...
Hooter
Опытный

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 08-05-2005 21:59 » 

попробуй поставить. так, на всякий случай. SP5 вообще много ошибок исправляет в VS6. мож и здесь поможет...
Записан
Diletant
Помогающий

de
Offline Offline

« Ответ #7 : 11-05-2005 13:04 » 

Ситуация, описанная в начале вполне нормальна. Т.е. при преобразовании десятичного целого в двоичное вещественное все равно добавится  "белый шум". И неизвестно в каком из чисел он будет больше. Ну не бывает одинаковых вещественных чисел, и сравнивать е важно на равенство  или на "больше-меньше" можно только с какой-то точностью. Поэтому условие должно выглядеть примерно так

if(itog<sum(1+0.000001))
return false;


Записан
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #8 : 11-05-2005 14:39 » 

Diletant, не могу понять, чем число 20 > 20 в независимости от того сколько там нулей после запятой стоит.
Записан

ещё один вопрос ...
LP
Помогающий

ru
Offline Offline

« Ответ #9 : 11-05-2005 16:01 » 

А между прочим зря вы мой предыдущий пост не почувствовали Ага
if(fabs(temp-sum)<0.000001) - это придумал не я, это стандартное решение данной проблемы...
Сервис паки тут не помогут...
Цитата
не могу понять, чем число 20 > 20 в независимости от того сколько там нулей после запятой стоит.
Михалыч про это тебе уже говорил. Попробуй например на яндексе набрать "сравнение вещественных чисел"
или что-то в этом роде.
PS nikedeforest, не в обиду если все это показалось тебе слишком резко Улыбаюсь

Diletant,
Цитата
if(itog<sum(1+0.000001))
return false;
что это такое Не понял
Записан

Если эта надпись уменьшается, значит ваш монитор уносят
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #10 : 11-05-2005 17:12 » 

Цитата
PS nikedeforest, не в обиду если все это показалось тебе слишком резко
ничего обидного не увидел Ага.
LP, я помню что ты писал и согласен и понял я что Михалыч писал, просто в голове как-то не укладывается, я же вроде собственоручно загонял в переменные число, ну да ладно вдаваться не будем.
ЗЫ: Кстати в другом проекте сравнение двух вещественных чисел проходит без проблем.
Записан

ещё один вопрос ...
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии

il
Offline Offline
Пол: Мужской
Бодрый птах


« Ответ #11 : 11-05-2005 21:16 » 

Код:
double a,b;

a = 20.0;
b = 20.0;

if (a<b) AfxMessageBox("<");
else
if (a>b) AfxMessageBox(">");
else
            AfxMessageBox("==");
Выдает == в VC6.0 без сервис паков.

Код:
	double a,b;
double ccc,ddd;

a = 20.0;
b = 20.0;

ccc = b/3;
ddd = a/3;

ccc *=3;
ddd *=3;
if (ccc<ddd) AfxMessageBox("<");
else
if (ccc>ddd) AfxMessageBox(">");
else
AfxMessageBox("==");
Тоже выдает тот же результат...

Вывод твой глюк характерен для тебя.
Слышал о том, что на процессорах АМД есть проблемка с вычислением вещественных чисел...
Случаем не так???
Записан

А птичку нашу прошу не обижать!!!
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #12 : 12-05-2005 01:51 » 

Цитата
Слышал о том, что на процессорах АМД есть проблемка с вычислением вещественных чисел...
Случаем не так???
Не знаю, у меня Celeron.
Цитата
Вывод твой глюк характерен для тебя.
Что интересно, в других программах сравнение проходит нормально.
Записан

ещё один вопрос ...
Diletant
Помогающий

de
Offline Offline

« Ответ #13 : 12-05-2005 07:37 » 

Diletant, не могу понять, чем число 20 > 20 в независимости от того сколько там нулей после запятой стоит.
Если вычесть из одного double  числа другое нуля никогда не получить (может быт две двойки исключение, но не факт). Результатом будет скорее всего  ~1Е-22 или что-нибудь аналогичное. При сравнении двух чисел одно вычитается из другого и результат сравнивается с нулем. Вывод: Если числа одинаковые, результат будет неопределенным.
PS В способе, предложенном Михалычем, комментарий очень важен.
Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #14 : 12-05-2005 09:59 » 

Чёт я не пойму почему спор-то возникает? Это же элементарная математика.
Практически в природе нет целых чисел (если закрыть глаза на то, что природе вообще чисел нет).
Поэтому если используются вещественные числа, то всегда должна указываться (и указывается явно или косвенно) степень точности. Пэтому единственная возможность проверить две величины на равенство - сравненить модуль их разности с некоторой величиной (хотя... последний раз серьёзной математикой я занимался лет 15 назад, может что и изменилось в канонах Ага ).

А как же быть при сравнении на > или < ?

Ешё проще:
a-b>0   значит a>b
a-b<0   значит a<b
Ага

Теперь, то, о чём говорят Гром и nikedeforest - это точность связанная с конкретными условиями - в данном случае с компютером - здесь она конечная и зависит от железа и софта - процессоров, алгоритмов операций с плавающей запятой, типов данных, компиляторов и тд и тп (а так же наверно от силы космического излучения и активности солнца, чёрт её знает, можа какой-нить бариончик шандарахнет по транзистору в тот момент, когда мы хотим сравнить). И выяснять, почему это работает тут так, а там эдак ИМХО бессмысленно. Другое дело, что пользователи имеют право требовать обещанную техническим описанием точность, но реальный мир и обещания в тех. описании это не всегда одно и то же.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии

il
Offline Offline
Пол: Мужской
Бодрый птах


« Ответ #15 : 12-05-2005 10:27 » 

Не - не согласен. Для одинаковых чисел в любом представлении работает одинаковый алгоритм, поэтому, 2.0 будет всегда либо 2.0 либо 2.0 -Е23 и т.д.

При одинаковых вычислениях тоже проработает один алгоритм и мы получим одинаковые результаты которые будут сравниваться корректно.

При очень разных вычислениях могут произойти мелкие разночтения, но вы забываете, что есть величина которой можно пренебречь и в компе это учитывают, мы ведь говорим об одном и том же компе и компиляторе, так что все эти разности с разными мантиссами чисел все ИХО бредово немного.

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

А птичку нашу прошу не обижать!!!
Diletant
Помогающий

de
Offline Offline

« Ответ #16 : 12-05-2005 10:45 » 

Diletant,
Цитата
if(itog<sum(1+0.000001))
return false;
что это такое Не понял

Это учитывание той возможности, что itog и sum могут быть сами по себе меньше 0.000001. Поэтому разницу в относительных единицах сравнивать нужно.

2 Гром.
Все нынешние процессоры снабжены аппаратной реализацией операций с плавающей запятой. Поэтому иногда и рассматривания ассемблерного кода недостаточно. Нужно результаты операций смотреть.
Записан
LP
Помогающий

ru
Offline Offline

« Ответ #17 : 12-05-2005 15:47 » 

Код:
	
double d1=1.3;
double d2=1.469/1.13;    //1.3
if(d1==d2) cout<<"Equal\n";
else cout<<"NOT Equal\n";
cout<<"d1="<<d1<<endl;
cout<<"d2="<<d2<<endl;

выдает:
NOT Equal
d1=1.3
d2=1.3

Проверял на 6-м борланде и 7-й вижуал студии.
Записан

Если эта надпись уменьшается, значит ваш монитор уносят
LP
Помогающий

ru
Offline Offline

« Ответ #18 : 12-05-2005 16:11 » 

Думаю компьютер, компилятор и т.д. не виноваты  Улыбаюсь
Попробуйте поставить себя на их место. Переведите числа 1.3; 1.13; 1.469; в двоичную с.с.
затем разделите 1.469 на 1.13 и сравните с 1.3  в последних знаках  Ага
Записан

Если эта надпись уменьшается, значит ваш монитор уносят
Михалыч
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #19 : 12-05-2005 16:15 » 

Господа! Чего вы тут теории разводите? По жизни я еще не встречал программ, которые требовали бы "бесконечной" точности. Т.е. я хочу сказать, что завсегда можно (нужно???) задаться определенной точночтью (ну, как я постил выше - например 6 знаков). А по сему, поскольку ГАРАНТИРОВАННО можно сравнивать только целые числа то я иногда (пусть кому-то не покажется дииким) делаю так:
Надо мне точность 6 знаков - умножаю числа на 1000000, привожу к long (ну или во что влезет)
и сравнивая уже ЦЕЛЫЕ. Проблем нет... Конечно это не панацея и не все цифири туда влезут - размерность-то не бесконечная. Однако абсолютно универсальных приемов не существует.
А подобные приемы - if(fabs(temp-sum)<0.000001) помоему "те же грабли, только в профиль" Улыбаюсь
Все... Кидайте в меня камни Улыбаюсь
« Последнее редактирование: 13-05-2005 01:20 от Михалыч » Записан

Поживем - увидим... Доживем - узнаем... Выживу - учту  Улыбаюсь
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #20 : 13-05-2005 21:12 » 

F может быть следует от суда более простой вывод: действительные числа не надо сравнивать на равенство - достаточно больше-меньше. Если числа "практически равны", то не все ли равно, какое из низ больше?
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
LP
Помогающий

ru
Offline Offline

« Ответ #21 : 14-05-2005 11:43 » 

А как же быть при сравнении на > или < ?

Ешё проще:
a-b>0 значит a>b
a-b<0 значит a<b
Запись a-b>0 и a-b<0 принципиально не отличается от a>b и a<b. Поэтому проблемка остается:
а что если числа a и b отличаются лишь на 1Е-21 ?

Если числа "практически равны", то не все ли равно, какое из низ больше?
А если я не знаю равны они или нет, а мне просто надо узнать - получились ли, в результате вычислений, значения двух действительных чисел равными?
Записан

Если эта надпись уменьшается, значит ваш монитор уносят
Alf
Гость
« Ответ #22 : 14-05-2005 12:02 » 

Если, например, нужно совпадение с точностью до одной тысячной, можешь оценить значение выражения

Код:
abs((x-y)/x) < 0.001

вместо

Код:
x == y

Результат будет корректным независимо от значения x (разумеется, кроме нуля).
Записан
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #23 : 15-05-2005 11:53 » 

Столько премудростей, а ведь я до этого обчным образом проводил сравнение вещественных чисел и все работало, а в данном случае какое-то исключение образовалось Жаль.
Записан

ещё один вопрос ...
Alf
Гость
« Ответ #24 : 15-05-2005 17:44 » 

Если работало, значит, просто не проверял как следует. Или числа уж слишком разнились между собой. На близких числах заметил бы непременно.
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines