Модераторы: bsa
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Точность чисел с плавающей запятой 
V
    Опции темы
IKM2007
  Дата 14.5.2008, 16:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Зима близко
**


Профиль
Группа: Участник
Сообщений: 702
Регистрация: 26.4.2008
Где: olmedreca

Репутация: 3
Всего: 40



Добрый день всем,
ответьте вот на такой вопрос. Как выполняется прибавление или убавление чисел типа double.
Вот на примере.
Код

#include <iostream>
using namespace std;
void main()
{
cout<<(4.2-3.2==2.2-1.2)<<endl;//   0
cout<<(4.2-3.2<2.2-1.2)<<endl;//     1
cout<<(4.2-3.2>2.2-1.2)<<endl;//     0
}

то есть условие (4.2-3.2<2.2-1.2) верно.
Но вот...
Код

#include <iostream>
using namespace std;
void main()
{
cout<<(4.2-3.2==2.2-1.2)<<endl;//       0
cout<<(44.2-33.2<22.2-11.2)<<endl;//       0
cout<<(4.2-3.2>2.2-1.2)<<endl;//       0
}

то есть ни одно условие не верно.
Может кто нибудь обяснит мне, что здесь творится?


--------------------
"К чёрту обстоятельства, я создаю возможности."
Брюс Ли
PM MAIL Skype   Вверх
rrrFer
Дата 14.5.2008, 17:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 208
Регистрация: 11.5.2008
Где: Красноярск

Репутация: 0
Всего: 1



ИМХО парадокс  smile
интересно что:
Код

#include <iostream>
using namespace std;
bool f(double a,double b,double c,double d);
void main(){
    cout<<(4.2-3.2==2.2-1.2)<<endl;
    cout<<f(4.2,3.2,2.2,1.2)<<endl;
    cout<<(4.2-3.2>2.2-1.2)<<endl;
    getchar();
}
bool f(double a,double b,double c,double d){
    if(a-b<c-d)
        return 1;
    return 0;
}
смотрю что передано в функцию f:
    a    4.2000000000000002    double
    b    3.2000000000000002    double
    c    2.2000000000000002    double
    d    1.2000000000000000    double
вообще погрешности большие почему-то:
если написать
Код

cout<<f(1.2,0.2,1.3,0.3)<<endl;

то в функцию f передано:
    a    1.2000000000000000    double
    b    0.20000000000000001    double
    c    1.3000000000000000    double
    d    0.29999999999999999    double


Это сообщение отредактировал(а) rrrFer - 14.5.2008, 17:27
PM MAIL WWW ICQ   Вверх
anatox91
Дата 14.5.2008, 17:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


программист-самоучка
**


Профиль
Группа: Участник
Сообщений: 699
Регистрация: 12.1.2008
Где: ++Украина.Крым++

Репутация: 1
Всего: 13



мдаа.. попробовал - действительно...


--------------------

The code is the design ©

Sony VAIO VGN-FW480J

user posted image
PM MAIL ICQ   Вверх
rrrFer
Дата 14.5.2008, 17:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 208
Регистрация: 11.5.2008
Где: Красноярск

Репутация: 0
Всего: 1



а еще вот что получилось:
Код

#include <iostream>
using namespace std;
void main(){
    float d;
    scanf("%f",&d);
    printf("To-4To BBeJ|:\n%.20f\n\nkoHcTaHTa:%.20f\n",d,1.2);
    system("pause");
}

при вводе числа 2.5 все нормально, погрешности не видно вообще, а вот если ввести 1.2....
PM MAIL WWW ICQ   Вверх
Gradov
Дата 14.5.2008, 18:32 (ссылка)    | (голосов:7) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 124
Регистрация: 31.10.2006

Репутация: нет
Всего: 3



Цитата(IKM2007 @  14.5.2008,  16:51 Найти цитируемый пост)
то есть ни одно условие не верно.Может кто нибудь обяснит мне, что здесь творится?


Числа с плавающей запятой необходимо сравнивать только предварительно переведя их в строковую переменную. И уже после этого сравнивать строки а не числа с плавающей запятой!

Данная операция необходима для исключения погрешностей, которые возникают из-за особенностей самого формата хранения чисел с плавающей запятой.
PM MAIL   Вверх
JackYF
Дата 14.5.2008, 18:58 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


полуавантюрист
****


Профиль
Группа: Участник
Сообщений: 5814
Регистрация: 28.8.2004
Где: страна тысячи озё р

Репутация: 6
Всего: 162



Цитата(Gradov @  14.5.2008,  17:32 Найти цитируемый пост)
Числа с плавающей запятой необходимо сравнивать только предварительно переведя их в строковую переменную. И уже после этого сравнивать строки а не числа с плавающей запятой!

Феерическая фигня. Перевод в строковую форму занимает туеву хучу процессорного времени.

Сравнение чисел с плавающей точкой можно сравнивать только с учётом допуска некой малой величины E. То есть, к примеру:
Код

const double E = 1E-5
double x, y;
//...
if (x + E < y)
{
  // x is really less than y...
}

