วิธีที่เร็วที่สุดในการสร้างบูลีนแบบสุ่ม


87

ดังนั้นจึงมีหลายวิธีในการสร้างบูลแบบสุ่มใน C #:

  • ใช้ Random.Next (): rand.Next(2) == 0
  • ใช้ Random.NextDouble (): rand.NextDouble() > 0.5

มีความแตกต่างจริงหรือ? ถ้าเป็นเช่นนั้นอันไหนมีประสิทธิภาพดีกว่ากัน? หรือมีวิธีอื่นที่ฉันไม่เห็นซึ่งอาจเร็วกว่านี้?



7
นี่คือคอขวดจริงๆหรือ?
Brian Rasmussen

2
โดยไม่ต้องเรียกใช้จริง (เพราะวิธีใด ๆ จะเร็วอย่างน่าหัวเราะ) ฉันเดาว่าจะใช้NextBytesเพื่อเติมอาร์เรย์ไบต์ล่วงหน้าใช้BitArrayเพื่อเปลี่ยนเป็นชุดบูลีนและดึงข้อมูลบูลีนเหล่านั้นจาก a Queueจนกว่าจะหมดจากนั้นทำซ้ำ กระบวนการ. ด้วยวิธีนี้คุณจะใช้เครื่องสุ่มเพียงครั้งเดียวดังนั้นค่าใช้จ่ายใด ๆ ที่สร้างขึ้นจะเกิดขึ้นเมื่อคุณเติมคิวเท่านั้น สิ่งนี้อาจมีประโยชน์เมื่อจัดการกับตัวสร้างตัวเลขสุ่มที่ปลอดภัยแทนที่จะเป็นRandomคลาสปกติ
Joe Enos

2
@JoeEnos MS ทำให้การใช้งานยุ่งเหยิงNextBytesดังนั้นจึงช้าอย่างน่าประหลาดใจ
CodesInChaos

1
@CodesInChaos ว้าวมันน่าสนใจ - ฉันเพิ่งค้นหามันในตัวแยกชิ้นส่วนเพื่อดูว่าคุณกำลังอ้างถึงอะไร: buffer[i] = (byte)(this.InternalSample() % 256);- ฉันคิดว่านั่นคือสิ่งที่คุณกำลังพูดถึงว่าพวกเขาสามารถนำจำนวนเต็มสุ่มนั้นมาแบ่งเป็น 3 ไบต์ เติมอาร์เรย์ไบต์โดยประมาณ 1/3 ของงาน ฉันสงสัยว่ามีเหตุผลสำหรับสิ่งนั้นหรือเป็นเพียงการกำกับดูแลของนักพัฒนา
Joe Enos

คำตอบ:


72

ตัวเลือกแรก - rand.Next(2)รันอยู่เบื้องหลังรหัสต่อไปนี้:

if (maxValue < 0)
{
    throw new ArgumentOutOfRangeException("maxValue",
        Environment.GetResourceString("ArgumentOutOfRange_MustBePositive", new object[] { "maxValue" }));
}
return (int) (this.Sample() * maxValue);

และสำหรับตัวเลือกที่สอง - rand.NextDouble():

return this.Sample();

เนื่องจากตัวเลือกแรกที่มีmaxValueการตรวจสอบการคูณและการหล่อตัวเลือกที่สองน่าจะได้เร็วขึ้น


ขอบคุณนั่นคือทั้งหมดที่ฉันอยากรู้
หมดเวลา

5
การกำหนดเวลาของฉันเองบอกว่าตัวเลือกที่สองเร็วกว่าตัวแรกประมาณ 5%
ClickRick

61

การปรับปรุงเล็กน้อยสำหรับตัวเลือกที่สอง :

ตามMSDN

public virtual double NextDouble()

ผลตอบแทน

เลขทศนิยมที่มีความแม่นยำสองเท่ามากกว่าหรือเท่ากับ 0.0 และน้อยกว่า 1.0

