BlessRNG ko duba RNG don adalci

BlessRNG ko duba RNG don adalci

A cikin ci gaban wasan, sau da yawa kuna buƙatar ɗaure wani abu tare da bazuwar: Unity yana da nasa Random don wannan, kuma a cikin layi ɗaya tare da shi akwai System.Random. Da zarar wani lokaci, a kan ɗayan ayyukan, na sami ra'ayi cewa duka biyu na iya yin aiki daban-daban (ko da yake ya kamata su sami ma rarraba).

Sa'an nan ba su shiga cikin cikakkun bayanai ba - ya isa cewa canzawa zuwa System.Random ya gyara duk matsalolin. Yanzu mun yanke shawarar bincika shi daki-daki kuma mu gudanar da ɗan bincike kaɗan: yadda “RNGs masu son zuciya” ko tsinkaya suke, da wanda za a zaɓa. Bugu da ƙari, fiye da sau ɗaya na ji ra'ayoyi masu karo da juna game da "gaskiya" su - bari mu yi ƙoƙari mu gano yadda ainihin sakamakon ya kwatanta da waɗanda aka bayyana.

Takaitaccen shirin ilimi ko RNG shine ainihin RNG

Idan kun riga kun saba da masu samar da lambar bazuwar, to zaku iya tsallake zuwa sashin "Gwaji".

Lambobin bazuwar (RN) jerin lambobi ne da aka samar ta amfani da wasu tsarin bazuwar (hargitsi), tushen entropy. Wato wannan shi ne jerin abubuwan da duk wata doka ta lissafi ba su da alaƙa da abubuwan da ke tattare da su - ba su da alaƙa da dalili da tasiri.

Abin da ke ƙirƙira lambar bazuwar ita ake kira da janareta na lambar bazuwar (RNG). Zai yi kama da cewa komai na farko ne, amma idan muka matsa daga ka'idar zuwa aiki, to a zahiri ba abu ne mai sauƙi ba don aiwatar da algorithm na software don samar da irin wannan jerin.

Dalilin ya ta'allaka ne a cikin rashin wannan rudani a cikin kayan lantarki na zamani. Idan ba tare da shi ba, bazuwar lambobi sun daina zama bazuwar, kuma janaretansu ya zama aikin yau da kullun na ƙayyadaddun hujjoji. Ga wasu ƙwararrun ƙwararru a fagen IT, wannan babbar matsala ce (misali, cryptography), amma ga wasu akwai cikakkiyar yarda da mafita.

Wajibi ne a rubuta algorithm wanda zai dawo, ko da yake ba da gaske ba lambobi ba, amma kusa da su - abin da ake kira pseudo-random lambobi (PRN). Algorithm a cikin wannan yanayin ana kiransa janareta mai lamba pseudorandom (PRNG).

