Название: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: Dimon-st от Июля 19, 2010, 13:29 Всем привет !
Столкнулся с банальной, но неприятной и неразрешимой (пока) ситуацией при простой операции деления с вещественными числами. Суть проблемы: при делении меньшего числа на большее число (по величине отличаются в 10 раз) результат получается: "0.10000000000000001" (и при отладке и при при прогоне программы). Причем результат не зависит от типа вещественных данных (пробовал qreal, double, long double). Вот фрагмент кода: Код: double vX, vY, vRez; Кроме того, при принудительном присваивании переменной значения "vX=0.1;", результат получается "vX=0.10000000000000001". :o ??? Код: long double vX; Пробовал округлять, но при нем вываливается тот же косяк.... У меня нет больше вариантов как с этим бороться ..... Использую Qt Creator (Qt 4.7.0 (32-битн.)) от Nokia Corp. Пожалуйста, помогите ! :'( Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: ecspertiza от Июля 19, 2010, 14:24 Для вещественных чисел это обычная погрешность.
для сравнения используй Код: if (fabs(a - b) < 1e-6) Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: Wlad_C от Июля 19, 2010, 14:25 С чем бороться?
То, что Вы получаете - так и должно быть! Это происходит при переводе из двоичной системы в десятичню. Можете проверить ручками! Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: Dimon-st от Июля 19, 2010, 14:39 Цитировать С чем бороться? То, что Вы получаете - так и должно быть! Это происходит при переводе из двоичной системы в десятичную. Можете проверить ручками! Я допускаю такое при делении, но при присваивании ???? Код: long double vX; при выполнении этого фрагмента получается "vX=0.10000000000000001". Может у кого по другому? Отпишитесь ..... Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: ecspertiza от Июля 19, 2010, 14:50 Боюсь что нет :) Это нормально вроде как :) а какие трудности в вязи с этим?
Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: Dimon-st от Июля 19, 2010, 15:10 Да, проблемы есть.
Разрабатываю класс, и в одном (именно этом) случае, он лагает. :( Имеется 4 числа: начальное, конечное значения, шаг и количество: vFirstValue, vLastValue, vStep, vCount. Изменяя одно из значений, пересчитываются остальные (или одно из них). При следующих данных: vLastValue=10, vFirstValue=0 задаем: vCount=101 и пересчитываем vStep и vFirstValue Получаю vStep=0.10000000000000001 vFirstValue=-5.55112e-16 Хотя, по идее должно быть: vStep=0.1 vFirstValue=0 Как этого добиться ? Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: SimpleSunny от Июля 19, 2010, 16:20 "-5.55112e-16" можно сказать, что 0. Какая проблема?
Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: Sancho_s_rancho от Июля 19, 2010, 17:42 Код: qFuzzyCompare ( double p1, double p2 ) [static] И обратите внимание на Код: // Instead of comparing with 0.0 Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: Dimon-st от Июля 19, 2010, 18:51 Цитировать "-5.55112e-16" можно сказать, что 0. Какая проблема? Проблема в том, что именно так он выдает и при преобразовании числа в стоку (без форматирования), хотя хотелось бы "0".Сравнение чисел в данном алгоритме не подходит Цитировать qFuzzyCompare(0.0,1.0e-200); Пробовал принудительно так: Код: if (vStep!=10.0) Программисты Qt, пожалуйста отпишитесь, у всех при отладке после банального присвоения "vStep=1.0e-1;" получается "vStep=0.10000000000000001"? Протестировал в BDS и MSVS2008, там все работает без всяких проблем. Не знаю что и думать, версия Qt у меня такая глючная, или я уже ничего не понимаю... Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: m_ax от Июля 19, 2010, 18:58 QString QString::number ( double n, char format = 'g', int precision = 6 ) [static]
Не вижу проблемы.. P.S. так вспомнилось: Российским учёным первыми в мире удалось раздуть из мухи слона ;D Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: Igors от Июля 19, 2010, 19:01 В дополнение к сказанному
- др. отладчики также показывают подобным образом - для чисел с конечным числом знаков после запятой равенство срабатывает, напр Код: float t = 1.0f; - пример c 1.0e-200 специфичен, насколько я помню: диапазон от 1.0e-38 до 1.0e+38 (для всех float, double и др., разница между ними в точности). Меньшие значения INF - не ноль, но и значение неизвестно Edit: см. также недавнее обсуждение http://www.prog.org.ru/topic_14154_0.html (http://www.prog.org.ru/topic_14154_0.html) Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: Dimon-st от Июля 19, 2010, 19:21 Цитировать Российским учёным первыми в мире Шутку оценил ! Но мне искренне не понятно: почему в BDS и MSVS код "1.0/10.0=0.1" работает без проблем, а в Qt банальное "x=1.0e-1;", приводит к "х=0.10000000000000001"? (получается риторический вопрос) ;Dудалось раздуть из мухи слона Как я понял от этого косяка не избавиться, единственное, что можно - воспользоваться округлением. Поэтому вопрос такой: есть ли какие стандартные функции округления, или придется извращаться через преобразование в строку и обратно "QString QString::number ( double n, char format = 'g', int precision = 6 )" ? Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: m_ax от Июля 19, 2010, 19:40 Вы там что, поправку к сверхтонкой структуре считаете, чтоль?
Сейчас Вам кто-нить расскажет, что дело здесь вовсе не в кутэ.. Так что не надо крошить на Qt)) Ответ кроется в том, как представляются числа с плавающей точкой.. Спросите у гугла, как устроен double, например) Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: Dimon-st от Июля 19, 2010, 19:56 Цитировать Ответ кроется в том, как представляются числа с плавающей точкой.. Спросите у гугла, как устроен double, например) Я знаком со структурой double и float, и на Qt никто не "крошит". Просто неясно: если в BDS, MSVS и Qt структуры типов данных одинаковые, то почему результаты BDS, MSVS и Qt - разные ? Может это быть из-за того, что установленная у меня версия Qt Creator "кривая" ? Поэтому я и просил протестировать на др. компах небольшие фрагменты кода.Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: Igors от Июля 19, 2010, 20:18 Просто неясно: если в BDS, MSVS и Qt структуры типов данных одинаковые, то почему результаты BDS, MSVS и Qt - разные ? Результаты - одинаковые и здесь и там. Просто "здесь" отладчик показывает с большей точностью - вот и всеНазвание: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: Dimon-st от Июля 19, 2010, 20:22 Никаких стандартных функций округления я не нашел. Таким образом придется извращаться через преобразование в строку и обратно "QString QString::number". Правильно я понимаю ?
Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: SimpleSunny от Июля 19, 2010, 20:24 Я всё еще понять не могу, чем вас не устраивает точность числа порядка e16?
Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: Dimon-st от Июля 19, 2010, 20:49 Цитировать Я всё еще понять не могу, чем вас не устраивает точность числа порядка e16? Точность устраивает, просто для моего примера:Цитировать vLastValue=10, vFirstValue=0 вместе с изменением vStep=0.10000000000000001 изменяется и vFirstValue=-5.55112e-16. И бороться с этим можно только округлением, но для этого придется всякий раз определять количество значащих разрядов vStep, которых больше, чем должно быть ... и опять замкнутый круг...задаем: vCount=101 и пересчитываем vStep и vFirstValue vStep = (vLast - vFirst)/(vCount-1.0); vFirstValue = vLast - vStep *(vCount-1.0); Получаю vStep=0.10000000000000001 vFirstValue=-5.55112e-16 Хотя, по идее должно быть: vStep=0.1 vFirstValue=0 Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: SimpleSunny от Июля 19, 2010, 21:05 "То ли лыжи не едут, то ли я неординарный."
Если точность вас устраивает, как вы заметили выше, то в чем проблема, если vFirstValue == 0 с точностью, которая вас устраивает? P.S. vFirstValue = vLast - vStep *(vCount-1.0); Если подставить vStep и раскрыть скобки, то получим vFirstValue = vFirst; Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: Igors от Июля 19, 2010, 21:09 вместе с изменением vStep=0.10000000000000001 изменяется и vFirstValue=-5.55112e-16. И бороться с этим можно только округлением, но для этого придется всякий раз определять количество значащих разрядов vStep, которых больше, чем должно быть ... и опять замкнутый круг... Вам не с чем бороться - Вы имеете точно те же числа что и в MSVC и др. (там где все устраивает). Это просто "трусы линяют" как в старом анекдоте :)Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: Dimon-st от Июля 19, 2010, 21:17 Цитировать Если подставить vStep и раскрыть скобки, то получим vFirstValue = vFirst; Логично, только вот компьютер раскрывать скобки и упрощать выражения не умеет. При изменении vCount=101 (вместо vCount=11) в алгоритме изменяются значения vStep и vFirstValue по приведенным выше формулам. И погрешность закравшаяся в vStep приводит к изменению vFirstValue, хотя по идее она не должна меняться.Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: Dimon-st от Июля 19, 2010, 21:39 Цитировать Это просто "трусы линяют" как в старом анекдоте Ссылочку на анекдот не дадите ? Просто интересно стало. :)(извиняюсь, что не по теме) Название: Re: Неожиданный результат при делении (1.0/10.0=0.10000000000000001 ?????????) Отправлено: Igors от Июля 20, 2010, 13:49 Ссылочку на анекдот не дадите ? Просто интересно стало. :) http://prikol.i.ua/user/1920258/?p=3 (http://prikol.i.ua/user/1920258/?p=3) |