1

Тема: Це цікаво!

double a = 2;
a += 0.4;
a += 0.4;
a += 0.4;

if(a == 3.2)
   cout << "yeaah!";

через особливості внутрішнього представлення даних в пам'яті комп'ютера дана умова не виконується!

хоча, якщо провести математичні операції в нашій рідній 10-вій системі числення
а = 2 + 0.4 + 0.4 + 0.4 = 3.2
проблема полягає в тому що число 0.4(10) = 0.6666666(16) - а саме так воно представиться в пам'яті комп'ютера
робимо зворотнє перетворення до десяткової системи числення
0.66666(16) = 0.39999(10)
і бачимо що 0.4 != 0.39999, тому треба очікувати некоректного результату
2 + 0.39999+ 0.39999 + 0.39999 = 3.1999999(наближено)
3.2 != 3.199999

отакі-то справи)
досить багато дробових чисел при переведенні до 16 системи дають не зовсім правильний результат
Буду радий почути цікаві ідеї щодо усунення цієї проблеми :)

2

Re: Це цікаво!

Проблема відома. Для вирішення треба вибрати "міру рівності" тобто максимальну прийнятну різницю між числами щоб їх вважати рівними. Тоді найпростіше порівняння буде типу

if(fabs(a - b) < 0.000001)

Але метод поганий, бо константа може виявитись завеликою.

Отут описаний кращий метод

Maybe a = Just a | Nothing
Подякували: Chemist-i1

3

Re: Це цікаво!

Використовувати float для "a" чи double але з round() ?

=)

4

Re: Це цікаво!

Спробуй так

if (fabs(a-b) <= DBL_EPSILON * fmax(fabs(a),fabs(b)))
double a = 2;
    a += 0.4;
    a += 0.4;
    a += 0.4;
    if (fabs(a - 3.2) <= DBL_EPSILON * fmax(fabs(a), fabs(3.2)))
        cout << "yeaah!";

5 Востаннє редагувалося mich_retten (08.07.2015 11:28:35)

Re: Це цікаво!

vector9 написав:
double a = 2;
a += 0.4;
a += 0.4;
a += 0.4;

if(a == 3.2)
   cout << "yeaah!";

double tmp = 3.2;
cout << (*(unsigned long long*)&a >> 2 == *(unsigned long long*)&tmp >> 2 ? "yeaah!" : "ne yeaah";

Якщо треба точніше, краще щось інше використовувати. Почитайте цю гілку:
http://stackoverflow.com/questions/1531 … type-for-c

Подякували: Yola1

6 Востаннє редагувалося Yola (07.07.2015 14:20:32)

Re: Це цікаво!

mich_retten написав:

bla-bla-bla

Вибачте пане, але ваш код не працює. Наводжу приклад числами одинарної точності.

void baz(float a, float b)
{
    cout << (*(unsigned int*)&a >> 2 == *(unsigned int*)&b >> 2 ? "yeaah!" : "ne yeaah");
}
...
    float a = 3.2f;
    float b = nexttowardf(a, a+1);
    baz(a, b);
...
    float a = 3.2f;
    float b = a+1;
    baz(a, b);
...
    float a = 1.17549435082228750796873653722E-38;
    float a = 5.87747175411143753984368268611E-39;
    baz(a, b);

Перші два випадки працюють правильно, але у третьому випадку числа повинні вважатись однаковими, але це не так.

Річ у тім, що ви не врахували можливість поступової втрати розрядів.

Двійкове представлення:
перше число
друге число

PS. Ці числа таки повинні вважатись відмінними, але залишаю повідомлення для історії

ukrainian.stackexchange.com - це питання-відповіді з української мови

7

Re: Це цікаво!

Взагалі для чисели з плаваючою точкою застосовувати = не варто. тільки більше менше.