2015-05-06 9 views
7

Na przykładW jaki sposób kompilatory C i C++ implementują decyzję równości dla liczb zmiennoprzecinkowych?

float a = 1.0; 
float b = 1.2; 

puts(a == b? "equal": "not equal"); 

zajmuje kompilatora z nim bitwisely lub za pomocą innych metod?

(wiem, że nie jest to dobry wybór, aby zdecydować, równość liczb zmiennoprzecinkowych przez „==”, po prostu chcę wiedzieć, jak kompilator oferty z tej sytuacji.)

+1

Jaka jest różnica między wartością bitową a wartością? Z pewnością są takie same dla pływających –

+0

@EdHeal wszystko w porządku, problem jest edytowany – Wizmann

+5

Wszystkie liczby zmiennoprzecinkowe są przechowywane w ** IEEE-754 Format zmiennoprzecinkowy **. Są one albo ** 32-bitowe ** (zmiennoprzecinkowa pojedyncza precyzja), albo ** 64-bitowe ** (zmiennoprzecinkowa podwójna precyzja). Znaczenie oznacza liczbę całkowitą dla każdej liczby zmiennoprzecinkowej na podstawie bitów w pamięci. Kompilator obsługuje go w ten sam sposób, w jaki robi liczbę całkowitą o równoważnym rozmiarze. Zobacz: [** Przewodnik po floodzie - Co każdy programista powinien wiedzieć ... **] (http://floating-point-gui.de/) –

Odpowiedz

5

Ogólna, pełna odpowiedź jest taka, że ​​numery zmiennoprzecinkowe są porównywane zgodnie ze specyfikacją IEEE 754.

Aby odpowiedzieć na to pytanie konkretnie, większość czasu dwie liczby zmiennoprzecinkowe są porównywane bitowego, z kilku wyjątkowych przypadkach:

  • pozytywnych i negatywnych zera są uznawane za równe
  • NaN jest uważany nierówny wszystko, nawet NaN samego
  • Subnormals może porównać równe zeru i innych subnormals w niektórych trybach pracy (na przykład „gładkimi subnormals do zera”)
  • innych niż te ex ceptions, regularne porównanie bitowe jest używane
+3

... z wyjątkiem, oczywiście, gdy system nie używa zmiennoprzecinkowego interfejsu IEEE (np. Niektóre komputery mainframe IBM nadal nie działają, sporo układów GPU nie działa, przynajmniej zwykle). –

+1

C++ nie wymaga IEEE754 (chociaż [istnieje zmienna statyczna, którą można sprawdzić, aby sprawdzić, czy jest używana ieee754] (http://stackoverflow.com/questions/5777484/how-to-check-if-c-compiler -use-ieee-754-zmiennoprzecinkowy-standardowy)). –

1

Ja zakładając, że znaczy po skompilowaniu programu, w jaki sposób porównuje on dwie zmienne. Sposób, w jaki przechowywane są pływaki, jest bardzo unikalny. Jest przechowywany przez znak, wykładnik i ułamek, jak widać here. Dlatego, o ile nie jest absolutnie równy, program zobaczy nawet 1 i 1.000000000001 jako różne. Aby sprawdzić, czy są one prawie równe, można użyć następujących:

bool AlmostEqualRelativeOrAbsolute(float A, float B, 
      float maxRelativeError, float maxAbsoluteError) 
{ 
    if (fabs(A - B) < maxAbsoluteError) 
     return true; 
    float relativeError; 
    if (fabs(B) > fabs(A)) 
     relativeError = fabs((A - B)/B); 
    else 
     relativeError = fabs((A - B)/A); 
    if (relativeError <= maxRelativeError) 
     return true; 
    return false; 
} 

Kod jest otrzymywany z here, może chcesz przeczytać więcej na stronie.

3

gcc i clang korzystają z instrukcji UCOMISS x86/x64.

Źródło: tried it z -O3 i sprawdzono dane wyjściowe zespołu.

+5

Mówiąc bardziej ogólnie, kompilator tworzy instrukcję specyficzną dla architektury do porównywania liczb zmiennoprzecinkowych, jeśli architektura obsługuje dla nich sprzęt - na przykład x86, x86-64 i ARM - w przeciwnym razie wysyła sekwencję instrukcji implementujących wymagane zachowanie przy użyciu standardu zmiennoprzecinkowego, prawie zawsze IEEE-754. –

Powiązane problemy