BlessRNG หรือตรวจสอบ RNG เพื่อความเป็นธรรม

BlessRNG หรือตรวจสอบ RNG เพื่อความเป็นธรรม

ในการพัฒนาเกม คุณมักจะต้องผูกบางสิ่งเข้ากับการสุ่ม: Unity มีการสุ่มของตัวเองสำหรับสิ่งนี้ และในทางกลับกันก็มี System.Random กาลครั้งหนึ่ง ในโครงการหนึ่ง ฉันรู้สึกว่าทั้งสองสามารถทำงานได้แตกต่างกัน (แม้ว่าทั้งสองควรจะมีการกระจายที่เท่ากันก็ตาม)

จากนั้นพวกเขาไม่ได้ลงรายละเอียด - แค่การเปลี่ยนไปใช้ System.Random ก็เพียงพอแล้วที่จะแก้ไขปัญหาทั้งหมด ตอนนี้เราตัดสินใจที่จะดูรายละเอียดเพิ่มเติมและดำเนินการวิจัยเล็กๆ น้อยๆ ว่า RNG “ลำเอียง” หรือคาดการณ์ได้เป็นอย่างไร และอันไหนที่จะเลือก ยิ่งกว่านั้นฉันเคยได้ยินความคิดเห็นที่ขัดแย้งกันเกี่ยวกับ "ความซื่อสัตย์" ของพวกเขามากกว่าหนึ่งครั้ง - ลองพิจารณาว่าผลลัพธ์ที่แท้จริงเปรียบเทียบกับที่ประกาศไว้อย่างไร

โปรแกรมการศึกษาแบบย่อหรือ RNG จริงๆ แล้วคือ RNG

หากคุณคุ้นเคยกับเครื่องสร้างตัวเลขสุ่มอยู่แล้ว คุณสามารถข้ามไปที่ส่วน "การทดสอบ" ได้ทันที

ตัวเลขสุ่ม (RN) คือลำดับของตัวเลขที่สร้างขึ้นโดยใช้กระบวนการสุ่ม (วุ่นวาย) ซึ่งเป็นแหล่งที่มาของเอนโทรปี นั่นคือ นี่คือลำดับที่องค์ประกอบต่างๆ ไม่ได้เชื่อมโยงกันตามกฎทางคณิตศาสตร์ใดๆ - ไม่มีความสัมพันธ์ระหว่างเหตุและผล

สิ่งที่สร้างตัวเลขสุ่มเรียกว่าเครื่องสร้างตัวเลขสุ่ม (RNG) ดูเหมือนว่าทุกอย่างจะเป็นเรื่องพื้นฐาน แต่ถ้าเราเปลี่ยนจากทฤษฎีไปสู่การปฏิบัติจริง ๆ แล้วมันไม่ง่ายเลยที่จะใช้อัลกอริธึมซอฟต์แวร์เพื่อสร้างลำดับดังกล่าว

เหตุผลก็คือในกรณีที่ไม่มีความสับสนวุ่นวายแบบเดียวกันในอุปกรณ์อิเล็กทรอนิกส์สำหรับผู้บริโภคยุคใหม่ หากไม่มีมัน ตัวเลขสุ่มก็จะไม่เป็นแบบสุ่ม และเครื่องกำเนิดของพวกมันจะกลายเป็นฟังก์ชันปกติของอาร์กิวเมนต์ที่กำหนดไว้อย่างชัดเจน สำหรับความเชี่ยวชาญเฉพาะด้านในสาขาไอที นี่เป็นปัญหาร้ายแรง (เช่น การเข้ารหัส) แต่สำหรับสาขาอื่นๆ ก็มีวิธีแก้ปัญหาที่ยอมรับได้อย่างสมบูรณ์

จำเป็นต้องเขียนอัลกอริทึมที่จะส่งคืนแม้ว่าจะไม่ใช่ตัวเลขสุ่มอย่างแท้จริง แต่ให้ใกล้เคียงที่สุดเท่าที่จะเป็นไปได้ - สิ่งที่เรียกว่าตัวเลขสุ่มหลอก (PRN) อัลกอริทึมในกรณีนี้เรียกว่าเครื่องกำเนิดตัวเลขสุ่มเทียม (PRNG)

มีหลายตัวเลือกในการสร้าง PRNG แต่สิ่งต่อไปนี้จะเกี่ยวข้องกับทุกคน:

  1. ความจำเป็นในการเริ่มต้นเบื้องต้น

    PRNG ไม่มีแหล่งที่มาของเอนโทรปี ดังนั้นจึงต้องได้รับสถานะเริ่มต้นก่อนใช้งาน โดยระบุเป็นตัวเลข (หรือเวกเตอร์) และเรียกว่าเมล็ด (เมล็ดสุ่ม) บ่อยครั้งที่ตัวนับนาฬิกาของโปรเซสเซอร์หรือตัวเลขที่เทียบเท่ากับเวลาของระบบถูกใช้เป็นข้อมูลเริ่มต้น

  2. ความสามารถในการทำซ้ำของลำดับ

    PRNG ถูกกำหนดไว้อย่างสมบูรณ์ ดังนั้นข้อมูลเริ่มต้นที่ระบุระหว่างการกำหนดค่าเริ่มต้นจะกำหนดลำดับตัวเลขในอนาคตทั้งหมดโดยไม่ซ้ำกัน ซึ่งหมายความว่า PRNG ที่แยกกันซึ่งเริ่มต้นด้วย seed เดียวกัน (ในเวลาที่ต่างกัน ในโปรแกรมที่ต่างกัน บนอุปกรณ์ที่แตกต่างกัน) จะสร้างลำดับเดียวกัน

คุณต้องรู้การแจกแจงความน่าจะเป็นที่กำหนดลักษณะของ PRNG ด้วย - มันจะสร้างตัวเลขอะไรและความน่าจะเป็นเท่าใด ส่วนใหญ่แล้วนี่คือการแจกแจงแบบปกติหรือการแจกแจงแบบสม่ำเสมอ
BlessRNG หรือตรวจสอบ RNG เพื่อความเป็นธรรม
การแจกแจงแบบปกติ (ซ้าย) และการกระจายแบบสม่ำเสมอ (ขวา)

สมมุติว่าเราตายอย่างยุติธรรมซึ่งมี 24 ด้าน หากคุณทอย ความน่าจะเป็นที่จะได้เลขหนึ่งจะเท่ากับ 1/24 (เช่นเดียวกับความน่าจะเป็นที่จะได้เลขอื่น) หากคุณโยนหลายครั้งและบันทึกผลลัพธ์ คุณจะสังเกตเห็นว่าขอบทั้งหมดหลุดออกมาด้วยความถี่เดียวกันโดยประมาณ โดยพื้นฐานแล้ว แม่พิมพ์นี้ถือได้ว่าเป็น RNG ที่มีการกระจายสม่ำเสมอ

จะเป็นอย่างไรถ้าคุณโยนลูกเต๋าเหล่านี้ 10 ลูกพร้อมกันแล้วนับคะแนนรวมล่ะ? จะรักษาความสม่ำเสมอเอาไว้หรือไม่? เลขที่ ส่วนใหญ่แล้วจำนวนเงินจะอยู่ใกล้ 125 จุดนั่นคือเป็นค่าเฉลี่ย และด้วยเหตุนี้ แม้กระทั่งก่อนที่จะทำการขว้าง คุณก็สามารถประมาณผลลัพธ์ในอนาคตได้อย่างคร่าว ๆ

เหตุผลก็คือ มีจำนวนชุดค่าผสมมากที่สุดเพื่อให้ได้คะแนนเฉลี่ย ยิ่งอยู่ห่างจากมันมากเท่าไร การรวมกันก็จะน้อยลงเท่านั้น และด้วยเหตุนี้ ความน่าจะเป็นที่จะสูญเสียก็จะยิ่งน้อยลงเท่านั้น หากมองเห็นข้อมูลนี้ จะมีลักษณะคล้ายกับรูปร่างระฆังอย่างคลุมเครือ ดังนั้นหากยืดออกไปอีกหน่อย ระบบลูกเต๋า 10 ลูกจึงสามารถเรียกว่า RNG ด้วยการแจกแจงแบบปกติ

อีกตัวอย่างหนึ่ง เฉพาะครั้งนี้บนเครื่องบิน - ยิงไปที่เป้าหมาย เกมยิงจะเป็น RNG ที่สร้างคู่ตัวเลข (x, y) ที่แสดงบนกราฟ
BlessRNG หรือตรวจสอบ RNG เพื่อความเป็นธรรม
ยอมรับว่าตัวเลือกทางด้านซ้ายนั้นใกล้เคียงกับชีวิตจริงมากขึ้น - นี่คือ RNG ที่มีการแจกแจงแบบปกติ แต่ถ้าคุณต้องการกระจายดาวในท้องฟ้าที่มืดมิด ตัวเลือกที่เหมาะสมซึ่งได้รับโดยใช้ RNG ที่มีการกระจายแบบสม่ำเสมอจะเหมาะสมกว่า โดยทั่วไป ให้เลือกเครื่องกำเนิดไฟฟ้าขึ้นอยู่กับงานที่ทำอยู่