Akwai zaɓuɓɓuka da yawa don ƙirƙirar PRNG, amma waɗannan zasu dace da kowa da kowa:

  1. Bukatar farawa na farko.

    PRNG ba shi da tushen entropy, don haka dole ne a ba shi yanayin farko kafin amfani. An ayyana shi azaman lamba (ko vector) kuma ana kiransa iri (tsaron bazuwar iri). Sau da yawa, ma'aunin agogon na'ura mai sarrafawa ko daidai da lokacin tsarin ana amfani da shi azaman iri.

  2. Maimaitu jerin abubuwa.

    PRNG yana da ƙayyadaddun ƙayyadaddun ƙayyadaddun ƙayyadaddun bayanai, don haka iri da aka kayyade yayin ƙaddamarwa ta musamman ke ƙayyade duk jerin lambobi na gaba. Wannan yana nufin cewa PRNG daban da aka fara da iri ɗaya (a lokuta daban-daban, a cikin shirye-shirye daban-daban, akan na'urori daban-daban) zai haifar da jeri iri ɗaya.

Hakanan kuna buƙatar sanin yiwuwar rarrabawar da ke nuna PRNG - waɗanne lambobi ne za su haifar da kuma waɗanne yuwuwar. Mafi sau da yawa wannan shine ko dai rabawa na al'ada ko kuma rarraba iri ɗaya.
BlessRNG ko duba RNG don adalci
Rarraba na al'ada (hagu) da rarraba iri ɗaya (dama)

Bari mu ce muna da mutuƙar gaskiya tare da bangarorin 24. Idan ka jefar da shi, yuwuwar samun ɗaya zai yi daidai da 1/24 (daidai da yuwuwar samun kowane lamba). Idan kun yi jifa da yawa da rikodin sakamakon, za ku lura cewa duk gefuna suna faɗuwa da kusan mitar iri ɗaya. Mahimmanci, ana iya ɗaukar wannan mutuwar RNG tare da rarraba iri ɗaya.

Menene idan kuka jefa 10 na waɗannan dice guda ɗaya kuma ku ƙidaya jimillar maki? Shin za a kiyaye daidaito a kai? A'a. Mafi sau da yawa, adadin zai kasance kusa da maki 125, wato, zuwa wasu matsakaicin darajar. Kuma a sakamakon haka, ko da kafin yin jifa, za ku iya kimanta sakamakon gaba.

Dalilin shi ne cewa akwai mafi girman adadin haɗuwa don samun matsakaicin maki. Mafi nisa daga gare ta, ƙananan haɗuwa - kuma, bisa ga haka, ƙananan yuwuwar asara. Idan an hango wannan bayanan, zai yi kama da siffar kararrawa. Saboda haka, tare da wasu shimfidawa, ana iya kiran tsarin dice 10 RNG tare da rarraba ta al'ada.

Wani misali, kawai wannan lokacin a kan jirgin sama - harbi a wani manufa. Mai harbi zai zama RNG wanda ke haifar da lambobi biyu (x, y) waɗanda aka nuna akan jadawali.
BlessRNG ko duba RNG don adalci
Yarda da cewa zaɓi na hagu ya fi kusa da rayuwa ta ainihi - wannan RNG ce tare da rarraba ta al'ada. Amma idan kuna buƙatar watsar da taurari a cikin sararin sama mai duhu, to, zaɓin da ya dace, wanda aka samu ta amfani da RNG tare da rarraba iri, ya fi dacewa. Gabaɗaya, zaɓi janareta dangane da aikin da ke hannu.

Yanzu bari muyi magana game da entropy na jerin PNG. Misali, akwai jerin da ke farawa kamar haka:

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

Yaya bazuwar waɗannan lambobin a kallon farko? Bari mu fara da duba rarraba.
BlessRNG ko duba RNG don adalci
Ya yi kama da uniform, amma idan ka karanta jerin lambobi biyu kuma ka fassara su azaman haɗin kai a kan jirgin sama, zaka sami wannan:
BlessRNG ko duba RNG don adalci
Alamu sun zama bayyane a fili. Kuma tun da aka ba da umarnin bayanan da ke cikin jeri ta wata hanya (wato yana da ƙananan entropy), wannan na iya haifar da wannan "ƙauna". Aƙalla, irin wannan PRNG bai dace sosai don samar da haɗin kai a kan jirgin sama ba.

Wani jerin:

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

Komai yana da kyau a nan ko da a cikin jirgin:
BlessRNG ko duba RNG don adalci
Mu duba cikin girma (karanta lambobi uku a lokaci guda):
BlessRNG ko duba RNG don adalci
Kuma sake da alamu. Ba zai yiwu a sake gina abin gani a cikin girma huɗu ba. Amma alamu na iya kasancewa akan wannan girman kuma akan manya.

A cikin cryptography, inda mafi tsananin buƙatu aka sanya akan PRNGs, irin wannan yanayin ba shi da karbuwa sosai. Saboda haka, an ƙirƙiri algorithms na musamman don tantance ingancin su, waɗanda ba za mu taɓa su yanzu ba. Batun yana da yawa kuma ya cancanci labarin daban.

Gwaji

Idan ba mu san wani abu ba tabbas, to yaya za a yi aiki da shi? Shin yana da daraja ketare hanya idan ba ku san wane hasken zirga-zirga ya ba shi damar ba? Sakamakon zai iya bambanta.

Haka yake ga sanannen bazuwar a cikin Unity. Yana da kyau idan takardun ya bayyana cikakkun bayanai masu mahimmanci, amma labarin da aka ambata a farkon labarin ya faru daidai saboda rashin ƙayyadaddun abubuwan da ake so.

Kuma idan ba ku san yadda kayan aikin ke aiki ba, ba za ku iya amfani da shi daidai ba. Gabaɗaya, lokaci ya yi don dubawa da gudanar da gwaji don ƙarshe tabbatar da aƙalla game da rarrabawa.

Maganinta ya kasance mai sauƙi kuma mai tasiri - tattara ƙididdiga, sami bayanan haƙiƙa kuma duba sakamakon.

Batun nazari

Akwai hanyoyi da yawa don samar da lambobi bazuwar a cikin Unity - mun gwada biyar.

  1. Tsarin.Random.Na gaba(). Yana haifar da ƙididdiga a cikin kewayon ƙima.
  2. Tsarin.Random.NextDouble(). Yana haifar da daidaitattun lambobi biyu a cikin kewayo daga [0; 1).
  3. UnityEngine.Random.Range(). Yana haifar da daidaitattun lambobi guda ɗaya ( masu iyo) a cikin kewayon ƙimar da aka bayar.
  4. UnityEngine.Random.darajar. Yana haifar da daidaitattun lambobi guda ɗaya (yana iyo) a cikin kewayo daga [0; 1).
  5. Haɗin kai.Mathematics.Random.NextFloat(). Wani ɓangare na sabon ɗakin karatu na Unity.Mathematics. Yana haifar da daidaitattun lambobi guda ɗaya ( masu iyo) a cikin kewayon ƙimar da aka bayar.

Kusan a ko'ina a cikin takardun an ƙayyade rarraba kayan aiki, ban da UnityEngine.Random.value (inda ba a ƙayyade rarraba ba, amma ta hanyar kwatanta tare da UnityEngine.Random.Range() uniform an kuma sa ran) da Unity.Mathematics.Random. .NextFloat () (inda a cikin Tushen shine algorithm xorshift, wanda ke nufin cewa kuma kuna buƙatar jira don rarraba uniform).

Ta hanyar tsoho, an ɗauki sakamakon da ake tsammani kamar waɗanda aka ƙayyade a cikin takaddun.

Hanyar hanya

Mun rubuta ƙaramin aikace-aikacen da ya haifar da jerin lambobin bazuwar ta amfani da kowane hanyoyin da aka gabatar kuma mun adana sakamakon don ƙarin aiki.

Tsawon kowane jeri shine lambobi 100.
Kewayon lambobin bazuwar shine [0, 100).

An tattara bayanai daga dandamali da yawa na manufa:

  • Windows
    - Unity v2018.3.14f1, Yanayin Edita, Mono, NET Standard 2.0
  • macOS
    - Unity v2018.3.14f1, Yanayin Edita, Mono, NET Standard 2.0
    - Unity v5.6.4p4, Yanayin Edita, Mono, .NET Standard 2.0
  • Android
    - Unity v2018.3.14f1, gina kowane na'ura, Mono, .NET Standard 2.0
  • iOS
    - Unity v2018.3.14f1, gina kowane na'ura, il2cpp, NET Standard 2.0

Aiwatarwa

Muna da hanyoyi daban-daban don samar da lambobi bazuwar. Ga kowane ɗayansu, za mu rubuta nau'in nadi daban, wanda yakamata ya samar:

  1. Yiwuwar saita kewayon ƙimar [min/max). Za a saita ta hanyar ginin ginin.
  2. Hanyar dawowa MF. Bari mu zaɓi iyo a matsayin nau'in, kamar yadda ya fi kowa.
  3. Sunan hanyar tsara don yiwa sakamako alama. Don dacewa, za mu dawo azaman darajar cikakken sunan ajin + sunan hanyar da aka yi amfani da shi don samar da MF.

Da farko, bari mu ayyana abstraction wanda IrandomGenerator ke wakilta:

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

        float Generate();
    }
}

