เอ็นจิ้นตัวเลขสุ่มของ <random> ใดที่ควรใช้ในทางปฏิบัติจริง ๆ มาตรฐาน :: mt19937?


21

สมมติว่าคุณต้องการใช้<random>สิ่งอำนวยความสะดวกC ++ ในโปรแกรมที่ใช้งานจริง (สำหรับคำจำกัดความของ "การปฏิบัติ" บางข้อ จำกัด ที่นี่เป็นส่วนหนึ่งของคำถามนี้) คุณได้รับรหัสคร่าว ๆ เช่นนี้:

int main(int argc, char **argv) {
    int seed = get_user_provided_seed_value(argc, argv);
    if (seed == 0) seed = std::random_device()();
    ENGINE g(seed);  // TODO: proper seeding?
    go_on_and_use(g);
}

คำถามของฉันคือคุณควรใช้แบบENGINEไหน

  • ฉันเคยพูดเสมอstd::mt19937เพราะมันพิมพ์ได้อย่างรวดเร็วและมีการจดจำชื่อ แต่ทุกวันนี้ดูเหมือนว่าทุกคนกำลังพูดว่า Mersenne Twister นั้นหนักและแคชไม่เป็นมิตรและไม่ผ่านการทดสอบทางสถิติทั้งหมดที่คนอื่นทำ

  • ฉันต้องการพูดstd::default_random_engineเพราะเป็น "ค่าเริ่มต้น" ที่ชัดเจน แต่ฉันไม่รู้ว่ามันแตกต่างจากแพลตฟอร์มหนึ่งไปอีกแพลตฟอร์มหรือไม่และฉันไม่รู้ว่ามันดีทางสถิติหรือไม่

  • เนื่องจากทุกคนอยู่บนแพลตฟอร์ม 64 บิตวันนี้อย่างน้อยเราควรจะใช้std::mt19937_64มากกว่าstd::mt19937หรือไม่

  • ฉันต้องการที่จะพูดpcg64หรือxoroshiro128เพราะพวกเขาดูดีและมีน้ำหนักเบา แต่พวกเขาไม่ได้อยู่ใน<random>นั้น

  • ผมไม่ทราบอะไรเกี่ยวกับminstd_rand, minstd_rand0, ranlux24, knuth_bฯลฯ - แน่นอนพวกเขาจะต้องดีสำหรับบางสิ่งบางอย่าง?

เห็นได้ชัดว่ามีข้อ จำกัด บางอย่างในการแข่งขันที่นี่

  • ความแข็งแรงของเครื่องยนต์ ( <random>ไม่มี PRNG ที่แข็งแกร่งในการเข้ารหัส แต่ยังบางส่วนของมาตรฐานที่ได้รับการ "อ่อนแอ" กว่าคนอื่นใช่มั้ย?)

  • sizeof เครื่องยนต์

  • operator()ความเร็วของ

  • ความง่ายในการเพาะ mt19937เป็นการยากที่จะหว่านเมล็ดอย่างเหมาะสมเนื่องจากมีสถานะมากในการเริ่มต้น

  • ความสะดวกในการพกพาระหว่างผู้จำหน่ายห้องสมุด หากผู้ขายรายหนึ่งfoo_engineผลิตหมายเลขที่แตกต่างจากผู้จำหน่ายรายอื่นfoo_engineนั่นไม่ดีสำหรับบางแอปพลิเคชัน (หวังว่านี่จะเป็นข้อยกเว้นdefault_random_engineบางอย่างออกไป)

การชั่งน้ำหนักข้อ จำกัด เหล่านี้ให้มากที่สุดเท่าที่คุณจะทำได้คุณจะพูดว่าอะไรคือคำตอบที่ดีที่สุด "คำตอบที่ดีที่สุดสำหรับการอยู่ภายในห้องสมุดมาตรฐาน" ฉันควรจะใช้ต่อstd::mt19937ไปหรืออะไรนะ?


2
จนถึงจุดสุดท้ายของคุณอะแด็ปเตอร์เอ็นจิ้นมาตรฐานทั้งหมดจะถูกระบุเพื่อส่งคืนค่าเฉพาะในการเรียกใช้ที่ต่อเนื่องกันของค่าเริ่มต้นที่สร้างขึ้นดังนั้นจึงควรพกพาได้
1201ProgramAlarm

คำตอบ:


15

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

  • default_random_engine มีการกำหนดการใช้งานดังนั้นจึงไม่ทราบว่าเครื่องยนต์มีข้อบกพร่องทางสถิติที่แอปพลิเคชันอาจสนใจหรือไม่
  • linear_congruential_engineใช้เครื่องกำเนิดไฟฟ้าเชิงเส้นที่สอดคล้องกัน อย่างไรก็ตามพวกเขามักจะมีคุณภาพไม่ดีเว้นแต่โมดูลัสนั้นดีและใหญ่มาก (อย่างน้อย 64 บิต) นอกจากนี้พวกเขาไม่สามารถยอมรับเมล็ดมากกว่าโมดูลัสของพวกเขา
  • minstd_rand0และminstd_randยอมรับเพียงประมาณ 2 ^ 31 เมล็ด knuth_bล้อมรอบminstd_rand0และสลับสับเปลี่ยนของ Bays – Durham
  • mt19937และmt19937_64สามารถรับเมล็ดได้มากขึ้นหากเริ่มต้นได้ดีกว่า (เช่นการเริ่มต้น a std::seed_seqด้วยเอาต์พุตจำนวนrandom_deviceมากไม่ใช่แค่เพียงเมล็ดเดียว) แต่ใช้สถานะประมาณ 2500 ไบต์
  • ranlux24และranlux48ใช้สถานะประมาณ 577 บิต แต่จะช้า (ทำงานได้โดยการเก็บรักษาบางส่วนและยกเลิกเอาต์พุต pseudorandom อื่น ๆ )

อย่างไรก็ตาม C ++ ยังมีเอ็นจิ้นสองตัวที่ห่อเอ็นจิ้นอื่นเพื่อปรับปรุงคุณสมบัติการสุ่มของมัน:

  • discard_block_engine ทิ้งเอาต์พุตบางส่วนของเอนจินการสุ่มที่กำหนด
  • shuffle_order_engine ใช้ Bays – Durham shuffle ของเอ็นจินสุ่ม

ยกตัวอย่างเช่นมันเป็นไปได้ที่การพูดที่จะมีการสับเปลี่ยนอ่าว-เดอร์แฮมmt19937, ranlux24หรือกำหนดเองด้วยlinear_congruential_engine shuffle_order_engineบางทีเครื่องยนต์ที่หุ้มไว้อาจมีคุณภาพดีกว่าของเดิม แต่ก็ยากที่จะทำนายเครื่องยนต์ใหม่ของคุณภาพทางสถิติโดยไม่ต้องทดสอบ

ดังนั้นเมื่อรอการทดสอบดังกล่าวดูเหมือนว่าmt19937เป็นเครื่องมือที่ใช้งานได้จริงที่สุดในมาตรฐาน C ++ ในขณะนี้ อย่างไรก็ตามฉันรู้ว่ามีข้อเสนออย่างน้อยหนึ่งข้อที่จะเพิ่มเอ็นจินตัวเลขสุ่มอีกตัวในเวอร์ชัน C ++ ในอนาคต (ดูC ++ paper P2075 )


1

ตามที่c ++ อ้างอิง , default_random_engine:

การเลือกของตัวสร้างไลบรารี่ของ implemention ที่ให้พฤติกรรมของเอ็นจิ้นที่ยอมรับได้อย่างน้อยสำหรับการใช้งานที่ค่อนข้างไม่เป็นทางการและ / หรือมีน้ำหนักเบา

ดังนั้นสำหรับการใช้งานที่มีน้ำหนักเบาคุณไม่จำเป็นต้องกังวลเกี่ยวกับสิ่งใดเมล็ดพันธุ์ที่default_random_engineมีEpoch Time (time(0))และนั่นจะดีพอ;)


ฉันเชื่อว่าปัญหาที่นี่คือการพกพา แม้ว่าค่าเริ่มต้นอาจเป็นเอ็นจิ้นที่ทำงานได้ดี แต่อาจไม่สามารถทำซ้ำได้บนแพลตฟอร์มอื่น
bremen_matt

@bremen_matt อืม ... ทำไมเราต้องสร้างหมายเลข "สุ่ม" อีกครั้ง
Farbod Ahmadian

2
การทดสอบ เพื่อจุดประสงค์ในการทดสอบคุณต้องมีอินพุตที่สามารถผลิตซ้ำได้ ในเวลาเดียวกันคุณอาจต้องการหรือต้องการอินพุตเหล่านั้นเป็นแบบสุ่ม ตัวอย่างเช่นอัลกอริทึมการเรียนรู้ของเครื่องส่วนใหญ่สมมติว่าพารามิเตอร์นั้นเริ่มต้นด้วยการสุ่ม Ransac, CNNs, DNNs, ... อัลกอริทึมจำนวนมากต้องการพารามิเตอร์แบบสุ่ม
bremen_matt
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.