BlessRNG atanapi pariksa RNG pikeun fairness

BlessRNG atanapi pariksa RNG pikeun fairness

Dina ngembangkeun kaulinan, anjeun mindeng kudu dasi hal up kalawan randomness: Unity boga acak sorangan pikeun ieu, sarta dina paralel jeung aya System.Random. Sakali-kali, dina salah sahiji proyék, kuring ngagaduhan gambaran yén duanana tiasa dianggo béda (sanaos aranjeunna kedah gaduh distribusi anu rata).

Lajeng aranjeunna henteu lebet kana detil - éta cukup yén transisi ka System.Random dilereskeun sagala masalah. Ayeuna kami mutuskeun pikeun ningali langkung rinci sareng ngalaksanakeun panalungtikan sakedik: kumaha "bias" atanapi RNG anu tiasa diprediksi, sareng anu mana anu kedah dipilih. Sumawona, kuring langkung ti sakali ngupingkeun pendapat anu bertentangan ngeunaan "kajujuran" na - hayu urang coba terang kumaha hasil nyata dibandingkeun sareng anu dinyatakeun.

Program atikan singket atanapi RNG saleresna RNG

Upami anjeun parantos wawuh sareng generator nomer acak, anjeun tiasa langsung ngalangkungan bagian "Nguji".

Angka acak (RN) nyaéta runtuyan angka anu dihasilkeun ngagunakeun sababaraha prosés acak (kacau), sumber éntropi. Hartina, ieu runtuyan anu unsur-unsurna teu dikait-kaitkeun ku hukum matématika - teu aya hubungan sabab-akibat.

Anu nyiptakeun nomer acak disebut generator nomer acak (RNG). Éta sigana yén sadayana dasar, tapi upami urang ngalih tina téori kana prakték, maka saleresna henteu saderhana pikeun nerapkeun algoritma parangkat lunak pikeun ngahasilkeun sekuen sapertos kitu.

Alesanna nyaéta henteuna huru-hara anu sami dina éléktronika konsumen modéren. Tanpa éta, angka acak cease janten acak, sarta generator maranéhna robah jadi hiji fungsi biasa argumen jelas diartikeun. Pikeun sababaraha spésial dina widang IT, ieu masalah serius (contona, kriptografi), tapi keur batur aya solusi sagemblengna ditarima.

Perlu nulis hiji algoritma nu bakal balik, sanajan teu sabenerna angka acak, tapi sacaket mungkin ka aranjeunna - nu disebut angka pseudo-acak (PRN). Algoritma dina hal ieu disebut generator angka pseudorandom (PRNG).

Aya sababaraha pilihan pikeun nyieun PRNG, tapi ieu bakal relevan pikeun sadayana:

  1. Kabutuhan pikeun initialization awal.

    PRNG henteu gaduh sumber éntropi, janten kedah dipasihkeun kaayaan awal sateuacan dianggo. Ieu dieusian salaku angka (atawa vektor) jeung disebut siki (siki acak). Mindeng, counter jam processor atawa sarimbag numerik waktu sistem dipaké salaku cikal.

  2. Reproducibility runtuyan.

    PRNG sagemblengna deterministik, jadi cikal dieusian salila initialization uniquely nangtukeun sakabéh runtuyan hareup angka. Ieu ngandung harti yén hiji PRNG misah initialized kalawan siki sarua (dina waktu béda, dina program béda, dina alat béda) bakal ngahasilkeun runtuyan sarua.

Anjeun oge kudu nyaho sebaran probabiliti characterizing PRNG - angka naon eta bakal ngahasilkeun sarta kalawan probabiliti naon. Paling sering ieu téh boh sebaran normal atawa sebaran seragam.
BlessRNG atanapi pariksa RNG pikeun fairness
Sebaran normal (kénca) jeung sebaran seragam (katuhu)

Anggap urang gaduh maot anu adil sareng 24 sisi. Lamun Tos eta, kamungkinan meunang hiji bakal sarua jeung 1/24 (sarua jeung kamungkinan meunang sagala angka sejenna). Lamun nyieun loba throws sarta ngarekam hasil, anjeun bakal aya bewara nu sagala edges ragrag kaluar kalawan frékuénsi kira sarua. Intina, paeh ieu tiasa dianggap RNG kalayan distribusi seragam.

Kumaha lamun maledog 10 tina dadu ieu sakaligus tur cacah total titik? Naha keseragaman bakal dijaga pikeun éta? No. Seringna, jumlahna bakal caket kana 125 poin, nyaéta, sababaraha nilai rata-rata. Jeung salaku hasilna, malah saméméh nyieun lémparan, Anjeun kasarna bisa estimasi hasil nu bakal datang.

alesan teh nya eta aya jumlah greatest kombinasi pikeun ménta skor rata. Langkung tebih ti éta, langkung seueur kombinasi - sareng, sasuai, langkung handap kamungkinan kaleungitan. Lamun data ieu visualized, eta bakal vaguely nyarupaan bentuk bel a. Ku alatan éta, kalawan sababaraha manteng, sistem 10 dadu bisa disebut RNG kalawan sebaran normal.

conto sejen, ngan waktu ieu dina pesawat - shooting di udagan. Jujur bakal janten RNG anu ngahasilkeun sapasang nomer (x, y) anu dipidangkeun dina grafik.
BlessRNG atanapi pariksa RNG pikeun fairness
Satuju yén pilihan di kénca téh ngadeukeutan ka kahirupan nyata - ieu RNG kalawan sebaran normal. Tapi lamun perlu paburencay béntang dina langit poék, pilihan katuhu, diala ngagunakeun RNG kalawan distribusi seragam, leuwih cocog. Sacara umum, milih generator gumantung kana tugas di leungeun.

Ayeuna hayu urang ngobrol ngeunaan éntropi tina sekuen PNG. Contona, aya runtuyan nu dimimitian kawas kieu:

89, 93, 33, 32, 82, 21, 4, 42, 11, 8, 60, 95, 53, 30, 42, 19, 34, 35, 62, 23, 44, 38, 74, 36, 52 18, 58, 79, 65, 45, 99, 90, 82, 20, 41, 13, 88, 76, 82, 24, 5, 54, 72, 19, 80, 2, 74, 36, 71, 9, ...

Kumaha acak angka ieu dina glance kahiji? Hayu urang mimitian ku mariksa distribusi.
BlessRNG atanapi pariksa RNG pikeun fairness
Sigana deukeut ka seragam, tapi lamun maca runtuyan dua angka jeung napsirkeun aranjeunna salaku koordinat dina pesawat, anjeun meunang ieu:
BlessRNG atanapi pariksa RNG pikeun fairness
Pola jadi jelas katempo. Sarta saprak data dina runtuyan ieu maréntahkeun dina cara nu tangtu (nyaéta, mibanda éntropi low), ieu bisa ngabalukarkeun éta pisan "bias". Sahenteuna, PRNG sapertos kitu henteu cocog pisan pikeun ngahasilkeun koordinat dina pesawat.

runtuyan séjén:

42, 72, 17, 0, 30, 0, 15, 9, 47, 19, 35, 86, 40, 54, 97, 42, 69, 19, 20, 88, 4, 3, 67, 27, 42 56, 17, 14, 20, 40, 80, 97, 1, 31, 69, 13, 88, 89, 76, 9, 4, 85, 17, 88, 70, 10, 42, 98, 96, 53, ...

Sagalana sigana henteu kunanaon di dieu bahkan dina pesawat:
BlessRNG atanapi pariksa RNG pikeun fairness
Hayu urang tingali dina volume (baca tilu angka sakaligus):
BlessRNG atanapi pariksa RNG pikeun fairness
Jeung deui pola. Teu mungkin deui ngawangun visualisasi dina opat diménsi. Tapi pola tiasa aya dina diménsi ieu sareng anu langkung ageung.

Dina kriptografi, dimana sarat paling stringent ditumpukeun dina PRNGs, kaayaan kitu téh categorically unacceptable. Ku alatan éta, algoritma husus geus dimekarkeun pikeun assess kualitas maranéhanana, nu urang moal noél ayeuna. Topik anu éksténsif jeung pantes artikel misah.

Tés

Upami urang henteu terang naon anu pasti, teras kumaha cara damelna? Éta patut nyebrang jalan upami anjeun henteu terang lampu lalu lintas mana anu ngamungkinkeun? Balukarna bisa jadi béda.

Sami lumaku pikeun randomness notorious di Unity. Éta saé upami dokuméntasi ngungkabkeun detil anu diperyogikeun, tapi carita anu disebatkeun dina awal tulisan éta kajantenan kusabab kurangna spésifik anu dipikahoyong.

Sareng upami anjeun henteu terang kumaha alatna jalanna, anjeun moal tiasa dianggo kalayan leres. Sacara umum, waktuna pikeun pariksa sareng ngalaksanakeun percobaan pikeun mastikeun sahenteuna ngeunaan distribusi.

Solusina saderhana sareng efektif - kumpulkeun statistik, kéngingkeun data objektif sareng tingali hasilna.

Subjek pangajaran

Aya sababaraha cara pikeun ngahasilkeun nomer acak dina Unity - kami nguji lima.

  1. System.Random.Next (). Ngahasilkeun integer dina rentang nilai nu tangtu.
  2. System.Random.NextDouble(). Ngahasilkeun angka precision ganda dina rentang ti [0; 1).
  3. UnityEngine.Random.Range(). Ngahasilkeun angka precision tunggal (ngambang) dina rentang nilai dibikeun.
  4. UnityEngine.Random.value. Ngahasilkeun angka precision tunggal (ngambang) dina rentang ti [0; 1).
  5. Unity.Mathematics.Random.NextFloat(). Bagian tina perpustakaan Unity.Mathematics anyar. Ngahasilkeun angka precision tunggal (ngambang) dina rentang nilai dibikeun.

Ampir unggal madhab dina dokuméntasi ieu sebaran seragam dieusian, iwal UnityEngine.Random.value (dimana sebaran teu dieusian, tapi ku analogi jeung UnityEngine.Random.Range () seragam ieu ogé diperkirakeun) jeung Unity.Mathematics.Random .NextFloat () (dimana dina dasarna nyaéta algoritma xorshift, anu hartosna deui anjeun kedah ngantosan distribusi seragam).

Sacara standar, hasil anu dipiharep dicandak sakumaha anu dijelaskeun dina dokuméntasi.

Téhnik

Urang nulis hiji aplikasi leutik nu dihasilkeun runtuyan angka acak ngagunakeun unggal sahiji metodeu dibere tur disimpen hasilna pikeun ngolah salajengna.

Panjang unggal runtuyan nyaéta 100 angka.
Kisaran angka acak nyaéta [0, 100).

Data dikumpulkeun tina sababaraha platform target:

  • Windows
    — Unity v2018.3.14f1, Modeu Éditor, Mono, .NET Standard 2.0
  • macOS
    — Unity v2018.3.14f1, Modeu Éditor, Mono, .NET Standard 2.0
    - Unity v5.6.4p4, modeu Editor, Mono, .NET Standar 2.0
  • Android
    - Unity v2018.3.14f1, ngawangun per alat, Mono, .NET Standar 2.0
  • ios
    - Unity v2018.3.14f1, ngawangun per alat, il2cpp, .NET Standar 2.0

Реализация

Simkuring gaduh sababaraha cara pikeun ngahasilkeun angka acak. Pikeun masing-masingna, kami bakal nyerat kelas bungkus anu misah, anu kedah nyayogikeun:

  1. Kamungkinan pikeun nyetél rentang nilai [mnt / max). Bakal diatur via constructor nu.
  2. Métode mulangkeun MF. Hayu urang milih ngambang salaku jenis, sabab leuwih umum.
  3. Ngaran metode generasi pikeun nyirian hasil. Pikeun genah, urang bakal balik salaku nilai ngaran lengkep kelas + nami metoda dipaké pikeun ngahasilkeun MF.

Mimiti, hayu urang nyatakeun abstraksi anu bakal diwakilan ku antarmuka IRandomGenerator:

namespace RandomDistribution
{
    public interface IRandomGenerator
    {
        string Name { get; }

        float Generate();
    }
}

Palaksanaan System.Random.Next()

Metoda ieu ngidinan Anjeun pikeun nyetél sauntuyan nilai, tapi mulih integer, tapi floats diperlukeun. Anjeun ngan saukur tiasa napsirkeun integer salaku ngambang, atanapi anjeun tiasa ngalegaan kisaran nilai ku sababaraha ordo gedéna, ngimbanganana unggal generasi midrange. Hasilna bakal sapertos titik tetep kalayan urutan akurasi anu ditangtukeun. Urang bakal ngagunakeun pilihan ieu saprak éta ngadeukeutan ka nilai float nyata.

