Vartotojo vardas:
Slaptažodis:
Prisiminti:
Paslėpti:
 

Visos datos yra UTC + 2 valandos [ DST ]




Naujos temos kūrimas Atsakyti į temą  [ 12 pranešimai(ų) ] 
Autorius Žinutė
 Pranešimo tema: Floating point tikslumas...
StandartinėParašytas: 2004-10-22 12:55:42 
Atsijungęs
Vartotojo avataras

Užsiregistravo: 2004-02-03 07:36:24
Pranešimai: 1165
Miestas: Vilnius
Chia shiaip del idomumo. Atrodo simple skaichiavimai, tachiau tikslumas shokiruoja! Jau po 1k karto ishryshkeja klaida... Tiesa pasakius buvau labai nustebes!

Kodas:
   int i;
   float f = 0.0f;
   double d = 0.0f;

   for (i = 20; i--;) {
      printf("  %2.20f \t %2.20f\n", f, d);
      f += 0.1f;
      d += 0.1f;
   }

   for (i = 1000; i--;) {
      f += 0.1f;
      d += 0.1f;
   }
   printf("\n  %2.20f \t %2.20f\n", f, d);


rezultatai...

Kodas:
  0.00000000000000000000         0.00000000000000000000
  0.10000000149011612000         0.10000000149011612000
  0.20000000298023224000         0.20000000298023224000
  0.30000001192092896000         0.30000000447034836000
  0.40000000596046448000         0.40000000596046448000
  0.50000000000000000000         0.50000000745058060000
  0.60000002384185791000         0.60000000894069672000
  0.70000004768371582000         0.70000001043081284000
  0.80000007152557373000         0.80000001192092896000
  0.90000009536743164000         0.90000001341104507000
  1.00000011920928960000         1.00000001490116120000
  1.10000014305114750000         1.10000001639127730000
  1.20000016689300540000         1.20000001788139340000
  1.30000019073486330000         1.30000001937150960000
  1.40000021457672120000         1.40000002086162570000
  1.50000023841857910000         1.50000002235174180000
  1.60000026226043700000         1.60000002384185790000
  1.70000028610229490000         1.70000002533197400000
  1.80000030994415280000         1.80000002682209010000
  1.90000033378601070000         1.90000002831220630000
po 1k kartu:
  101.99901580810547000000       102.00000151991844000000


Į viršų
 Aprašymas  
 
 Pranešimo tema:
StandartinėParašytas: 2004-10-22 08:01:04 
Atsijungęs
Vartotojo avataras

Užsiregistravo: 2004-01-03 05:24:00
Pranešimai: 349
Miestas: Klaipėda
nu taip, tai naturalu


Į viršų
 Aprašymas Siųsti laišką  
 
 Pranešimo tema:
StandartinėParašytas: 2004-10-22 01:22:16 
Atsijungęs
Vartotojo avataras

Užsiregistravo: 2004-01-07 07:22:45
Pranešimai: 334
Miestas: Vilnius
Chia nieko va kai ishlenda bajeriai, kad

Kodas:
double a = count_wins()/count_loses();

if (a != count_wins()/count_loses())
   cout << "boo floating pointas" << endl;


va tada linksma. Tiksliai nepasakysiu kaip gaunas bet ideja tokia, kad jei double saugomas registre tai by default saugomas 64 bitu tikslumu, jei memory tai 48 bitu tikslumu tad jei lygini 1/3 registre su 1/3 kuri buvo registre bet tu irashei i memory gauni nelygius skaichius.

(po linuxu tikrai taip po windais neatsimenu)

Kitas ish zhymesniu bugu veikia ir po C/C++ ir java tai kai
Kodas:
a + b + c != a + c + b


todel geriau naudoti:
Kodas:
(let ((d 0))
  (loop for i from 1 to 1020
   do (incf d (/ 10)))
  d)

102


negu

Kodas:
(let ((d 0))
  (loop for i from 1 to 1020
   do (incf d 0.1))
  d)
101.99.....

_________________
If you have nothing nice to say, say it online.


Į viršų
 Aprašymas  
 
 Pranešimo tema:
StandartinėParašytas: 2005-02-09 02:25:41 
Atsijungęs

Užsiregistravo: 2004-01-12 01:15:21
Pranešimai: 973
Miestas: Vilnius
Zinoma sokiruoja, kai klaidu pridarai. Nesu floating pointo guru, bet viena
akivaizdzia klaida pataisiau:

Kodas:
   int i;
   float f = 0.0f;
   double d = 0.0;

   for (i = 20; i--;) {
      printf("  %2.20f \t %2.20lf\n", f, d);
      f += 0.1f;
      d += 0.1;
   }

   for (i = 1000; i--;) {
      f += 0.1f;
      d += 0.1;
   }
   printf("\n  %2.20f \t %2.20lf\n", f, d);


Rezultatai:
Kodas:
  0.00000000000000000000         0.00000000000000000000
  0.10000000149011612000         0.10000000000000001000
  0.20000000298023224000         0.20000000000000001000
  0.30000001192092896000         0.30000000000000004000
  0.40000000596046448000         0.40000000000000002000
  0.50000000000000000000         0.50000000000000000000
  0.60000002384185791000         0.59999999999999998000
  0.70000004768371582000         0.69999999999999996000
  0.80000007152557373000         0.79999999999999993000
  0.90000009536743164000         0.89999999999999991000
  1.00000011920928960000         0.99999999999999989000
  1.10000014305114750000         1.09999999999999990000
  1.20000016689300540000         1.20000000000000000000
  1.30000019073486330000         1.30000000000000000000
  1.40000021457672120000         1.40000000000000010000
  1.50000023841857910000         1.50000000000000020000
  1.60000026226043700000         1.60000000000000030000
  1.70000028610229490000         1.70000000000000040000
  1.80000030994415280000         1.80000000000000050000
  1.90000033378601070000         1.90000000000000060000

  101.99901580810547000000       101.99999999999848000000


Tavo rezultatu paklaida nuo norimo tikslumo (double):
Kodas:
102,00000151991844000000  /  102 =
1,0000000149011611764705882352941


Mano rezultatu paklaida nuo norimo tikslumo (double):
Kodas:
101,99999999999848000000  /  102 =
0,99999999999998509803921568627451


Kaip matai, siek tiek tiksliau.

_________________
Vytautas Šaltenis
On the Web: http://rtfb.lt


Į viršų
 Aprašymas Siųsti laišką  
 
 Pranešimo tema:
StandartinėParašytas: 2005-02-09 04:28:23 
Atsijungęs

Užsiregistravo: 2004-01-12 01:15:21
Pranešimai: 973
Miestas: Vilnius
Kai mandagiai paprasiau kompiliatoriaus siek tiek paoptimizuot, rezultatai
pasidare vos vos tikslesni:

Kodas:
  0.00000000000000000000         0.00000000000000000000
  0.10000000149011612000         0.10000000000000001000
  0.20000000298023224000         0.20000000000000001000
  0.30000000447034836000         0.30000000000000004000
  0.40000001341104507000         0.40000000000000002000
  0.50000000745058060000         0.50000000000000000000
  0.60000000149011612000         0.59999999999999998000
  0.70000002533197403000         0.69999999999999996000
  0.80000004917383194000         0.79999999999999993000
  0.90000007301568985000         0.89999999999999991000
  1.00000009685754780000         0.99999999999999989000
  1.10000012069940570000         1.09999999999999990000
  1.20000014454126360000         1.20000000000000000000
  1.30000016838312150000         1.30000000000000000000
  1.40000019222497940000         1.40000000000000010000
  1.50000021606683730000         1.50000000000000020000
  1.60000023990869520000         1.60000000000000030000
  1.70000026375055310000         1.70000000000000040000
  1.80000028759241100000         1.80000000000000050000
  1.90000031143426900000         1.90000000000000060000

  102.00000182539225000000       102.00000000000000000000


Priezhastis:
Neoptimizuotas kodas:
Kodas:
LC1:
        .long   1036831949        /* (float) 0.1f                  */
        .align 8
LC2:
        .long   -1717986918       /* (double) 0.1 (upper 4 bytes)  */
        .long   1069128089        /* (double) 0.1 (lower 4 bytes)  */

        /* ..... */

        /* the loop */
L3:
        movl    $1000, -4(%ebp)   /* for (i = 1000                  */
L6:
        leal    -4(%ebp), %eax
        decl    (%eax)            /* i--                            */
        cmpl    $-1, -4(%ebp)     /* i >= 0                         */
        jne     L9                /* if so, go to body              */
        jmp     L7                /* otherwise, jump to call printf */
