![]() |
|
Модераторы: bsa |
![]()
|
|
| peanucm |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 4 Регистрация: 10.3.2008 Репутация: нет Всего: нет |
Здрасьте всем. Столкнулся с такой проблемой: при использовании переменной double в С++, компилятор (visual C++ 7.1) вместо ее значения использует значение, отличающееся на микроскопическую величину, что однако ж приводит к кардинальному изменению в результате программы. Например, в ф-ю принимающую переменную типа double передается значение 0.57, однако ж когда я смотрю ее значение через отладчик, выясняю, что компилятор реально передает 0.56999999999999995. В самой же функции у меня стоит выделение целой части числа, что приводит к совершенно неправильному результату, т.к. вместо 0.57 получается 0.56. Причем это явление не поддается никакой закономерности - какие-то числа он изменяет подобным образом, а какие-то нет, какие-то занижает, какие-то завышает. Подскажите пожалуйста, что же это такое и как с этим бороться?
|
|||
|
||||
| maxim1000 |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 3334 Регистрация: 11.1.2003 Где: Киев Репутация: 1 Всего: 110 |
можно использовать более традиционное округление - к ближайшему, а не к ближайшему меньшему
функции не помню, но смысл такой: int(x+0.5) тогда если дробная часть была меньше 0.5, она будет просто отброшена если больше - округлится в бОльшую сторну Добавлено через 38 секунд а... ещё надо посмотреть будет, как оно с отрицательными работает... -------------------- qqq |
|||
|
||||
| peanucm |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 4 Регистрация: 10.3.2008 Репутация: нет Всего: нет |
Проблема не с округлением, а с тем, что он неправильное число ставит - я ему 0.57 пишу, а он его меняет - ну ваще беспредел какой-то. Тем более, что мне не округление нужно, а выделение целой части, хотя это только пример того, к каким неправильностям приводят подобные изменения, их можно привести и больше. Вопрос в том, почему он так воспринимает некоторые double числа, может в конце числа что-то надо ставить, либо вначале какую-нить волшебную директиву препроцессора написать?
|
|||
|
||||
| JackYF |
|
|||
![]() полуавантюрист ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 5814 Регистрация: 28.8.2004 Где: страна тысячи озё р Репутация: 6 Всего: 162 |
число 0.57 не может быть отображено точно в двоичной памяти компьютера. Никто ничего не меняет. |
|||
|
||||
| Alexeis |
|
|||
![]() Амеба Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 4 Всего: 459 |
Просто число 0.57 в двоичной системе получается с периодом. Примерно так как в десятичной нельзя представить 2/3. Это ж вам не калькулятор -------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
| comcon1 |
|
||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 838 Регистрация: 11.6.2005 Где: Москва ДАС-МГУ Репутация: нет Всего: 17 |
если нужна высокая точность - юзайте gmp (gnu multiply precision). Если юзаешь double и нужна точность, пиши обёртки для сравнения. Я в свое время скачал на винграде обертку от earnest:
Добавлено через 4 минуты и 27 секунд подключаешь эту фигулину и юзаешь так
|
||||
|
|||||
| peanucm |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 4 Регистрация: 10.3.2008 Репутация: нет Всего: нет |
Я в шоке от ответов...честно.....
Вообще пишется программа для подсчета интеграла от сингулярной функции. Рассмотрим след. участок проги: double z,x1,x2,y1,y2,n=10000; int i1,i2; z=0.57; i1=(int)(z*n); после этой строчки i1 должно равняться 5700, а компилятор дает 5699 i2=i1+1; соответственно после этой i2 должно равняться 5701, а компилятор дает 5700 if ((i1/n-z)==0) i1=i1-1; после этой строчки i1 должно равняться 5699, так и есть, но не из-за того, что условие удовлетворилось, а из-за того, что оно стало таким еще выше x1=(double)i1/n; x2=(double)i2/n; y1=f(x1)*x1/(z-x1); y2=f(x2)*x2/(z-x2); Т.к. i2 не увиличилась должным образом до 5701, то i2/n, т.е. x2 оказывается равной z, в результате чего y2 равно бесконечности - проще говоря сингулярность попадает в узловую точку, когда я методом трапеций подсчитываю. В принципе можно все это помножить на n, тогда i2, т.е. x2*n не будет равно z*n в знаменателе...но это же пардон маразм. Вот вы все говорите, что double число не точное...Но мне же нужно производить с ним точную операцию сравнения - равно-неравно. Как тогда быть то? comcon1, неужели все так сложно, а проще нельзя? |
|||
|
||||
| Alexeis |
|
|||
![]() Амеба Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 4 Всего: 459 |
Это бесполезно. Так никто не делает. Нужно вычислять модуль разности чисел и проверять чтобы он был меньше требуемой погрешности (маленького числа, например 1e-6) -------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
| comcon1 |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 838 Регистрация: 11.6.2005 Где: Москва ДАС-МГУ Репутация: нет Всего: 17 |
чувак, я ж тебе кинул обёртку - ее и юзай. Или тебе лень fcmp( перед переменной дописывать? Думаешь, ты один математикой занимаешься??
проблема, что оператор == вещественных чисел нельзя юзать - это проблема с такоооой бородой! странно, что ты впервые об этом услышал.
аахахаха - зацените это предложение в отрыве от контекста!! НЕ лИЖИ ОКТАЭДР! ЮЗАЙ ОБЁРТКУ! Это сообщение отредактировал(а) comcon1 - 10.3.2008, 16:13 |
|||
|
||||
| baldina |
|
||||||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 15 Всего: 101 |
peanucm, в компьютерах числа с плавающей запятой (в отличие от целых) представляются с конечной точностью. Фактически мы манипулироем не множеством действительных чисел, а его подмножеством. Это все должны знать, а уж кто математику считает - тем более.
Сравнивать оператором == числа double можно лишь в случае, если они НЕ получены в результате вычислений, т.е. почти никогда. Сравнивать надо по формуле
Здесь epsilon - относительная погрешность. Округлить double до int можно так:
соответственно строка
а вообще то, вот так не проще будет?
comcon1, обертка интересная. Подумай, почему бы вместо struct _FloatPrec не использовать std::numeric_limits? ;) |
||||||||||
|
|||||||||||
| korian |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 651 Регистрация: 8.3.2008 Где: Украина, Харьков Репутация: 2 Всего: 17 |
peanucm
для всех вычислений используйте один типа переменных, пока все переменные не будут вычеслены
в данном случае, если не приводить к int, то будет не 5699, а 5699.99999999999 сравнение значений с плавующей точкой, как тут уже было сказано, надо производить в таком виде: double x,y; count double epsilon = 1e-6; ... вместо if (x == y) пишем if (fabs(x - y) < epsilon) можна так писать, но лучше использовать какую-нибудь обертку (для того, чтобы код был более читабельным) например, использовать, то что предложил comcon1 Это сообщение отредактировал(а) korian - 10.3.2008, 17:02 |
|||
|
||||
| comcon1 |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 838 Регистрация: 11.6.2005 Где: Москва ДАС-МГУ Репутация: нет Всего: 17 |
да не моя это обертка, а earnest - модератор С++ раздела. Очень грамотная девушка, кстати.
она ее выложила, когда только на форум пришла, а я вот сохранил)) (ну потому как юзал) |
|||
|
||||
![]()
|
| Правила форума "C/C++: Для новичков" | |
|
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Для новичков | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |