BlessRNG jew iċċekkja l-RNG għall-ġustizzja

BlessRNG jew iċċekkja l-RNG għall-ġustizzja

Fl-iżvilupp tal-logħob, ħafna drabi għandek bżonn torbot xi ħaġa ma 'randomness: Unity għandha Random tagħha stess għal dan, u b'mod parallel magħha hemm System.Random. Darba, fuq wieħed mill-proġetti, ħadt l-impressjoni li t-tnejn jistgħu jaħdmu b’mod differenti (għalkemm għandu jkollhom distribuzzjoni uniformi).

Imbagħad ma daħlux fid-dettalji - kien biżżejjed li t-tranżizzjoni għal System.Random ikkoreġiet il-problemi kollha. Issa ddeċidejna li nħarsu f'aktar dettall u nagħmlu ftit riċerka: kemm huma "preġudikati" jew prevedibbli RNGs, u liema waħda tagħżel. Barra minn hekk, aktar minn darba smajt opinjonijiet kunfliġġenti dwar l-"onestà" tagħhom - ejja nippruvaw insemmu kif ir-riżultati reali jqabblu ma 'dawk iddikjarati.

Programm edukattiv qasir jew RNG huwa attwalment RNG

Jekk inti diġà familjari mal-ġeneraturi ta 'numri każwali, allura tista' immedjatament taqbeż it-taqsima "Ittestjar".

Numri każwali (RN) huma sekwenza ta 'numri ġġenerati bl-użu ta' xi proċess każwali (kaotiku), sors ta 'entropija. Jiġifieri, din hija sekwenza li l-elementi tagħha mhumiex interkonnessi minn ebda liġi matematika - m'għandhom l-ebda relazzjoni ta 'kawża u effett.

Dak li joħloq in-numru każwali jissejjaħ ġeneratur ta 'numru każwali (RNG). Jidher li kollox huwa elementari, imma jekk nimxu mit-teorija għall-prattika, allura fil-fatt mhuwiex daqshekk sempliċi li timplimenta algoritmu ta 'softwer għall-ġenerazzjoni ta' sekwenza bħal din.

Ir-raġuni tinsab fin-nuqqas ta 'dak l-istess kaos fl-elettronika moderna tal-konsumatur. Mingħajrha, in-numri każwali ma jibqgħux każwali, u l-ġeneratur tagħhom jinbidel f'funzjoni ordinarja ta 'argumenti definiti b'mod ovvju. Għal numru ta 'speċjalitajiet fil-qasam tal-IT, din hija problema serja (per eżempju, kriptografija), iżda għal oħrajn hemm soluzzjoni kompletament aċċettabbli.

Huwa meħtieġ li tikteb algoritmu li jirritorna, għalkemm mhux numri verament każwali, iżda qrib kemm jista 'jkun tagħhom - l-hekk imsejħa numri psewdo-random (PRN). L-algoritmu f'dan il-każ jissejjaħ ġeneratur ta' numru pseudorandom (PRNG).

Hemm diversi għażliet biex jinħoloq PRNG, iżda dan li ġej se jkun rilevanti għal kulħadd:

  1. Il-ħtieġa għall-inizjalizzazzjoni preliminari.

    Il-PRNG m'għandu l-ebda sors ta 'entropija, għalhekk għandu jingħata stat inizjali qabel l-użu. Huwa speċifikat bħala numru (jew vettur) u jissejjaħ żerriegħa (żerriegħa każwali). Ħafna drabi, il-counter tal-arloġġ tal-proċessur jew l-ekwivalenti numeriku tal-ħin tas-sistema jintuża bħala żerriegħa.

  2. Riproduċibbiltà tas-sekwenza.

    Il-PRNG huwa kompletament deterministiku, għalhekk iż-żerriegħa speċifikata waqt l-inizjalizzazzjoni tiddetermina unikament is-sekwenza futura kollha tan-numri. Dan ifisser li PRNG separat inizjalizzat bl-istess żerriegħa (f'ħinijiet differenti, fi programmi differenti, fuq apparati differenti) se jiġġenera l-istess sekwenza.

Trid tkun taf ukoll id-distribuzzjoni tal-probabbiltà li tikkaratterizza l-PRNG - liema numri se tiġġenera u b'liema probabbiltà. Ħafna drabi din hija jew distribuzzjoni normali jew distribuzzjoni uniformi.
BlessRNG jew iċċekkja l-RNG għall-ġustizzja
Distribuzzjoni normali (xellug) u distribuzzjoni uniformi (lemin)

Ejja ngħidu li għandna die ġust b'24 naħa. Jekk titfagħha, il-probabbiltà li tikseb waħda tkun ugwali għal 1/24 (l-istess bħall-probabbiltà li tikseb xi numru ieħor). Jekk tagħmel ħafna throws u tirreġistra r-riżultati, tinduna li t-truf kollha jaqgħu barra bejn wieħed u ieħor bl-istess frekwenza. Essenzjalment, dan id-die jista 'jitqies bħala RNG b'distribuzzjoni uniformi.

X'jiġri jekk tarmi 10 minn dawn id-dadi f'daqqa u tgħodd il-punti totali? Se tinżamm l-uniformità għaliha? Nru. Ħafna drabi, l-ammont ikun qrib il-125 punt, jiġifieri, għal xi valur medju. U bħala riżultat, anki qabel ma tagħmel tarmi, tista 'bejn tistma r-riżultat futur.

Ir-raġuni hija li hemm l-akbar numru ta 'kombinazzjonijiet biex jinkiseb il-punteġġ medju. Aktar ma jkun 'il bogħod minnu, inqas kombinazzjonijiet - u, għaldaqstant, inqas tkun il-probabbiltà ta' telf. Jekk din id-dejta tiġi viżwalizzata, tixbah b'mod vag il-forma ta 'qanpiena. Għalhekk, b'xi stretch, sistema ta '10 dadi tista' tissejjaħ RNG b'distribuzzjoni normali.

Eżempju ieħor, din id-darba biss fuq ajruplan - sparar fuq mira. It-tiratur se jkun RNG li jiġġenera par numri (x, y) li jintwerew fuq il-graff.
BlessRNG jew iċċekkja l-RNG għall-ġustizzja
Naqbel li l-għażla fuq ix-xellug hija eqreb lejn il-ħajja reali - dan huwa RNG b'distribuzzjoni normali. Imma jekk għandek bżonn tferrex stilel f'sema skur, allura l-għażla t-tajba, miksuba bl-użu ta 'RNG b'distribuzzjoni uniformi, hija aktar adattata. B'mod ġenerali, agħżel ġeneratur skont il-kompitu li jkun hemm.

Issa ejja nitkellmu dwar l-entropija tas-sekwenza PNG. Pereżempju, hemm sekwenza li tibda hekk:

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, ...

Kemm huma każwali dawn in-numri mal-ewwel daqqa t'għajn? Nibdew billi niċċekkjaw id-distribuzzjoni.
BlessRNG jew iċċekkja l-RNG għall-ġustizzja
Jidher qrib l-uniformi, imma jekk taqra sekwenza ta’ żewġ numri u tinterpretahom bħala koordinati fuq pjan, ikollok dan:
BlessRNG jew iċċekkja l-RNG għall-ġustizzja
Il-mudelli jsiru viżibbli b'mod ċar. U peress li d-dejta fis-sekwenza hija ordnata b'ċertu mod (jiġifieri għandha entropyja baxxa), dan jista 'jwassal għal dak il-"preġudizzju" ħafna. Bħala minimu, tali PRNG mhuwiex adattat ħafna biex jiġġenera koordinati fuq pjan.

Sekwenza oħra:

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, ...

Jidher kollox tajjeb hawn anke fuq l-ajruplan:
BlessRNG jew iċċekkja l-RNG għall-ġustizzja
Ejja nħarsu fil-volum (aqra tliet numri kull darba):
BlessRNG jew iċċekkja l-RNG għall-ġustizzja
U għal darb'oħra l-mudelli. M'għadux possibbli li tinbena viżwalizzazzjoni f'erba' dimensjonijiet. Iżda mudelli jistgħu jeżistu fuq din id-dimensjoni u fuq oħrajn akbar.

Fil-kriptografija, fejn l-aktar rekwiżiti stretti huma imposti fuq il-PRNGs, sitwazzjoni bħal din hija kategorikament inaċċettabbli. Għalhekk, algoritmi speċjali ġew żviluppati biex jevalwaw il-kwalità tagħhom, li aħna mhux se tmisshom issa. Is-suġġett huwa estensiv u jistħoqqlu artiklu separat.

Ittestjar

Jekk ma nafux xi ħaġa żgur, allura kif naħdmu magħha? Ta’ min taqsam it-triq jekk ma tafx liema dawl tat-traffiku jippermettilu? Il-konsegwenzi jistgħu jkunu differenti.

L-istess jgħodd għall-każwali notorji f'Unità. Tajjeb jekk id-dokumentazzjoni tiżvela d-dettalji meħtieġa, iżda l-istorja msemmija fil-bidu tal-artiklu ġrat preċiżament minħabba n-nuqqas tal-ispeċifiċitajiet mixtieqa.

U jekk ma tkunx taf kif taħdem l-għodda, ma tkunx tista' tużaha b'mod korrett. B'mod ġenerali, wasal iż-żmien li tivverifika u twettaq esperiment biex finalment niżguraw mill-inqas dwar id-distribuzzjoni.

Is-soluzzjoni kienet sempliċi u effettiva - iġbor statistika, tikseb data oġġettiva u tħares lejn ir-riżultati.

Suġġett ta' studju

Hemm diversi modi kif tiġġenera numri bl-addoċċ f'Unity - ittestjajna ħamsa.

  1. System.Random.Next (). Jiġġenera numri interi f'firxa partikolari ta' valuri.
  2. System.Random.NextDouble(). Jiġġenera numri ta' preċiżjoni doppja fil-medda minn [0; 1).
  3. UnityEngine.Random.Range(). Jiġġenera numri ta' preċiżjoni waħda (floats) f'firxa partikolari ta' valuri.
  4. UnityEngine.Random.value. Jiġġenera numri ta' preċiżjoni waħda (floats) fil-medda minn [0; 1).
  5. Unity.Mathematics.Random.NextFloat(). Parti mil-librerija l-ġdida Unity.Mathematics. Jiġġenera numri ta' preċiżjoni waħda (floats) f'firxa partikolari ta' valuri.

Kważi kullimkien fid-dokumentazzjoni kienet speċifikata distribuzzjoni uniformi, bl-eċċezzjoni ta' UnityEngine.Random.value (fejn id-distribuzzjoni ma kinitx speċifikata, iżda b'analoġija ma' UnityEngine.Random.Range() uniformi kienet mistennija wkoll) u Unity.Mathematics.Random .NextFloat() (fejn fil Il-bażi hija l-algoritmu xorshift, li jfisser li għal darb'oħra għandek bżonn tistenna għal distribuzzjoni uniformi).