ทีนี้เรามาพูดถึงเอนโทรปีของลำดับ PNG กัน ตัวอย่างเช่น มีลำดับที่เริ่มต้นดังนี้:

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

ตัวเลขเหล่านี้สุ่มแค่ไหนเมื่อมองแวบแรก? เริ่มต้นด้วยการตรวจสอบการกระจายตัว
BlessRNG หรือตรวจสอบ RNG เพื่อความเป็นธรรม
มันดูใกล้เคียงกัน แต่ถ้าคุณอ่านลำดับของตัวเลขสองตัวแล้วตีความว่าเป็นพิกัดบนระนาบ คุณจะได้สิ่งนี้:
BlessRNG หรือตรวจสอบ RNG เพื่อความเป็นธรรม
ลวดลายจะมองเห็นได้ชัดเจน และเนื่องจากข้อมูลในลำดับได้รับการเรียงลำดับในลักษณะใดลักษณะหนึ่ง (นั่นคือ มีเอนโทรปีต่ำ) สิ่งนี้จึงสามารถทำให้เกิด "อคติ" เช่นนั้นได้ อย่างน้อยที่สุด PRNG ดังกล่าวไม่เหมาะนักสำหรับการสร้างพิกัดบนเครื่องบิน

ลำดับอื่น:

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

ดูเหมือนทุกอย่างจะเรียบร้อยดีที่นี่แม้แต่บนเครื่องบิน:
BlessRNG หรือตรวจสอบ RNG เพื่อความเป็นธรรม
มาดูกันในปริมาณ (อ่านครั้งละสามตัวเลข):
BlessRNG หรือตรวจสอบ RNG เพื่อความเป็นธรรม
และรูปแบบอีกครั้ง การสร้างภาพข้อมูลแบบสี่มิติเป็นไปไม่ได้อีกต่อไป แต่รูปแบบสามารถมีอยู่ในมิตินี้และในมิติที่ใหญ่กว่าได้

ในการเข้ารหัสซึ่งมีการกำหนดข้อกำหนดที่เข้มงวดที่สุดกับ PRNG สถานการณ์ดังกล่าวเป็นสิ่งที่ยอมรับไม่ได้อย่างเด็ดขาด ดังนั้นจึงมีการพัฒนาอัลกอริธึมพิเศษเพื่อประเมินคุณภาพซึ่งเราจะไม่พูดถึงในตอนนี้ หัวข้อนี้กว้างขวางและสมควรได้รับบทความแยกต่างหาก

การทดสอบ

ถ้าเราไม่รู้บางสิ่งบางอย่างอย่างแน่นอน แล้วจะทำอย่างไรกับมัน? คุ้มไหมที่จะข้ามถนนถ้าคุณไม่รู้ว่าสัญญาณไฟจราจรไหนอนุญาตให้ข้ามถนน? ผลที่ตามมาอาจแตกต่างกัน

เช่นเดียวกับการสุ่มที่ฉาวโฉ่ใน Unity เป็นการดีถ้าเอกสารเปิดเผยรายละเอียดที่จำเป็น แต่เรื่องราวที่กล่าวถึงในตอนต้นของบทความเกิดขึ้นอย่างแม่นยำเนื่องจากขาดข้อมูลเฉพาะที่ต้องการ

และหากคุณไม่รู้ว่าเครื่องมือทำงานอย่างไร คุณจะใช้งานไม่ถูกต้องได้ โดยทั่วไป ถึงเวลาแล้วที่จะต้องตรวจสอบและดำเนินการทดลองเพื่อให้แน่ใจว่าอย่างน้อยที่สุดเกี่ยวกับการกระจายตัว

วิธีแก้ปัญหานั้นง่ายและมีประสิทธิภาพ - รวบรวมสถิติ รับข้อมูลวัตถุประสงค์ และดูผลลัพธ์

สาขาวิชา

