Posted By: Quasimodo (Quasimodo) on 'CZprogram' Title: Re: Zaokrouhlovani cisla typu Extended Date: Thu May 9 15:35:44 2002 > Ahoj. > > Ja mam obcas problemy s double/floaty. Zkomiluju to v debugovacim rezimu a > > vse jede ok. Pak 'release' a uz to pad a na division by zero, spatne se > vyhodnoti podminka typu if ( (a-b) < 0) pro cisla, kde a = b a tak podobne. > Ja to resim timhle: > > #define DOUBLE_PRECISION_CONSTANT 1e-6 > > a > > if ( (a-b) < DOUBLE_PRECISION_CONSTANT) .... > > > Je to hnus, ale zatim jsem tak zkrotil vsechny algoritmy, ktere mely > problemy > s podtekanim. Navic to funguje, i kdyz v prekladaci zadate optimalizaci :-) Mladezi, tohle se mi nejak nezda... i kdyz uz jsem to v literature podobne parkrat videl. Chyba ve floatech je snad relativni a ne absolutni. Mam prece float zapsany jako mantisa * exponent. Takze, kdyz zavzpominam jak vypada pascal, lepsi porovnani bude vypadat nejak takhle: if (abs(a * (1 + 1e-5) >= (abs(b))) and (abs(a * (1 - 1e-5)) < abs(b)) then rovna_se_to; Coz sice zafunguje dejme tomu pro stejne dobre porovnani cisel 1.000001e22 a 1.0e22 jako pro 1.0000001e-17 a 1.0 e-17, ale ma jako znacnou nevyhodu, ze to nefunguje pokud a=0.0 presne a b treba 1e-30, coz bychom radi prohlasili za shodu, pokud se doted pracovalo v radu rekneme jednotek. Tudiz zde by bylo lepsi pracovat s onou absolutni konstantou, tak jak bylo uvedeno vyse. Jenze rad hodnot s jakymi ma program pracovat nemusim vzdy znat. (Stejnou rutinku bych rad pouzil kdyz budou mit na vstupu v jednotkach SI pikofarady nebo gigawatty.) Dalsi, alternativni, jeste o malicko lepsi reseni, ktere si hlida rad promennych by bylo neco jako: epsilon:= (abs(a)+abs(b)) / 2e5; if abs(a-b) < epsilon then rovna_se_to; Ovsem protoze si svoji matikou nejsem nikdy moc jisty, tak bud rad vysledku odhadnu ze vstupnich parametru (programem) nebo pouzivam priblizne tohle: if ((abs(a + err) * (1 + 1e-5)) >= (abs(b + err) * (1 - 1e-5))) and ((abs(a + err) * (1 - 1e-5)) <= (abs(b + err) * (1 + 1e-5))) then rovna_se_to; kde do err dosazuju bud minfloat nebo uzivatelsky zadanou toleranci. Vsechny tyhle silene vyrazy jsou samozrejme trochu zkratit a optimalizovat, vypisuju je takhle rozvlacne, aby bylo jednoduse patrne co delam :-) Ten finalni vyraz muze po mensim zjednoduseni nakonec vypadat asi takhle: if (a = 0.00) then a:=err; if (b = 0.00) then b:=err; if ((a * (1+1e-5)) > b) = ((a * (1-1e-5) < b) then rovna_se_to; Tak a ted doufam, ze jsem toho moc nezvoral, jsem silene ospalej a boli me hlava... - Clovek je nejpomalejsi zname zarizeni typu I/O. Quasimodo