IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Diskuze: Chyba v programu na odhad pi

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

Aktivity
Avatar
Regedin the Immortal:9.1.2017 17:08

Snažně prosím o jakoukoli radu, připomínku nebo opravu ke kódu uvedenému níže. Účelem aplikace je odhad hodnoty pí pomocí opakované volby náhodného bodu ve čtverci 12 přičemž se po každé iteraci cyklu zjistí platnost podmínky pro polohu tohoto bodu a provede se příslušná operace.

class Program
    {
        static void Main(string[] args)
        {
            Cislo x = new Cislo();
            Cislo y = new Cislo();
            int h = 0;
            int u = 0;
            double x_a;
            double y_a;
            double pi;
            float pravdepodobnost;
            while (h<1000)
            {
                x_a = x.hod();
                y_a = x.hod();
                if (Math.Sqrt(Math.Pow(x_a,2)+Math.Pow(y_a, 2))<1)
                {
                    u++;
                }
                    h++;
                if (h % 100 == 0)
                {
                    pravdepodobnost = u / h;
                    Console.WriteLine("h : {0}   u : {1}   p : " + pravdepodobnost, h, u);
                    Console.WriteLine("x : {0}   y : {1}", x_a, y_a);
                }
            }
            pi = 4 * u / h;
            Console.WriteLine("určená hodnota pi je " + pi);
            Console.WriteLine("systémem určená hodnota je " + Math.PI);
            double rozdil = Math.Abs(pi - Math.PI);
            Console.WriteLine("rozdíl hodnot je " + rozdil);
            Console.ReadKey();
        }
    }

A tady ještě třída Cislo sloužící ke generování náhodných čísel

class Cislo
    {
        public double horni_mez;
        private Random random;
        public Cislo()
        {
            this.horni_mez = 1;
            random = new Random();
        }
        public Cislo(double horni_mez_a)
        {
            this.horni_mez = horni_mez_a;
            random = new Random();
        }
        public double hod()
        {
            int mezi_cislo = random.Next(1, 1000);             // dolní mez se dá nastavit odstraněním absolutní hodnoty a přičtením pevné hodnoty
            return Math.Abs(Math.Sin(mezi_cislo) * horni_mez);

        }
    }

Program by měl fungovat následovně : Je dán čtverec 12 a v něm je vepsána čtvrtkružnice se středem v levém dolním rohu. V každé iteraci cyklu se náhodně zvolí dvojice souřadnic na intervalu 0 až 1, která představuje souřadnice bodu ve čtverci. Pokud je vzdálenost tohoto bodu od středu kružnice menší nebo rovna jedné (v kódu jen menší ale to je minimální rozdíl) přičte se k proměnným h a u jednička, v opačném případě se přičte jen k h. Nakonec se odhadne hodnota pi jako čtyřnásobek statistické pravděpodobnosti, že podmínka bude splněna. A tady je ten problém, protože mi to vyhazuje že pi je asi 1. Byl bych vděčný za každý nápad který by odhalil chybu.

 
Odpovědět
9.1.2017 17:08
Avatar
Odpovídá na Regedin the Immortal
Regedin the Immortal:9.1.2017 17:32

Možná že ta část s

x_a = x.hod();
y_a = x.hod();

vypadá trochu zvláštně, ale když tam ještě bylo

x_a = x.hod();
y_a = y.hod();

byly vždycky obě vygenerované čísla stejné.

 
Nahoru Odpovědět
9.1.2017 17:32
Avatar
Odpovídá na Regedin the Immortal
Libor Šimo (libcosenior):9.1.2017 17:36

Na prvy pohlad mi padol do oka tento riadok:
Console.Write­Line("h : {0} u : {1} p : " + pravdepodobnost, h, u);
Si si isty, ze je spravne?

Nahoru Odpovědět
9.1.2017 17:36
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Odpovídá na Regedin the Immortal
Libor Šimo (libcosenior):9.1.2017 17:48

Mimochodom, ten kod si pisal sam alebo si ho niekde skopcil?

Nahoru Odpovědět
9.1.2017 17:48
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Odpovídá na Libor Šimo (libcosenior)
Regedin the Immortal:9.1.2017 18:15

ten řádek je tam proto aby to po každém stém pokusu vypsalo počet umístěných bodů a počet bodů v kružnici ale v něm chyba nebude protože to vyhazovalo stejný výstup i bez něho. Jinak ten kód odnikud zkopírovaný není, vytvořil jsem ho sám a v tom bude asi problém protože nemám moc zkušeností a asi jsem udělal nějakou chybu.

 
Nahoru Odpovědět
9.1.2017 18:15
Avatar
Odpovídá na Regedin the Immortal
Libor Šimo (libcosenior):9.1.2017 18:17