B'mod awtomatiku, ir-riżultati mistennija ttieħdu bħala dawk speċifikati fid-dokumentazzjoni.

Metodoloġija

Aħna ktibna applikazzjoni żgħira li ġġenerat sekwenzi ta 'numri każwali bl-użu ta' kull wieħed mill-metodi ppreżentati u ssejvjat ir-riżultati għal aktar ipproċessar.

It-tul ta 'kull sekwenza huwa 100 numru.
Il-firxa ta 'numri każwali hija [0, 100).

Id-dejta nġabret minn diversi pjattaformi mmirati:

  • twieqi
    — Unity v2018.3.14f1, Mod Editur, Mono, .NET Standard 2.0
  • MacOS
    — Unity v2018.3.14f1, Mod Editur, Mono, .NET Standard 2.0
    — Unity v5.6.4p4, Mod Editur, Mono, .NET Standard 2.0
  • Android
    — Unity v2018.3.14f1, bini għal kull apparat, Mono, .NET Standard 2.0
  • IOS
    — Unity v2018.3.14f1, build per device, il2cpp, .NET Standard 2.0

Реализация

Għandna diversi modi differenti biex niġġeneraw numri bl-addoċċ. Għal kull wieħed minnhom, aħna se niktbu klassi ta 'tgeżwir separata, li għandha tipprovdi:

  1. Possibbiltà li tissettja l-firxa ta 'valuri [min/max). Se jiġi stabbilit permezz tal-kostruttur.
  2. Metodu li jirritorna MF. Ejja nagħżlu float bħala t-tip, peress li huwa aktar ġenerali.
  3. L-isem tal-metodu tal-ġenerazzjoni għall-immarkar tar-riżultati. Għall-konvenjenza, aħna se nirritornaw bħala valur l-isem sħiħ tal-klassi + l-isem tal-metodu użat biex jiġġenera l-MF.

L-ewwel, ejja niddikjaraw astrazzjoni li se tkun rappreżentata mill-interface IRandomGenerator:

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

        float Generate();
    }
}

Implimentazzjoni ta' System.Random.Next()

Dan il-metodu jippermettilek li tissettja firxa ta 'valuri, iżda jirritorna numri interi, iżda huma meħtieġa sufruni. Tista 'sempliċement tinterpreta numru sħiħ bħala float, jew tista' tespandi l-firxa ta 'valuri b'diversi ordnijiet ta' kobor, u tikkumpensahom b'kull ġenerazzjoni tal-medda tan-nofs. Ir-riżultat se jkun xi ħaġa bħal punt fiss b'ordni partikolari ta 'eżattezza. Se nużaw din l-għażla peress li hija eqreb lejn il-valur float reali.

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;
    }
}