Aiwatar da Tsarin.Random.Na gaba()

Wannan hanyar tana ba ku damar saita ƙimar ƙima, amma tana mayar da lamba, amma ana buƙatar masu iyo. Kuna iya kawai fassara lamba azaman mai iyo, ko zaku iya faɗaɗa kewayon ƙimar ta umarni da yawa na girma, kuna rama su tare da kowane ƙarni na matsakaicin matsakaici. Sakamakon zai zama wani abu kamar kafaffen wuri tare da tsari da aka ba da daidaito. Za mu yi amfani da wannan zaɓi tunda yana kusa da ainihin ƙimar ta iyo.

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

Aiwatar da Tsarin.Random.NextDouble()

Anan tsayayyen kewayon ƙimar [0; 1). Don aiwatar da shi a kan wanda aka ƙayyade a cikin maginin, muna amfani da lissafi mai sauƙ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;
    }
}

Aiwatar da UnityEngine.Random.Range()

Wannan hanyar UnityEngine.Random static class ba ka damar saita kewayon dabi'u da kuma mayar da irin taso kan ruwa. Ba dole ba ne ka yi ƙarin canje-canje.

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

Aiwatar da UnityEngine.Random.darajar

Ƙimar darajar rukunin UnityEngine.Random yana dawo da nau'in iyo daga ƙayyadadden ƙimar ƙimar [0; 1). Bari mu aiwatar da shi zuwa kewayon da aka bayar daidai da lokacin aiwatar da 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;
    }
}