L9:
        flds    -8(%ebp)          /* "download" f from memory       */
        flds    LC1               /* "download" 0.1f from memory    */
        faddp   %st, %st(1)       /* add                            */
        fstps   -8(%ebp)          /* "upload" result to memory      */
        fldl    -16(%ebp)         /* "download" d from memory       */
        fldl    LC2               /* "download" 1.0 from memory     */
        faddp   %st, %st(1)       /* add                            */
        fstpl   -16(%ebp)         /* "upload" result to memory      */
        jmp     L6                /* end of for                     */
L7:
        /* printf goes here */
        leave
        ret


Optimizuotas kodas:
Kodas:
LC3:
        .long   1036831949        /* (float) 0.1f                  */
        .align 8
LC4:
        .long   -1717986918       /* (double) 0.1 (upper 4 bytes)  */
        .long   1069128089        /* (double) 0.1 (lower 4 bytes)  */

        /* ..... */

        /* the loop */

        movl    $999, %ebx        /* for (i = 1000                 */

L11:
        /* at this point st(0) contains d, st(1) contains f        */

        fxch    %st(1)            /* swap st(0) with st(1)         */
        decl    %ebx              /* i--                           */
        fadds   LC3               /* add 1.0f to st(0) (i.e. f)    */
        fxch    %st(1)            /* swap st(0) with st(1)         */
        faddl   LC4               /* add 1.0 to st(0) (i.e. d)     */
        cmpl    $-1, %ebx         /* i >= 0                        */
        jne     L11               /* end of for                    */

        /* printf goes here */
        leave
        ret


Akivaizdu, kad tikslumo skirtumas atsiranda del to, kad neoptimizuotoj
versijoj po kiekvieno += rezultatas yra talpinamas i atminti. Tuo
tarpu optimizuotoj visas ciklas ivykdomas "neishleidzhiant" f ir d
ish FPU.

Jeigu ash teisingai supratau, taip vyksta del to, kad Intelio procesoriai
visus vidinius skaichiavimus atlieka 80 bitu tikslumu ir tik
kopijuojant i/ish FPU atlieka konvertavima i reikiama (32/64 bitu)
formata. Taigi neoptimizuotoj versijoj paklaida atsiranda del to, kad
po kiekvieno veiksmo rezultatas suapvalinamas iki 64 bitu (double
precision floating point).

Any floating point gurus around? Patvirtinkit arba paneikit.

BTW, ta serija devynetu spausdinant double'a atsiranda del paklaidos,
susikaupianchios printf() viduje, ne del paklaidos skaichiavimuose.

-rtfb

_________________
Vytautas Šaltenis
On the Web: http://rtfb.lt


Į viršų
 Aprašymas Siųsti laišką  
 
 Pranešimo tema:
StandartinėParašytas: 2005-02-09 04:39:08 
Atsijungęs
Vartotojo avataras

Užsiregistravo: 2004-01-03 09:38:37
Pranešimai: 1326
Miestas: Kaunas, LT
rtfb rašė:
Jeigu ash teisingai supratau, taip vyksta del to, kad Intelio procesoriai visus vidinius skaichiavimus atlieka 80 bitu tikslumu ir tik
kopijuojant i/ish FPU atlieka konvertavima i reikiama (32/64 bitu)
formata. Taigi neoptimizuotoj versijoj paklaida atsiranda del to, kad
po kiekvieno veiksmo rezultatas suapvalinamas iki 64 bitu (double
precision floating point).

Taip. Tiksliau, skaičiuoja tokiu tikslumu, kokis būna nustatytas per FPU control registrus. Standartiškai tai būna, huh, turbūt tie 80 bitų. Tačiau galima tą pakeist (t.y. sumažint tikslumą). Direct3D taip daro (jei flago "fpu preserve" nenurodai), berods netgi tokie dalykai kaip win32 LoadLibrary (?) taip daro.
Tačiau in general, taip, x86 FPU registruose gali būti viena, o išsaugojus atminty jau kita. Dėl to ir Voblia minėtos situacijos yra galimos, kai c=a/b ir tada c != a/b :)

_________________
work | home | twitter


Į viršų
 Aprašymas  
 
 Pranešimo tema:
StandartinėParašytas: 2005-02-09 09:04:06 
Atsijungęs
Vartotojo avataras