using System;

namespace RandomDistribution
{
    public class SystemIntegerRandomGenerator : IRandomGenerator
    {
        private const int DefaultFactor = 100000;
        
        private readonly Random _generator = new Random();
        private readonly int _min;
        private readonly int _max;
        private readonly int _factor;


        public string Name => "System.Random.Next()";


        public SystemIntegerRandomGenerator(float min, float max, int factor = DefaultFactor)
        {
            _min = (int)min * factor;
            _max = (int)max * factor;
            _factor = factor;
        }


        public float Generate() => (float)_generator.Next(_min, _max) / _factor;
    }
}

Palaksanaan System.Random.NextDouble()

Di dieu rentang tetep tina nilai [0; 1). Pikeun proyek eta onto hiji dieusian dina constructor nu, kami nganggo arithmetic basajan: X * (max − mnt) + mnt.

using System;

namespace RandomDistribution
{
    public class SystemDoubleRandomGenerator : IRandomGenerator
    {
        private readonly Random _generator = new Random();
        private readonly double _factor;
        private readonly float _min;


        public string Name => "System.Random.NextDouble()";


        public SystemDoubleRandomGenerator(float min, float max)
        {
            _factor = max - min;
            _min = min;
        }


        public float Generate() => (float)(_generator.NextDouble() * _factor) + _min;
    }
}

Palaksanaan UnityEngine.Random.Range()

Metoda ieu UnityEngine.Random kelas statik ngidinan Anjeun pikeun nyetel sauntuyan nilai na mulih tipe ngambang. Anjeun teu kedah ngalakukeun transformasi tambahan.

using UnityEngine;

namespace RandomDistribution
{
    public class UnityRandomRangeGenerator : IRandomGenerator
    {
        private readonly float _min;
        private readonly float _max;


        public string Name => "UnityEngine.Random.Range()";


        public UnityRandomRangeGenerator(float min, float max)
        {
            _min = min;
            _max = max;
        }


        public float Generate() => Random.Range(_min, _max);
    }
}

Palaksanaan UnityEngine.Random.value

Harta nilai kelas statik UnityEngine.Random mulih tipe ngambang ti rentang tetep tina nilai [0; 1). Hayu urang proyek eta onto rentang dibikeun dina cara nu sarua salaku nalika nerapkeun System.Random.NextDouble ().

using UnityEngine;

namespace RandomDistribution
{
    public class UnityRandomValueGenerator : IRandomGenerator
    {
        private readonly float _factor;
        private readonly float _min;


        public string Name => "UnityEngine.Random.value";


        public UnityRandomValueGenerator(float min, float max)
        {
            _factor = max - min;
            _min = min;
        }


        public float Generate() => (float)(Random.value * _factor) + _min;
    }
}

Palaksanaan Unity.Mathematics.Random.NextFloat()

Metodeu NextFloat () kelas Unity.Mathematics.Random mulih hiji floating titik tipe ngambang tur ngidinan Anjeun pikeun nangtukeun sauntuyan nilai. Hiji-hijina nuansa nyaéta yén unggal conto Unity.Mathematics.Random kedah diinisialisasi ku sababaraha siki - ku cara ieu urang bakal nyingkahan ngahasilkeun sekuen anu diulang.

using Unity.Mathematics;

namespace RandomDistribution
{
    public class UnityMathematicsRandomValueGenerator : IRandomGenerator
    {
        private Random _generator;
        private readonly float _min;
        private readonly float _max;


        public string Name => "Unity.Mathematics.Random.NextFloat()";


        public UnityMathematicsRandomValueGenerator(float min, float max)
        {
            _min = min;
            _max = max;
            _generator = new Random();
            _generator.InitState(unchecked((uint)System.DateTime.Now.Ticks));
        }


        public float Generate() => _generator.NextFloat(_min, _max);
    }
}

Palaksanaan MainController

Sababaraha palaksanaan IRandomGenerator parantos siap. Salajengna, anjeun kedah ngahasilkeun sekuen sareng nyimpen set data anu hasilna pikeun diolah. Jang ngalampahkeun ieu, urang bakal nyieun adegan jeung Aksara MainController leutik di Unity, nu bakal ngalakukeun sagala pagawean diperlukeun tur dina waktos anu sareng jadi jawab interaksi jeung UI.