มีหลายวิธีในการสร้างตัวเลขสุ่มใน Unity - เราทดสอบห้าวิธี

  1. System.Random.Next() สร้างจำนวนเต็มในช่วงค่าที่กำหนด
  2. System.Random.NextDouble() สร้างตัวเลขความแม่นยำสองเท่าในช่วงตั้งแต่ [0; 1)
  3. UnityEngine.Random.Range() สร้างตัวเลขความแม่นยำเดี่ยว (ลอยตัว) ในช่วงของค่าที่กำหนด
  4. UnityEngine.Random.value สร้างตัวเลขความแม่นยำเดี่ยว (ลอยตัว) ในช่วงตั้งแต่ [0; 1)
  5. Unity.Mathematics.Random.NextFloat() ส่วนหนึ่งของไลบรารี Unity.Mathematics ใหม่ สร้างตัวเลขความแม่นยำเดี่ยว (ลอยตัว) ในช่วงของค่าที่กำหนด

เกือบทุกที่ในเอกสารมีการระบุการกระจายแบบสม่ำเสมอ ยกเว้น UnityEngine.Random.value (โดยที่ไม่ได้ระบุการกระจาย แต่โดยการเปรียบเทียบกับ UnityEngine.Random.Range() คาดว่าจะมีเครื่องแบบเหมือนกัน) และ Unity.Mathematics.Random .NextFloat() (โดยที่ The พื้นฐานคืออัลกอริธึม xorshift ซึ่งหมายความว่าคุณต้องรอการกระจายแบบสม่ำเสมออีกครั้ง)

ตามค่าเริ่มต้น ผลลัพธ์ที่คาดหวังจะถูกนำไปใช้ตามที่ระบุไว้ในเอกสารประกอบ

ระเบียบวิธี

เราเขียนแอปพลิเคชันขนาดเล็กที่สร้างลำดับตัวเลขสุ่มโดยใช้แต่ละวิธีที่นำเสนอและบันทึกผลลัพธ์เพื่อการประมวลผลต่อไป

ความยาวของแต่ละลำดับคือ 100 หมายเลข
ช่วงของตัวเลขสุ่มคือ [0, 100)

ข้อมูลถูกรวบรวมจากหลายแพลตฟอร์มเป้าหมาย:

  • Windows
    — Unity v2018.3.14f1, โหมดตัวแก้ไข, โมโน, .NET Standard 2.0
  • MacOS
    — Unity v2018.3.14f1, โหมดตัวแก้ไข, โมโน, .NET Standard 2.0
    — Unity v5.6.4p4, โหมดตัวแก้ไข, โมโน, .NET Standard 2.0
  • Android
    — Unity v2018.3.14f1, รุ่นต่ออุปกรณ์, Mono, .NET Standard 2.0
  • iOS
    — Unity v2018.3.14f1, สร้างต่ออุปกรณ์, il2cpp, .NET Standard 2.0

การดำเนินงาน

เรามีหลายวิธีในการสร้างตัวเลขสุ่ม สำหรับแต่ละคลาส เราจะเขียนคลาส wrapper แยกกัน ซึ่งควรมี:

  1. ความเป็นไปได้ในการตั้งค่าช่วงของค่า [ต่ำสุด/สูงสุด) จะถูกตั้งค่าผ่านตัวสร้าง
  2. วิธีการคืน MF เรามาเลือกประเภท float กันดีกว่า เนื่องจากเป็นแบบทั่วไปมากกว่า
  3. ชื่อของวิธีการสร้างสำหรับการทำเครื่องหมายผลลัพธ์ เพื่อความสะดวก เราจะส่งคืนเป็นค่าชื่อเต็มของคลาส + ชื่อของวิธีที่ใช้ในการสร้าง MF

ขั้นแรก เรามาประกาศนามธรรมที่จะแสดงโดยอินเทอร์เฟซ IRandomGenerator:

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

        float Generate();
    }
}

การใช้งาน System.Random.Next()

วิธีนี้ช่วยให้คุณสามารถตั้งค่าช่วงของค่าได้ แต่จะส่งคืนจำนวนเต็ม แต่จำเป็นต้องมีการลอยตัว คุณสามารถตีความจำนวนเต็มเป็นการลอยตัวหรือขยายช่วงของค่าตามลำดับความสำคัญหลายระดับโดยชดเชยค่าเหล่านั้นด้วยระดับกลางแต่ละรุ่น ผลลัพธ์จะเหมือนกับจุดคงที่ซึ่งมีลำดับความแม่นยำที่กำหนด เราจะใช้ตัวเลือกนี้เนื่องจากใกล้กับค่าทศนิยมที่แท้จริงมากขึ้น

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

การใช้งาน System.Random.NextDouble()

นี่คือช่วงของค่าคงที่ [0; 1) ในการฉายภาพลงบนค่าที่ระบุในตัวสร้าง เราใช้เลขคณิตอย่างง่าย: X * (สูงสุด − นาที) + นาที

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

การใช้งาน UnityEngine.Random.Range()

