Diskuze: Machr na C# .NET - Nejrychlejší shuffle
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.

Tvůrce

Zobrazeno 50 zpráv z 110.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
public void LibcoShuffle<T>(T[] input)
{
Random r = new Random();
for (int i = 0; i < input.Length; i++)
{
int a = r.Next(input.Length);
if (i != a)
{
var b = input[i];
input[i] = input[a];
input[a] = b;
}
}
}
Koukám na to. Jsem na tom podobně. Když ten algoritmus snad napadne
každého. Nebo alespoň já ho tak měl ještě předtím, než jsem ho našel.
Sice jsou asi tři druhy, ale rozdíl v tom moc nevidím. Spíš to bude o tom,
kdo má nejchytřejší Random a jak kdo vyřeší ty operace s čísly. Ještě
jsem zkoušel LINQ, je to několikanásobně rychlejší, ale OutOfMemory při kopírování zpět z
IEnumerable do pole.
No LINQ určitě rychlejší nebude. Každopádně testovat se to bude na číslech 103 - 104 (říkalo se tady v diskuzi)
Myslíš? Možná máš pravdu. Pouze 103? To bude na tiky procesoru nebo co? To už bude dost nepřesné měření, řekl bych.
Neviem či to takto pôjde na c#, možno ano.
public void LibcoShuffle<T>(T[] input)
{
Random r = new Random();
for (int i = 0; i < input.Length; i += 2)
{
int a = r.Next(input.Length);
i != a ? var b = input[i], input[i] = input[a], input[a] = b : 0;
}
}
Ne, myslel jsem, že máš jinou hlavičku než je v zadání.
Mi to neříkej celkově mi
tenhle úkol přijde trošku divný, kdyby v tom nebyla ta generika tak by se to
dalo možná nějak uspěchat
public void SilviniosShuffle<T>(T[] input)
{
// Fisher–Yates shuffle
// Linear congruential generator: r = (a * r + c) % m, m = 2^31, a=1103515245, c=12345
int r = (int) DateTime.Now.Ticks;
for (int i = input.Length - 1; i > 0; i--) {
r = (1103515245 * r + 12345) & 0x7FFFFFFF;
int j = r % (i + 1);
T c = input[j];
input[j] = input[i];
input[i] = c;
}
}
Nevadí, že mám naprosto "blbou" metodu random? Jakože není vůbec
vymakaná, ale náhodná čísla to jsou A je to zatím nejrychlejší
řešení. Ještě jsem našel něco podobného jako Silvinios, ale to jsem 1.
nevymyslel a 2. to bylo pomalejší.
Jsem si říkal, kde jsi sakra vytáhl ta čísla a on je to standart Céčka
pro rand() Ale pěkná
práce. U mě zatím nejrychlejší. Schválně, co vymyslí Luboš Běhounek Satik. To
bude zase síla. Už se těším.
Určitě se dá vymyslet něco horšího. Třeba, že některá uspořádání jsou více pravděpodobná, než jiná...
Ja se asi nezucastnim, o vikendu nejsem u PC a do patecni pulnoci musime
dodelat s Lukáš Hruda hru do magickeho leta, Luckin uz pise pribeh...
Random metodu asi nevytvoříš rychleji a v unsafe kódu toho moc
nevytvoříš s generikou
Pokud je generika takový problém, tak ji můžeme dát pryč
No omezil bych to na nějaký daný typ, protože já fakt googloval snad 4
hodiny různé způsoby jak se dá dostat nějak níže a optimalizovat takhle,
ale nic jsem nenašel - a v IL to psát opravdu nebudu
Příběh už mám Teď
vymýšlím atributy kouzlům a nepřátelům.
Jenže ona je vážně hrozně blbá taková odvozená, ale
zároveň náhodná. Generuje to nicméně docela čisté mapy (beztvaré), tak
to snad nebude problém. O unsafe kódu jsem také přemýšlel, ale C# ho
spíše "nedoporučuje" a v některých případech jeho použití i zpomaluje
kód.
Myslím, že pro úkol jako je tento by bylo vhodnější C++ nebo C. Tam by ta generika nebyla takový problém, C++ má šablony, v C se to dá nasimulovat pomocí typedef nebo maker.
Začali jsme brzo, ale měli jsme moc dlouhou pauzu
Toto je právě příklad, kde to reálně zkusíš já v C# nikdy s unsafe nepracoval,
tak jsem se "těšil" že si to zkusím a vylepším své znalosti a místo toho
jsem se akorát nasral, že u generiky to nejde
Já už to zkoušel několikrát. Vždy jsem byl sklamán rozdíly mezi Céčkem a C#. DOvolí toho několikanásobně méně.
Běží to na 1.7GHz i5-3317U. Ale vlákna stejně nepoužívám, rozsekat to na části zabere spoustu času.
Možná to je stupidní otázka, ale kam mám odevzdat tu metodu? Díky
Môj posledný pokus. Podmienka je pole väčšie ako 255 prvkov.
public void LibcoShuffle<T>(T[] input)
{
Random r = new Random((int)DateTime.Now.Ticks);
Byte[] b = new Byte[input.Length];
r.NextBytes(b);
for (int i = 0; i < input.Length; i += 2)
{
var c = input[i];
input[i] = input[b[i]];
input[b[i]] = c;
}
}
Zadání se změnilo na pole intů (jde to ofc i na to tvoje, ale bude to krapet pomalejší)
public void LibcoShuffle(int[] input)
{
Random r = new Random((int)DateTime.Now.Ticks);
Byte[] b = new Byte[input.Length];
r.NextBytes(b);
for (int i = 0; i < input.Length; i += 2)
{
int c = input[i];
input[i] = input[b[i]];
input[b[i]] = c;
}
}
Zde je můj pokus. Nefunguje pro pole obsahující záporná čísla a není ideální pro míchání malých polí a polí obsahujících pouze jedničky a nuly.
static void Shuffle(int[] arr)
{
Random rnd = new Random();
int size = arr.Length;
int num = rnd.Next() % (size / 2 - 1) + 1;
for (int i = 0; i < size; i++)
{
int pos = (arr[i] + num + i * 2) % size;
int temp = arr[i];
arr[i] = arr[pos];
arr[pos] = temp;
}
}
To minulé nepočítej.
Jsem to předělal na toto:
static void Sidecek123Shuffle(int[] array)
{
Random r = new Random();
for (int i = array.Length - 1; i > 0; i--)
{
int index = r.Next(i);
int tmp = array[index];
array[index] = array[i];
array[i] = tmp;
}
}
To moje nepočítej, našel jsem lepší způsob, ale nějak jsem nebyl doma
Předběžné výsledky jsou následující (viz screenshot) a velmi různé
pro různá pole. Pracuji ještě na testu pro míchaná pole. Také chci zkusit
jestli to opravdu shuffluje. Nevím, jestli to dnes stihnu vyhlásit
radši se jdi naladit na podzimní atmosféru.
private static void PakoShuffle(int[] input)
{
Random r = new Random();
int n, t;
for (int i = input.Length - 1; i > 0; i--)
{
n = r.Next(5);
t = input[n];
input[n] = input[i];
input[i] = t;
}
}
Můžeš zkusit toto ? byl tam improve skoro 350% oproti tomu předtím.
Kdyby se ti nechtělo, hodil bys mi zdroják a já bych si to pustil u sebe ?
Proměřil jsem i náhodná pole. Vypadá to na bitvu mezi Brisingrem a Davidomilem. Snad jsem tam někde neudělal chybu, jsem docela unavený. Zdroják prozatimního testu je zde: http://www.itnetwork.cz/dev-lighter/208
Jdu se kouknout jak vám to kluci prohazuje.
Podle výsledků bych to jednoznačně viděl na to, že vede Michael Olšavský
Vypadá to tedy, že z testu vyšel nejlépe Lukáš Hruda, získává tedy
Machra na C# Druhý je
Silvinios. Metody Brisingra a Davidomila mi nějak nedělaly to, co měly. Pro
případ přikládám celý zdroják testů: http://www.itnetwork.cz/dev-lighter/209 .
Luckinovu adresu prosím x do PM.
Sakra. To je dost trapný a to sem tomu algoritmu tak veril... Stacilo pritom pridat jednu
nahodnou navic... A ten cas by se skoro nezvedl. A vubec. mel jsem to nechat na
svem prvnim pokusu. Vypada to, ze by to s tim casem nebylo tak spatne, kdyz to
davidomilovi take nefunguje. Mam na tyhle machry teda stesti...
doufam, ze priste to vyjde.
Omlouvam se, za klamavy aloritmus. Nahodnost pentia nebyla schvalne.
Tomu už ani nevěřím... :/ Chce to víc kontrolovat. Přitom sem to opravil za pár
minut........................
Zobrazeno 50 zpráv z 110.