Aiwatar da Haɗin kai.Mathematics.Random.NextFloat()

Hanya na gabaFloat() na Unity.Mathematics.Random class yana dawo da wurin iyo na nau'in iyo kuma yana ba ku damar ƙididdige ƙimar ƙima. Iyakar abin da ke faruwa shine kowane misali na Unity.Mathematics.Random dole ne a fara shi da wasu iri - ta haka za mu guji haifar da maimaitawa.

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

Aiwatar da MainController

Yawancin aiwatarwa na IRandomGenerator sun shirya. Na gaba, kuna buƙatar samar da jeri da adana bayanan da aka samu don sarrafawa. Don yin wannan, za mu ƙirƙiri wani wuri da ƙaramin rubutun MainController a cikin Unity, wanda zai yi duk aikin da ake buƙata kuma a lokaci guda yana da alhakin hulɗa tare da UI.

Bari mu saita girman saitin bayanai da kewayon ƙimar MF, sannan mu sami hanyar da za ta dawo da tsararrun janareta da aka saita kuma a shirye don aiki.

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

        ...
    }
}

Yanzu bari mu ƙirƙiri saitin bayanai. A wannan yanayin, za a haɗa samar da bayanai tare da yin rikodin sakamakon cikin rafin rubutu (a cikin tsarin csv). Don adana dabi'u na kowane IRandomGenerator, an keɓe kansa daban ginshiƙi, kuma layin farko ya ƙunshi Sunan janareta.

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

        ...
    }
}

Abin da ya rage shine a kira hanyar GenerateCsvDataSet kuma ajiye sakamakon zuwa fayil, ko canja wurin bayanai nan da nan akan hanyar sadarwa daga na'urar ƙarshe zuwa uwar garken mai karɓa.

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

        ...
    }
}

Tushen aikin suna a GitLab.

Результаты

Babu wani abin al'ajabi da ya faru. Abin da suke tsammanin shine abin da suka samu - a kowane hali, rarraba ko da ba tare da alamar makirci ba. Ban ga ma'anar sanya hotuna daban-daban don dandamali ba - duk suna nuna kusan sakamako iri ɗaya.

Gaskiyar ita ce:
BlessRNG ko duba RNG don adalci

Kallon jeri a kan jirgin sama daga dukkan hanyoyin ƙarni biyar:
BlessRNG ko duba RNG don adalci

Kuma gani a cikin 3D. Zan bar kawai sakamakon System.Random.Next() don kada in samar da tarin abun ciki iri ɗaya.
BlessRNG ko duba RNG don adalci

Labarin da aka fada a cikin gabatarwar game da rarrabawar al'ada na UnityEngine.Random bai sake maimaita kansa ba: ko dai kuskure ne da farko, ko kuma wani abu ya canza a cikin injin. Amma yanzu mun tabbata.

source: www.habr.com

Add a comment