Užsiregistravo: 2004-02-03 07:36:24
Pranešimai: 1165
Miestas: Vilnius
rtfb rašė:
paklaida atsiranda del to, kad
po kiekvieno veiksmo rezultatas suapvalinamas iki 64 bitu (double
precision floating point).


Ash suprashchiau jei butu kokie lievi skaichiai, kaip kad sqrt(3). Bet kai skaichiuoji 0.1+0.1 tai kaip gali apvalinimas tai itakoti?! Be kokio +rand() tikrai neapsieisi. :-)


Į viršų
 Aprašymas  
 
 Pranešimo tema:
StandartinėParašytas: 2005-02-10 10:57:42 
Atsijungęs

Užsiregistravo: 2004-01-12 01:15:21
Pranešimai: 973
Miestas: Vilnius
sqrt (3) ir 0.1 dvejetainiam pavidale yra vienodai lievi skaichiai:

Kodas:
                IEEE-754 floating-point:
0.1:      0-01111011-10011001100110011001101
sqrt (3): 0-01111111-10111011011001111010111


See any substantial difference?

-rtfb

_________________
Vytautas Šaltenis
On the Web: http://rtfb.lt


Į viršų
 Aprašymas Siųsti laišką  
 
 Pranešimo tema:
StandartinėParašytas: 2005-02-10 04:48:52 
Atsijungęs
Vartotojo avataras

Užsiregistravo: 2004-01-03 09:38:37
Pranešimai: 1326
Miestas: Kaunas, LT
rtfb rašė:
sqrt (3) ir 0.1 dvejetainiam pavidale yra vienodai lievi skaichiai:

Kodas:
                IEEE-754 floating-point:
0.1:      0-01111011-10011001100110011001101
sqrt (3): 0-01111111-10111011011001111010111


Pliusas rtfb! Super pavyzdys :)

_________________
work | home | twitter


Į viršų
 Aprašymas  
 
 Pranešimo tema:
StandartinėParašytas: 2005-02-11 02:41:46 
Atsijungęs
Vartotojo avataras

Užsiregistravo: 2004-02-03 07:36:24
Pranešimai: 1165
Miestas: Vilnius
Kazhkokia nesamone. :-D tada float'ai sucks jei jie shitaip keistai koduojami. :-/ Bet netgi ir esant tokiam kodavimui vistiek keista matyt tokius error'us...


Į viršų
 Aprašymas  
 
 Pranešimo tema:
StandartinėParašytas: 2005-02-12 06:06:08 
Atsijungęs

Užsiregistravo: 2004-01-12 01:15:21
Pranešimai: 973
Miestas: Vilnius
Ne float'ai, o desimtaine skaiciavimo sitema yra nesamone. Jei zmogus
butu su ne su 10, o su 0x10 pirstu, gyvenimas butu daug paprastesnis :-).

Kai mokinsiu savo vaikus skaiciuoti ant pirstu, sakysiu, kad nyksciu
naudoti negalima, vis arciau tiesos bus :-D.

-rtfb

_________________
Vytautas Šaltenis
On the Web: http://rtfb.lt


Į viršų
 Aprašymas Siųsti laišką  
 
 Pranešimo tema:
StandartinėParašytas: 2005-02-14 02:40:30 
Atsijungęs
Vartotojo avataras

Užsiregistravo: 2004-02-03 07:36:24
Pranešimai: 1165
Miestas: Vilnius
rtfb rašė:
Kai mokinsiu savo vaikus skaiciuoti ant pirstu, sakysiu, kad nyksciu
naudoti negalima, vis arciau tiesos bus :-D.


Tai gal ir vaiku vardai bus version 1, version 2 kaip pas ta amerikieti? :-D


Į viršų
 Aprašymas  
 
Rodyti paskutinius pranešimus:  Rūšiuoti pagal  
Naujos temos kūrimas Atsakyti į temą  [ 12 pranešimai(ų) ] 

Visos datos yra UTC + 2 valandos [ DST ]


Dabar prisijungę

Vartotojai naršantys šį forumą: Registruotų vartotojų nėra ir 1 svečias


Jūs negalite kurti naujų temų šiame forume
Jūs negalite atsakinėti į temas šiame forume
Jūs negalite redaguoti savo pranešimų šiame forume
Jūs negalite trinti savo pranešimų šiame forume
Jūs negalite prikabinti failų šiame forume

Ieškoti:
Pereiti į:  
Mes naudojam: phpBB © 2008