Implimentazzjoni ta' System.Random.NextDouble()

Hawnhekk il-firxa fissa ta 'valuri [0; 1). Biex tipproġettaha fuq dik speċifikata fil-kostruttur, nużaw aritmetika sempliċi: X * (max − min) + min.

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;
    }
}

Implimentazzjoni ta' UnityEngine.Random.Range()

Dan il-metodu tal-klassi statika UnityEngine.Random jippermettilek li tissettja firxa ta 'valuri u tirritorna tip float. M'għandekx għalfejn tagħmel xi trasformazzjonijiet addizzjonali.

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);
    }
}

Implimentazzjoni ta' UnityEngine.Random.value

Il-proprjetà tal-valur tal-klassi statika UnityEngine.Random tirritorna tip float minn firxa fissa ta 'valuri [0; 1). Ejja nipproġettawha fuq firxa partikolari bl-istess mod bħal meta nimplimentaw 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;
    }
}

Implimentazzjoni ta' Unity.Mathematics.Random.NextFloat()

Il-metodu NextFloat() tal-klassi Unity.Mathematics.Random jirritorna punt varjabbli tat-tip float u jippermettilek tispeċifika firxa ta' valuri. L-unika sfumatura hija li kull istanza ta 'Unity.Mathematics.Random se jkollha tiġi inizjalizzata b'xi żerriegħa - b'dan il-mod se nevitaw li niġġeneraw sekwenzi ripetuti.

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);
    }
}

Implimentazzjoni ta 'MainController

Diversi implimentazzjonijiet ta 'IRandomGenerator huma lesti. Sussegwentement, għandek bżonn tiġġenera sekwenzi u tissejvja s-sett tad-dejta li jirriżulta għall-ipproċessar. Biex tagħmel dan, aħna se noħolqu xena u skript MainController żgħir f'Unity, li se jagħmel ix-xogħol kollu meħtieġ u fl-istess ħin ikun responsabbli għall-interazzjoni mal-UI.

Ejja nissettjaw id-daqs tas-sett tad-dejta u l-firxa tal-valuri MF, u wkoll tikseb metodu li jirritorna firxa ta 'ġeneraturi kkonfigurati u lesti biex jaħdmu.

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)
            };
        }

        ...
    }
}

Issa ejja noħolqu dataset. F'dan il-każ, il-ġenerazzjoni tad-dejta se tkun ikkombinata mar-reġistrazzjoni tar-riżultati fi fluss tat-test (f'format csv). Biex taħżen il-valuri ta 'kull IRandomGenerator, il-kolonna separata tagħha hija allokata, u l-ewwel linja fiha l-Isem tal-ġeneratur.

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();
            }
        }

        ...
    }
}

Li jibqa 'huwa li ssejjaħ il-metodu GenerateCsvDataSet u ssalva r-riżultat f'fajl, jew tittrasferixxi immedjatament id-dejta fuq in-netwerk mill-apparat finali għas-server li jirċievi.

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();
            }
        }

        ...
    }
}

Is-sorsi tal-proġett huma fuq GitLab.

Sejbiet

Ma ġara l-ebda miraklu. Dak li stennew huwa dak li kisbu - fil-każijiet kollha, distribuzzjoni uniformi mingħajr ħjiel ta 'konfoffa. Ma narax il-punt li npoġġi graffs separati għall-pjattaformi - kollha juru bejn wieħed u ieħor l-istess riżultati.

Ir-realtà hija:
BlessRNG jew iċċekkja l-RNG għall-ġustizzja

Viżwalizzazzjoni ta' sekwenzi fuq pjan mill-ħames metodi ta' ġenerazzjoni kollha:
BlessRNG jew iċċekkja l-RNG għall-ġustizzja

U viżwalizzazzjoni fi 3D. Se nħalli biss ir-riżultat ta 'System.Random.Next() sabiex ma nipproduċix mazz ta' kontenut identiku.
BlessRNG jew iċċekkja l-RNG għall-ġustizzja

L-istorja li rrakkonta fl-introduzzjoni dwar id-distribuzzjoni normali ta 'UnityEngine.Random ma rrepetix ruħha: jew inizjalment kienet żbaljata, jew xi ħaġa minn dak iż-żmien inbidlet fil-magna. Imma issa aħna żgur.

Sors: www.habr.com

Żid kumment