Dlaczego nie używać typu float i real?

13-maj-2011

SQL oferuje użytkownikom typy danych real i float. Oferują one bardzo dużą dokładność oraz możliwość zapisania w bazie danych bardzo dużych liczb. Zgodnie z informacją z Books Online:

Data type Range Storage
float – 1.79E+308 to -2.23E-308, 0 and 2.23E-308 to 1.79E+308 Depends on the value of n
real – 3.40E + 38 to -1.18E – 38, 0 and 1.18E – 38 to 3.40E + 38 4 Bytes

Te typy mają jednak także pewne wady.

 Otóż dane w nich zapisywane są w sposób przybliżony. Każdy matematyk potwierdzi, że 1,999999…. (liczba 9 w okresie) to w gruncie rzeczy z matematycznego punktu widzenia już 2. Chociaż dla normalnych ludzi, a nie dla matematyków jest niezrozumiałe…  Liczby typu float i real są zmiennoprzecinkowe i z natury nie idealnie dokładne. Co za tym idzie nie można mieć 100% pewności, że 0=0 !

Zobaczmy to na przykładzie. Ile razy wykona się taka pętla?

DECLARE @f float;
SET @f = -1;
WHILE @f <> 0
 BEGIN
  PRINT @f;
  SET @f=@f+0.1;
 END 
GO
Wydawało by się, że skończy się w memencie gdy @f przyjmie wartość zero. A tymczasem na moim kompterze pętla wykonywała się w nieskończoność i trzeba ją było przerwać, zaś na karcie messages wyświetliło się:
-1
-0.9
-0.8
-0.7
-0.6
-0.5
-0.4
-0.3
-0.2
-0.1
-1.38778e-016
0.1
0.2
0.3
0.4
0.5……
 

O rety! Po wartości -0.1 pojawiła się strasznie mała liczba (rzeczywiście bliska zeru), ale nie zero. Ale nawet gdzy zmieniłem konstrukcję pętli i PRINT wyświetliło „zero”, to i tak nie spowodowało to przerwania pętli. Zobacz np ten fragment kodu dla typu real:

DECLARE @r real;
SET @r = 0;
WHILE @r <> 1
 BEGIN
  PRINT @r;
  SET @r=@r+0.1;
 END

 To też jest pętla nieskończona, chociaż polecenie PRINT wyświetliło:

0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1
1.1
1.2
1.3
1.4…

Tak więc, jeśli piszesz aplikację biznesową, a nie naukową staraj się unikać typów float i real, no chyba że szekasz kłopotów….

Przy okazji – real to to samo co float(24), gdzie 24 oznacza ilość bitów przeznaczonych na przechowywanie mantysy liczby.

Komentarze:

  1. Anonim napisał,

    […] Ot zmieni? typ (wi?cej o typach i zwi?zanych z nimi przygodami znajdziesz na Mobilo / mobilo24 tutaj)? DECLARE @smallValue int SET @smallValue = 20000 + 20000 SELECT […]

Autor: Rafał Kraik