Само собой, E выбирается в зависимости от нужной точности и алгоритма.


--------------------
Пожаловаться на меня как модератора можно здесь.
PM MAIL Jabber   Вверх
nickless
Дата 14.5.2008, 19:17 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гентозавр
****


Профиль
Группа: Участник Клуба
Сообщений: 2976
Регистрация: 29.8.2005
Где: Germany

Репутация: 2
Всего: 181



Цитата(Gradov @  14.5.2008,  17:32 Найти цитируемый пост)
Числа с плавающей запятой необходимо сравнивать только предварительно переведя их в строковую переменную.

Код

if (isDone.toString().length() == 4) {
    // do stuff
}

 smile 

Просто сравнивать надо с погрешностью эпсилон, например так:
Код

const double eps = 1.0e-10;
if (1.2 - eps < f && f < 1.2 + eps) { // f == 1.2
    // code
}

Просто числа хранятся в двоичном виде, по этому число 1.2 = 1 + 1/5 точно представить невозможно, можно только приближенно.
Например в double точность мантиссы 52 бит, т.е. погрешность будет где-то +- 0.5 * 1/(2^52) ~ 1.110223e-16

Это сообщение отредактировал(а) nickless - 14.5.2008, 19:18


--------------------
user posted image

Real men don't use backups, they post their stuff on a public ftp server and let the rest of the world make copies
- Linus Torvalds
PM MAIL   Вверх
archimed7592
Дата 14.5.2008, 19:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 6
Всего: 93



Ещё, варианты:
1. Написать класс-обёртку над double(в идеале, над произвольным типом T), который будет проделывать операции сравнения с заданной точностью автоматически.
2. Использовать арифметику с бесконечной точностью(т.н. exact types): GMP, boost::rational, CGAL::Quotient, CGAL::Gmpzf(обёртка над gmp_mpf_class) и пр.
3. Использовать арифметику с неограниченной, но, задаваемой точностью(преимущество в том, что в отличии от exact types с ними можно проделывать такие операции, по определению невозможные для exact types как то sin, cos, sqrt, etc.): MPFR, mpfr::Real(С++ обёртка из MPFR_CPP).

Ссылки на все вышеупомянутые классы/библиотеки можно нарыть в гугле.

ЗЫ. Помню, как лет 5 назад я матерился на Delphi, когда обнаружил в нём "ошибку" из-за которой иногда получается отрицательный ноль из-за чего не работала вычислительная часть одного из моих проектов smile.
На самом деле - это всего лишь отрицательное бесконечно малое, которое, кстати тоже является почвой для долгих поисков мифического бага smile.


--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
IKM2007
  Дата 14.5.2008, 20:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Зима близко
**


Профиль
Группа: Участник
Сообщений: 702
Регистрация: 26.4.2008
Где: olmedreca

Репутация: 3
Всего: 40



Всем Большое Спасибо, все понятно. smile 


--------------------
"К чёрту обстоятельства, я создаю возможности."
Брюс Ли
PM MAIL Skype   Вверх
xvr
Дата 15.5.2008, 11:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Цитата(archimed7592 @ 14.5.2008,  19:25)
ЗЫ. Помню, как лет 5 назад я матерился на Delphi, когда обнаружил в нём "ошибку" из-за которой иногда получается отрицательный ноль из-за чего не работала вычислительная часть одного из моих проектов smile.
На самом деле - это всего лишь отрицательное бесконечно малое, которое, кстати тоже является почвой для долгих поисков мифического бага smile.

Сугубо точности ради  smile В floating point формате знак числа хранится отдельно, так что вполне возможен и реальный отрицательный ноль (float - 0x80000000).

PM MAIL   Вверх
archimed7592
Дата 15.5.2008, 12:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 6
Всего: 93



Цитата(xvr @  15.5.2008,  11:39 Найти цитируемый пост)
Сугубо точности ради  smile В floating point формате знак числа хранится отдельно, так что вполне возможен и реальный отрицательный ноль (float - 0x80000000).

Если мне не изменяет память, этот самый отрицательный ноль и интерпретируется как отрицательное бесконечно малое... Разве нет?


--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
xvr
Дата 15.5.2008, 13:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Цитата(archimed7592 @ 15.5.2008,  12:44)
Цитата(xvr @  15.5.2008,  11:39 Найти цитируемый пост)
Сугубо точности ради  smile В floating point формате знак числа хранится отдельно, так что вполне возможен и реальный отрицательный ноль (float - 0x80000000).

Если мне не изменяет память, этот самый отрицательный ноль и интерпретируется как отрицательное бесконечно малое... Разве нет?

Нет.
Код

Class             Sign Biased Exponent    Significand
                                       Integer  Fraction
Negative -Zero      1     00..00           0     00..00
         -Denormals 1     00..00           0     00..01
                         .
                         .
                    1     00..00           0     11..11

Integer - implied (not stored)


Это сообщение отредактировал(а) xvr - 15.5.2008, 13:26
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0649 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.