Hayu urang setel ukuran set data sareng kisaran nilai MF, sareng ogé kéngingkeun metode anu ngabalikeun sababaraha generator anu dikonpigurasi sareng siap dianggo.

namespace RandomDistribution
{
    public class MainController : MonoBehaviour
    {
        private const int DefaultDatasetSize = 100000;

        public float MinValue = 0f;
        public float MaxValue = 100f;

        ...

        private IRandomGenerator[] CreateRandomGenerators()
        {
            return new IRandomGenerator[]
            {
                new SystemIntegerRandomGenerator(MinValue, MaxValue),
                new SystemDoubleRandomGenerator(MinValue, MaxValue),
                new UnityRandomRangeGenerator(MinValue, MaxValue),
                new UnityRandomValueGenerator(MinValue, MaxValue),
                new UnityMathematicsRandomValueGenerator(MinValue, MaxValue)
            };
        }

        ...
    }
}

Ayeuna hayu urang ngadamel set data. Dina hal ieu, generasi data bakal digabungkeun sareng ngarékam hasil kana aliran téks (dina format csv). Pikeun nyimpen nilai unggal IRandomGenerator, kolom misah sorangan disadiakeun, sarta baris kahiji ngandung Ngaran generator nu.

namespace RandomDistribution
{
    public class MainController : MonoBehaviour
    {
        ...
		
        private void GenerateCsvDataSet(TextWriter writer, int dataSetSize, params IRandomGenerator[] generators)
        {
            const char separator = ',';
            int lastIdx = generators.Length - 1;

            // write header
            for (int j = 0; j <= lastIdx; j++)
            {
                writer.Write(generators[j].Name);
                if (j != lastIdx)
                    writer.Write(separator);
            }
            writer.WriteLine();

            // write data
            for (int i = 0; i <= dataSetSize; i++)
            {
                for (int j = 0; j <= lastIdx; j++)
                {
                    writer.Write(generators[j].Generate());
                    if (j != lastIdx)
                        writer.Write(separator);
                }

                if (i != dataSetSize)
                    writer.WriteLine();
            }
        }

        ...
    }
}

Sadaya anu tetep nyaéta nyauran metodeu GenerateCsvDataSet sareng simpen hasilna kana file, atanapi langsung nransper data dina jaringan tina alat tungtung ka server anu nampi.

namespace RandomDistribution
{
    public class MainController : MonoBehaviour
    {
        ...
		
        public void GenerateCsvDataSet(string path, int dataSetSize, params IRandomGenerator[] generators)
        {
            using (var writer = File.CreateText(path))
            {
                GenerateCsvDataSet(writer, dataSetSize, generators);
            }
        }


        public string GenerateCsvDataSet(int dataSetSize, params IRandomGenerator[] generators)
        {
            using (StringWriter writer = new StringWriter(CultureInfo.InvariantCulture))
            {
                GenerateCsvDataSet(writer, dataSetSize, generators);
                return writer.ToString();
            }
        }

        ...
    }
}

Sumber proyék aya di GitLab.

Hasil

Taya kaajaiban lumangsung. Anu diarepkeun nyaéta anu aranjeunna kéngingkeun - dina sagala hal, distribusi anu rata tanpa aya konspirasi. Kuring henteu ningali titik dina nempatkeun grafik anu misah pikeun platform - aranjeunna sadayana nunjukkeun hasil anu sami.

kanyataanana nyaéta:
BlessRNG atanapi pariksa RNG pikeun fairness

Visualisasi urutan dina pesawat tina sakabeh lima métode generasi:
BlessRNG atanapi pariksa RNG pikeun fairness

Jeung visualisasi dina 3D. Kuring gé ninggalkeun ukur hasil System.Random.Next () ku kituna teu ngahasilkeun kebat eusi idéntik.
BlessRNG atanapi pariksa RNG pikeun fairness

Carita ngawartoskeun dina bubuka ngeunaan sebaran normal UnityEngine.Random teu ngulang sorangan: boh éta mimitina erroneous, atawa hal geus saprak robah dina mesin. Tapi ayeuna urang yakin.

sumber: www.habr.com

Tambahkeun komentar