วิธีการของคลาสคงที่ UnityEngine.Random นี้ช่วยให้คุณสามารถตั้งค่าช่วงของค่าและส่งกลับประเภทโฟลต คุณไม่จำเป็นต้องทำการแปลงเพิ่มเติมใดๆ

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

การใช้งาน UnityEngine.Random.value

คุณสมบัติค่าของคลาสคงที่ UnityEngine.Random ส่งคืนประเภท float จากช่วงค่าคงที่ [0; 1) เรามาฉายภาพบนช่วงที่กำหนดในลักษณะเดียวกับเมื่อใช้ 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;
    }
}

การใช้งาน Unity.Mathematics.Random.NextFloat()

เมธอด NextFloat() ของคลาส Unity.Mathematics.Random ส่งคืนจุดลอยตัวของประเภท float และอนุญาตให้คุณระบุช่วงของค่า ความแตกต่างเพียงอย่างเดียวคือแต่ละอินสแตนซ์ของ Unity.Mathematics.Random จะต้องเริ่มต้นด้วยเมล็ดบางส่วน - วิธีนี้เราจะหลีกเลี่ยงการสร้างลำดับที่ซ้ำกัน

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

การใช้งาน MainController

การใช้งาน IRandomGenerator หลายอย่างพร้อมแล้ว ถัดไป คุณต้องสร้างลำดับและบันทึกชุดข้อมูลผลลัพธ์สำหรับการประมวลผล ในการดำเนินการนี้ เราจะสร้างฉากและสคริปต์ MainController ขนาดเล็กใน Unity ซึ่งจะทำงานที่จำเป็นทั้งหมดและในขณะเดียวกันก็รับผิดชอบในการโต้ตอบกับ UI

มากำหนดขนาดของชุดข้อมูลและช่วงของค่า MF และรับวิธีที่ส่งคืนอาร์เรย์ของเครื่องกำเนิดไฟฟ้าที่กำหนดค่าและพร้อมใช้งาน

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

        ...
    }
}

ตอนนี้เรามาสร้างชุดข้อมูลกันดีกว่า ในกรณีนี้ การสร้างข้อมูลจะรวมกับการบันทึกผลลัพธ์ลงในสตรีมข้อความ (ในรูปแบบ CSV) ในการจัดเก็บค่าของ IRandomGenerator แต่ละตัว คอลัมน์แยกของตัวเองจะถูกจัดสรร และบรรทัดแรกจะมีชื่อของตัวสร้าง

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

        ...
    }
}

สิ่งที่เหลืออยู่คือการเรียกเมธอด GenerateCsvDataSet และบันทึกผลลัพธ์ลงในไฟล์หรือถ่ายโอนข้อมูลผ่านเครือข่ายทันทีจากอุปกรณ์ปลายทางไปยังเซิร์ฟเวอร์ที่รับ

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

        ...
    }
}

แหล่งที่มาของโครงการอยู่ที่ GitLab.

ผลการวิจัย

ไม่มีปาฏิหาริย์เกิดขึ้น สิ่งที่พวกเขาคาดหวังคือสิ่งที่พวกเขาได้รับ - ในทุกกรณี การกระจายที่เท่าเทียมกันโดยไม่มีการสมรู้ร่วมคิด ฉันไม่เห็นประเด็นในการแยกกราฟสำหรับแพลตฟอร์ม - กราฟทั้งหมดแสดงผลลัพธ์ที่เหมือนกันโดยประมาณ

ความจริงคือ:
BlessRNG หรือตรวจสอบ RNG เพื่อความเป็นธรรม

การสร้างภาพลำดับบนระนาบจากวิธีการสร้างทั้งห้าวิธี:
BlessRNG หรือตรวจสอบ RNG เพื่อความเป็นธรรม

และการแสดงภาพในรูปแบบ 3 มิติ ฉันจะเหลือเพียงผลลัพธ์ของ System.Random.Next() เพื่อไม่ให้สร้างเนื้อหาที่เหมือนกันจำนวนมาก
BlessRNG หรือตรวจสอบ RNG เพื่อความเป็นธรรม

เรื่องราวที่เล่าในบทนำเกี่ยวกับการกระจาย UnityEngine แบบปกติการสุ่มไม่ได้เกิดขึ้นซ้ำ: ในตอนแรกมีข้อผิดพลาดหรือมีบางอย่างเปลี่ยนแปลงไปในเครื่องยนต์ แต่ตอนนี้เราแน่ใจแล้ว

ที่มา: will.com

เพิ่มความคิดเห็น