TCH (statz) | #1, Főfasz (10443) |
7110 | #1779 | ^ | Idézet | Mon, 31 Oct 2011 15:36:21 +01 |
46.107.*.* | *.catv.pool.telekom.hu |
Gondolkoztam, hogy mit lehetne fejleszteni ezen a szaron, meg közben Csárli és Boreger #amigaspiritről azt mondta, hogy a számismétlés nem gond, a pattern ismétlés az igen. Hát akkor. (Sz*rk: A változók típusát sima unsigned int-ről lecseréltem unsigned long int-re, mert az mindenütt jelöletlen 32 bites, nem csak a GCC-ben. A tesztkódokban nem bántottam, mert GCC alatt volt tesztelve. Ez semmi változást nem okoz a kódban, csak más fordítók alatt is fordulni fog.) (Sz*rk 2015: A tipust visszacseréltem, mert 64 bit alatt az unsigned long int az 64 bit. :P Egyébként az unsigned int az, ahogy néztem, Amigán és pöcén, 32 és 64 biten, egyaránt 32-bit. rnd2.c unsigned int __seed0, __seed1, __seed2, __seed3; unsigned int __rol(unsigned int value, unsigned char offset) { offset = offset & 0x1f; return (value << offset) | (value >> (0x20 - offset)); } unsigned int __ror(unsigned int value, unsigned char offset) { offset = offset & 0x1f; return (value >> offset) | (value << (0x20 - offset)); } void srnd2(unsigned int seed) { __seed0 = seed; __seed1 = __seed0 ^ 0xaaaaaaaa; __seed1 = __rol(__seed1 >> 11, __seed1); __seed1 = __seed1 ^ (__seed1 >> 21); __seed2 = __seed0 ^ 0x55555555; __seed2 = __ror(__seed2 << 6, __seed2); __seed2 = __seed2 ^ (__seed2 >> 22); __seed3 = (__seed2 << 16) | (__seed1 >> 16); } unsigned int rnd2() { __seed1 = __rol(__seed1, 5); __seed2 = __ror(__seed2, 9); __seed0 = __rol(__seed0, 11); __seed0 ^= __seed1; __seed0 ^= __rol(__seed1, 8) << 11; __seed0 ^= __ror(__seed2, 8) & 63; __seed0 ^= __rol(__seed3, 8) >> 5; __seed0 = __ror(__seed0, 14); __seed0 ^= __seed3; __seed1 ^= __seed3; __seed2 ^= __seed3; __seed3 = __ror(__seed3, __seed0); return __seed0; }Teszteljük. Először sebességet. rndstest.c void main() { int u; for (u = 0; u < 500000000; ++u) rand(); }rndstest2.c #include "rnd2.c" void main() { int u; for (u = 0; u < 500000000; ++u) rnd2(); }Eredmény: root@Csabi:~# gcc ./rndstest.c -O3 root@Csabi:~# time ./a.out real 0m13.890s user 0m13.885s sys 0m0.000s root@Csabi:~# gcc ./rndstest2.c -O3 root@Csabi:~# time ./a.out real 0m2.847s user 0m2.840s sys 0m0.000sLol. Ez aztán optimalizáció bazdmeg, 11x-es sebességnövekedés. :DDDD Lássuk az első ismétlés tesztjét. Kicsit változtattam a tesztelőkódon, hogy ne kelljen egyesével beírni a seedeket. rndtest.c: unsigned int tbl[1048576]; int first() { int i, j; unsigned int l; for (i = 0; i < 1048576; ++i) { l = rand(); for (j = 0; j < i; ++j) { if (l == tbl[j]) { return i; } } tbl[i] = l; } } void main() { const unsigned int num[] = {0, 0xb11193c1, 0xfa52fe7, 0xffffffff, 1, 4743463, 0x986fae83, 982357, 986739687, 666}; int u, t, s; s = 0; for (u = 0; u < 10; ++u) { srand(num[u]); t = first(); s += t; printf("%d\n", t); } printf("%d\n", s); }rndtest2.c: #include "rnd2.c" unsigned int tbl[1048576]; int first() { int i, j; unsigned int l; for (i = 0; i < 1048576; ++i) { l = rnd2(); for (j = 0; j < i; ++j) { if (l == tbl[j]) { return i; } } tbl[i] = l; } } void main() { const unsigned int num[] = {0, 0xb11193c1, 0xfa52fe7, 0xffffffff, 1, 4743463, 0x986fae83, 982357, 986739687, 666}; int u, t, s; s = 0; for (u = 0; u < 10; ++u) { srnd2(num[u]); t = first(); s += t; printf("%d\n", t); } printf("%d\n", s); }Eredmények (ugyanazokkal a seedekkel mint tegnap, az utolsó 11. sor az összesített) root@Csabi:~# gcc ./rndtest.c -O3 15357 102640 41026 53585 15357 46003 80668 56884 62171 43118 516809 root@Csabi:~# gcc ./rndtest2.c -O3 root@Csabi:~# ./a.out 39597 183360 25880 14782 70036 120541 71392 29256 91058 108667 7545693:7 a javunkra és az összesítettben is eléggé rávert. De ha már Csárli felhívta a figyelmemet a szórásra, akkor végezzünk el egy ilyen tesztet is. Ez a teszt azt vizsgálja, hogy a legenerált elemekből hány van meg legalább 2x, azaz hány különbözik és hány ismétlődik. Ezt nem 1 megáig néztem, mert az sose futott volna le, hanem csak 128 kilóig (azaz azt számolta, hogy 131072 "véletlen" elem közül hány ismételt, a maradék (131072-n) az egyedi) rndptest.c: unsigned int tbl[131072]; int calcrep() { int i, j, q; q = 0; unsigned int l; for (i = 0; i < 131072; ++i) { l = rand(); for (j = 0; j < i; ++j) { if (l == tbl[j]) { q++; j = i; } } tbl[i] = l; } return q; } void main() { const unsigned int num[] = {0, 0xb11193c1, 0xfa52fe7, 0xffffffff, 1, 4743463, 0x986fae83, 982357, 986739687, 666}; int u, t, s; s = 0; for (u = 0; u < 10; ++u) { srand(num[u]); t = calcrep(); s += t; printf("%d\n", t); } printf("%d\n", s); }rndptest2.c: #include "rnd2.c" unsigned int tbl[131072]; int calcrep() { int i, j, q; q = 0; unsigned int l; for (i = 0; i < 131072; ++i) { l = rnd2(); for (j = 0; j < i; ++j) { if (l == tbl[j]) { q++; j = i; } } tbl[i] = l; } return q; } void main() { const unsigned int num[] = {0, 0xb11193c1, 0xfa52fe7, 0xffffffff, 1, 4743463, 0x986fae83, 982357, 986739687, 666}; int u, t, s; s = 0; for (u = 0; u < 10; ++u) { srnd2(num[u]); t = calcrep(); s += t; printf("%d\n", t); } printf("%d\n", s); }És az eredmény (újfennt ugyanazokkal a seedekkel): root@Csabi:~# gcc ./rndptest.c -O3 root@Csabi:~# ./a.out 6 2 6 5 6 1 2 2 3 7 40 root@Csabi:~# gcc ./rndptest2.c -O3 root@Csabi:~# ./a.out 2 0 2 4 2 1 1 2 2 2 181:9 és az az 1 pont is két döntetlenből volt. Az eredmény magáért beszél. :) Konklúzió: Az rnd2() közel 5x olyan gyors, mint a libc rand(), az esetek 90%-ában kevesebb ismétlést ad és átlagosan kevesebb mint feleannyi ismétlést ad. Énszerintem ez egyértelmű zsírkarajság. :))) 68k verzió: srnd2 move.l d0, d1 eor.l #$aaaaaaaa, d1 move.b d1, d4 asr.l #11, d1 rol.l d4, d1 move.l d1, d4 asr.l #21, d4 eor.l d4, d1 move.l d0, d2 eor.l #$55555555, d2 move.b d2, d4 asl.l #6, d2 ror.l d4, d2 move.l d2, d4 asr.l #22, d4 eor.l d4, d2 move.l d1, d3 asr.l #16, d3 move.l d2, d4 asl.l #16, d4 or.l d4, d3 movel. d0, __seed0 movel. d1, __seed1 movel. d2, __seed2 movel. d3, __seed3 rts rnd2 move.l __seed0, d0 move.l __seed1, d1 move.l __seed2, d2 move.l __seed3, d3 rol.l #5, d1 ror.l #9, d2 rol.l #11, d0 eor.l d1, d0 move.l d1, d4 rol.l #8, d4 asl.l #11, d4 eor.l d4, d0 move.l d2, d4 ror.l #8, d4 andi.l #63, d4 eor.l d4, d0 move.l d3, d4 rol.l #8, d4 asr.l #5, d4 eor.l d4, d0 ror.l #14, d0 eor.l d3, d0 eor.l d3, d1 eor.l d3, d2 ror.l d0, d3 movel. d0, __seed0 movel. d1, __seed1 movel. d2, __seed2 movel. d3, __seed3 rts __seed0 dc.l 0 __seed1 dc.l 0 __seed2 dc.l 0 __seed3 dc.l 0Használjátok egész seggel. ;) |