OK, už to testujem vo VS 2015.

Nahoru Odpovědět
9.1.2017 18:17
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Odpovídá na Regedin the Immortal
Libor Šimo (libcosenior):9.1.2017 18:41

Čo má robiť tento riadok:

Math.Sqrt(Math.Pow(x_a, 2) + Math.Pow(y_a, 2))
Nahoru Odpovědět
9.1.2017 18:41
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Regedin the Immortal:9.1.2017 18:42

určit vzdálenost bodu od středu kružnice podle pythagorovy věty.
aspoň trochu pomohlo přepsat

pi = 4 * u / h;

na

pi = 4 * (double)u / h

ale i tak je pro h=1000000 π = 2,005 což je pořád špatně. Možná že rozdělení pravděpodobnosti u těch souřadnicí není úplně rovnoměrné.

 
Nahoru Odpovědět
9.1.2017 18:42
Avatar
Libor Šimo (libcosenior):9.1.2017 18:49

Testuj ďalej, prídeš na to sám a budeš spokojnejší. ;-)

Nahoru Odpovědět
9.1.2017 18:49
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Regedin the Immortal:9.1.2017 18:52

chyba je určitě v tom generátoru náhodných čísel protože pravděpodobnost umístění do kružnice je tu asi 50% ale ve skutečnosti je to tak 78% (kruh vyplňuje 78% čtverce). Ještě jsem trochu vylepšil Program.cs na verzi

class Program
    {
        static void Main(string[] args)
        {
            Cislo x = new Cislo();
            Cislo y = new Cislo();
            int h = 0;
            int u = 0;
            double x_a;
            double y_a;
            float pravdepodobnost;
            while (h<1000000)
            {
                x_a = x.hod();
                y_a = x.hod();
                if (Math.Sqrt(Math.Pow(x_a,2)+Math.Pow(y_a, 2))<1)
                {
                    u++;
                }
                    h++;
                if (h % 1000 == 0)
                {
                    pravdepodobnost = 100 * (float)u / h;
                    Console.WriteLine("h : {0}   u : {1}   p : " + pravdepodobnost + " %", h, u);
                    Console.WriteLine("x : {0}   y : {1}", x_a, y_a);
                }
            }
            double pi = 4 * (double)u / h;
            Console.WriteLine("určená hodnota pi je " + pi);
            Console.WriteLine("systémem určená hodnota je " + Math.PI);
            double rozdil = Math.Abs(pi - Math.PI);
            Console.WriteLine("rozdíl hodnot je " + rozdil);
            Console.ReadKey();
        }
    }
 
Nahoru Odpovědět
9.1.2017 18:52
Avatar
Libor Šimo (libcosenior):9.1.2017 18:58

Tak si pridaj podmienku, že generované číslo musí byť v určitom rozsahu.

Nahoru Odpovědět
9.1.2017 18:58
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Regedin the Immortal:9.1.2017 19:01

ale ono je ve správném rozsahu, jen má nějakou divnou distribuční funkci, tak zkusím přepsat Cislo.cs ale stejně moc děkuji za rychlé a věcné reakce :-)

 
Nahoru Odpovědět
9.1.2017 19:01
Avatar
Ondřej Štorc
Tvůrce
Avatar
Odpovídá na Regedin the Immortal
Ondřej Štorc:9.1.2017 21:05

Takovej tip. Ta instance Randomu by mělo být pokud možno jedna ;-)

Editováno 9.1.2017 21:06
Nahoru Odpovědět
9.1.2017 21:05
Život je příliš krátký na to, abychom bezpečně odebírali USB z počítače..
Avatar
Regedin the Immortal:9.1.2017 21:29

Ale můj problém nespočívá v tom že by měly souřadnice špatný rozsah (v cyklu je i funkce na jejich vypisování každých 1000 pokusů a rozsah vždy sedí) ale v tom, že vyšší hodnoty jsou z nějakého důvodu častější než nizší, což koresponduje s výslednou hodnotou protože statistická pravděpodobnost umístění do kruhu klesá když jsou vyšší hodnoty častější a ta pravděpodobnost je tím místo nějakých 78% asi 50%. Potřebuji takový generátor náhodných čísel 0 až 1, kde jsou všechny hodnoty stejně pravděpodobné. Třeba si můžu vzít přirozené číslo od 1 do 1000000 a pak ho vydělit 1000000.

 
Nahoru Odpovědět
9.1.2017 21:29
Avatar
Regedin the Immortal:9.1.2017 21:32

udělal jsem to s tím dělením a už to funguje, odchylka je asi 0,0000012

Akceptované řešení
+5 Zkušeností
Řešení problému
 
Nahoru Odpovědět
9.1.2017 21:32
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 15 zpráv z 15.