ดังนั้นหากคุณต้องการบูลแบบสุ่มที่กระจายอย่างสม่ำเสมอคุณควรใช้ >= 0.5

rand.NextDouble() >= 0.5

ช่วง 1: [0.0 ... 0.5 [
ช่วง 2: [0.5 ... 1.0 [
| ช่วง 1 | = | ช่วง 2 |


10

ที่เร็วที่สุด. การเรียกใช้เมธอดRandom.Nextมีค่าใช้จ่ายน้อยกว่า วิธีขยายด้านล่างวิ่ง 20% เร็วกว่าRandom.NextDouble() > 0.5และ 35% Random.Next(2) == 0เร็วกว่า

public static bool NextBoolean(this Random random)
{
    return random.Next() > (Int32.MaxValue / 2);
    // Next() returns an int in the range [0..Int32.MaxValue]
}

เร็วกว่าเร็วที่สุด เป็นไปได้ที่จะสร้างบูลีนแบบสุ่มด้วยRandomคลาสได้เร็วขึ้นโดยใช้เทคนิค 31 บิตที่มีนัยสำคัญของ a ที่สร้างขึ้นintสามารถใช้สำหรับการผลิตบูลีน 31 รายการที่ตามมา การใช้งานด้านล่างนี้เร็วกว่าการประกาศก่อนหน้านี้ถึง 40% ว่าเร็วที่สุด

public class RandomEx : Random
{
    private uint _boolBits;

    public RandomEx() : base() { }
    public RandomEx(int seed) : base(seed) { }

    public bool NextBoolean()
    {
        _boolBits >>= 1;
        if (_boolBits <= 1) _boolBits = (uint)~this.Next();
        return (_boolBits & 1) == 0;
    }
}

ขอบคุณ! สำหรับผู้ที่ใช้ UnityEngine ในการเขียนสคริปต์อย่าลืมใช้ System.Random ไม่ใช่ UnityEngine.Random เนื่องจากไม่ใช่สิ่งเดียวกัน!
DonCarleone

6

ฉันทำการทดสอบด้วยนาฬิกาจับเวลา การทำซ้ำ 100,000 ครั้ง:

System.Random rnd = new System.Random();
if (rnd.Next(2) == 0)
     trues++;

ซีพียูเหมือนจำนวนเต็มดังนั้นเมธอด Next (2) จึงเร็วกว่า 3,700 เทียบกับ 7,500ms ซึ่งค่อนข้างมาก นอกจากนี้: ฉันคิดว่าตัวเลขสุ่มอาจเป็นปัญหาคอขวดฉันสร้างประมาณ 50 ทุกเฟรมใน Unity แม้จะมีฉากเล็ก ๆ ที่ทำให้ระบบของฉันช้าลงอย่างเห็นได้ชัดดังนั้นฉันก็หวังว่าจะหาวิธีสร้างบูลแบบสุ่ม ดังนั้นฉันก็พยายามด้วย

if (System.DateTime.Now.Millisecond % 2 == 0)
       trues++;

แต่การเรียกใช้ฟังก์ชันคงที่ทำได้ช้ากว่าด้วย 9,600ms คุ้มค่ากับการยิง ในที่สุดฉันก็ข้ามการเปรียบเทียบและสร้างค่าสุ่มเพียง 100,000 ค่าเพื่อให้แน่ใจว่าการเปรียบเทียบระหว่าง int เทียบกับสองครั้งไม่ส่งผลต่อเวลาที่ผ่านไป แต่ผลลัพธ์ก็ค่อนข้างเหมือนกัน


1
DateTime ตอนนี้ช้าอย่างฉาวโฉ่ ควรใช้โซลูชันที่ขึ้นอยู่กับฮาร์ดแวร์หรืออย่างน้อยก็ขึ้นอยู่กับระบบปฏิบัติการเพื่อให้รวดเร็ว
Do-do-new

ใช้DateTime.UtcNowงานได้เร็วกว่าDateTime.Nowมาก
Theodor Zoulias
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.