อ่าน 13 นาที
ซอร์ชิฟต์
เครื่องกำเนิดเลขสุ่ม Xorshift หรือที่เรียกว่า เครื่องกำเนิดเลขสุ่มแบบรีจิสเตอร์เลื่อน เป็นกลุ่มของ เครื่องกำเนิดเลขสุ่มเทียม ที่คิดค้นโดย George Marsaglia [ 1 ] เป็น กลุ่มย่อยของ...
ซอร์ชิฟต์

เครื่องกำเนิดเลขสุ่ม Xorshiftหรือที่เรียกว่าเครื่องกำเนิดเลขสุ่มแบบรีจิสเตอร์เลื่อนเป็นกลุ่มของเครื่องกำเนิดเลขสุ่มเทียมที่คิดค้นโดยGeorge Marsaglia [ 1 ] เป็นกลุ่มย่อยของรีจิสเตอร์เลื่อนป้อนกลับเชิงเส้น (LFSR) ซึ่งช่วยให้สามารถใช้งานในซอฟต์แวร์ได้อย่างมีประสิทธิภาพเป็นพิเศษโดยไม่ต้องใช้พหุนามแบบเบาบางมากเกินไป[ 2 ]เครื่องกำเนิด เลขสุ่ม Xorshift สร้างเลขถัดไปในลำดับโดยการใช้การดำเนินการเอกซ์คลูซีฟออร์ซ้ำๆกับเลขหนึ่งที่เลื่อนบิตซึ่งทำให้การทำงานมีประสิทธิภาพสูงมากบนสถาปัตยกรรมคอมพิวเตอร์สมัยใหม่ แต่ไม่มีประโยชน์ต่อประสิทธิภาพในการใช้งานฮาร์ดแวร์ เช่นเดียวกับ LFSR ทั้งหมด พารามิเตอร์จะต้องถูกเลือกอย่างระมัดระวังเพื่อให้ได้ระยะเวลาที่ยาวนาน[ 3 ]
สำหรับการดำเนินการในซอฟต์แวร์ ตัวสร้าง xorshift เป็นหนึ่งใน PRNG ที่เร็วที่สุด โดยต้องการโค้ดและสถานะที่เล็กมาก อย่างไรก็ตาม พวกมันไม่ผ่านการทดสอบทางสถิติทุกครั้งหากไม่มีการปรับปรุงเพิ่มเติม จุดอ่อนนี้ได้รับการแก้ไขโดยการรวมเข้ากับฟังก์ชันที่ไม่เป็นเชิงเส้น ดังที่อธิบายไว้ในเอกสารต้นฉบับ เนื่องจากตัวสร้าง xorshift แบบธรรมดา (โดยไม่มีขั้นตอนที่ไม่เป็นเชิงเส้น) ล้มเหลวในการทดสอบทางสถิติบางอย่าง จึงถูกกล่าวหาว่าไม่น่าเชื่อถือ[ 3 ] : 360
ตัวอย่างการใช้งาน
เวอร์ชันC [ a ]ของอัลกอริธึม xorshift สามแบบ[ 1 ] : 4,5 มีให้ที่นี่ อัลกอริธึมแรกมีคำสถานะ 32 บิตหนึ่งคำ และคาบ 2 32 −1อัลกอริธึมที่สองมีคำสถานะ 64 บิตหนึ่งคำ และคาบ 2 64 −1 อัลกอริธึมสุดท้ายมีคำสถานะ 32 บิตสี่คำ และคาบ 2 128 −1 อัลกอริธึม 128 บิตผ่านการทดสอบ diehardอย่างไรก็ตาม มันไม่ผ่าน การทดสอบ MatrixRankและLinearCompของชุดทดสอบBigCrushจากเฟรมเวิร์ก TestU01
ทั้งหมดใช้ระบบการทำงานสามกะ และการดำเนินการแบบ Exclusive-OR สามหรือสี่ครั้ง:
#include <stdint.h>typedef struct { uint32_t a ; } XorShift32State ;// สถานะต้องถูกกำหนดค่าเริ่มต้นเป็นค่าที่ไม่ใช่ศูนย์uint32_t xorshift32 ( XorShift32State * state ) { // อัลกอริทึม "xor" จากหน้า 4 ของ Marsaglia, "Xorshift RNGs" uint32_t x = state -> a ; x ^= x << 13 ; x ^= x >> 17 ; x ^= x << 5 ; return state -> a = x ; }typedef struct { uint64_t a ; } XorShift64State ;// สถานะต้องถูกกำหนดค่าเริ่มต้นเป็นค่าที่ไม่ใช่ศูนย์uint64_t xorshift64 ( XorShift64State * state ) { uint64_t x = state -> a ; x ^= x << 13 ; x ^= x >> 7 ; x ^= x << 17 ; return state -> a = x ; }// XorShift128State สามารถกำหนดได้อีกทางหนึ่งเป็นคู่// ของ uint64_t หรือ uint128_t ในกรณีที่รองรับtypedef struct { uint32_t x [ 4 ]; } XorShift128State ;// สถานะต้องถูกกำหนดค่าเริ่มต้นเป็นค่าที่ไม่ใช่ศูนย์uint32_t xorshift128 ( XorShift128State * state ) { // อัลกอริทึม "xor128" จากหน้า 5 ของ Marsaglia, "Xorshift RNGs" uint32_t t = state -> x [ 3 ]; uint32_t s = state -> x [ 0 ]; // ทำการเลื่อนบิต 32 บิตที่สร้างขึ้นstate -> x [ 3 ] = state -> x [ 2 ]; state -> x [ 2 ] = state -> x [ 1 ]; state -> x [ 1 ] = s ;t ^= t << 11 ; t ^= t >> 8 ; return state -> x [ 0 ] = t ^ s ^ ( s >> 19 ); }ในกรณีของคำสถานะ 64 บิตหนึ่งคำ จะมีพารามิเตอร์ที่ยึดคาบ 2 64 −1 ด้วยการดำเนินการเอกซ์คลูซีฟออร์และเลื่อนสองคู่[ 2 ] [ 4 ]
#include <stdint.h>typedef struct { uint64_t a ; } XorShift64State ;uint64_t xorshift64 ( XorShift64State * state ) { uint64_t x = state -> a ; x ^= x << 7 ; x ^= x >> 9 ; return state -> a = x ; }การเปลี่ยนแปลงที่ไม่เป็นเชิงเส้น
ตัวสร้าง xorshift ทั้งหมดล้มเหลวในการทดสอบบางอย่างใน ชุดทดสอบ BigCrushนี่เป็นความจริงสำหรับตัวสร้างทั้งหมดที่ใช้ความสัมพันธ์เชิงเส้น เช่นMersenne TwisterหรือWELLอย่างไรก็ตาม การสุ่มลำดับเอาต์พุตของตัวสร้างเหล่านี้เพื่อปรับปรุงคุณภาพนั้นทำได้ง่าย
ตัวเข้ารหัสที่รู้จักกันในชื่อ+และ*ยังคงมีจุดอ่อนในบิตต่ำ[ 5 ]ดังนั้นจึงมีจุดประสงค์เพื่อใช้ในเลขทศนิยม ซึ่งบิตต่ำสุดของเลขทศนิยมมีผลกระทบต่อค่าที่ตีความน้อยกว่า[ 6 ]สำหรับวัตถุประสงค์ทั่วไป ตัวเข้ารหัส** (อ่านว่า สตา ร์สตาร์ ) ทำให้ตัวสร้าง LFSR ส่งผ่านบิตทั้งหมด
xorwow
มาร์ซาเกลียเสนอให้สุ่มผลลัพธ์โดยการรวมเข้ากับตัวนับบวกแบบง่ายๆ โมดูล 2 32 (ซึ่งเขาเรียกว่า " ลำดับไวล์ " ตามทฤษฎีบทการกระจายเท่าๆ กันของไวล์ ) วิธีนี้จะเพิ่มคาบขึ้นอีกเท่าตัวเป็น 2 192 −2 32 :
#include <stdint.h>typedef struct { uint32_t x [ 5 ]; uint32_t counter ; } XorWowState ;// อาร์เรย์สถานะต้องได้รับการเริ่มต้นเพื่อไม่ให้เป็นศูนย์ทั้งหมดในสี่คำแรกuint32_t xorwow ( XorWowState * state ) { // อัลกอริทึม "xorwow" จากหน้า 5 ของ Marsaglia, "Xorshift RNGs" uint32_t t = state -> x [ 4 ]; uint32_t s = state -> x [ 0 ]; // ทำการหมุน 32 บิตที่สร้างขึ้นstate -> x [ 4 ] = state -> x [ 3 ]; state -> x [ 3 ] = state -> x [ 2 ]; state -> x [ 2 ] = state -> x [ 1 ]; state -> x [ 1 ] = s ; t ^= t >> 2 ; t ^= t << 1 ; t ^= s ^ ( s << 4 ); state -> x [ 0 ] = t ; state- > counter += 362437 ; return t + state- > counter ; }การทำงานนี้ดี แต่ล้มเหลวในการทดสอบบางส่วนใน BigCrush [ 7 ] ตัวสร้างนี้เป็นค่าเริ่มต้นในชุดเครื่องมือCUDA ของ Nvidia [ 8 ]
xorshift*
ตัว สร้าง xorshift*ใช้การคูณแบบผกผันได้ (โมดูลัสขนาดคำ) เป็นการแปลงแบบไม่เชิงเส้นกับเอาต์พุตของ ตัวสร้าง xorshiftตามที่ Marsaglia แนะนำ[ 1 ] ตัวสร้าง xorshift*ทั้งหมดจะปล่อยลำดับของค่าที่กระจายอย่างเท่าเทียมกันในมิติสูงสุดที่เป็นไปได้ (ยกเว้นว่าจะไม่ส่งออกค่าศูนย์ติดต่อกัน 16 ครั้ง หรือ 128 ไบต์) [ 9 ]
ตัวสร้าง 64 บิตต่อไปนี้มีคาบสูงสุด 2 64 −1 [ 9 ]
#include <stdint.h>// xorshift64s, variant A_1(12,25,27) พร้อมตัวคูณ M_32 จากบรรทัดที่ 3 ของตารางที่ 5 uint64_t xorshift64star ( void ) { // ค่าเริ่มต้นต้องไม่ใช่ศูนย์ อย่าใช้ตัวแปร static สำหรับสถานะหากใช้มัลติเธรดstatic uint64_t x = 1 ; x ^= x >> 12 ; x ^= x << 25 ; x ^= x >> 27 ; return x * 0x2545F4914F6CDD1DULL ; }ตัวสร้างล้มเหลวเฉพาะ การทดสอบ MatrixRankของ BigCrush เท่านั้น อย่างไรก็ตาม หากตัวสร้างได้รับการแก้ไขให้ส่งคืนเฉพาะ 32 บิตสูงสุด ก็จะผ่าน BigCrush โดยไม่มีข้อผิดพลาดใดๆ[ 10 ] : 7 อันที่จริง เวอร์ชันที่ลดลงซึ่งมีสถานะภายในเพียง 40 บิตก็ผ่านชุดทดสอบ ซึ่งบ่งชี้ถึงระยะปลอดภัยที่มาก[ 10 ] : 19 ตัวสร้างที่คล้ายกันที่แนะนำในNumerical Recipes [ 11 ]ยังRanQ1ล้มเหลวในการทดสอบ BirthdaySpacings อีกด้วย
Vigna [ 9 ]แนะนำ ตัวสร้าง xorshift1024* ต่อไปนี้ ที่มีสถานะ 1024 บิตและคาบสูงสุด 2 1024 −1 อย่างไรก็ตาม มันไม่ได้ผ่าน BigCrush เสมอไป[ 5 ]ดังนั้น xoshiro256** จึงเป็นตัวเลือกที่ดีกว่ามาก
#include <stdint.h>// ต้องมีการกำหนดค่าเริ่มต้นให้กับสถานะเพื่อให้มีองค์ประกอบที่ไม่เป็นศูนย์อย่างน้อยหนึ่งรายการในอาร์เรย์typedef struct { uint64_t x [ 16 ]; int index ; } XorShift1024sState ;uint64_t xorshift1024s ( XorShift1024sState * state ) { int index = state -> index ; const uint64_t s = state -> x [ index ++ ]; uint64_t t = state -> x [ index &= 15 ]; t ^= t << 31 ; // a t ^= t >> 11 ; // b -- อีกครั้ง การเลื่อนและตัวคูณสามารถปรับแต่งได้t ^= s ^ ( s >> 30 ); // c state -> x [ index ] = t ; state -> index = index ; return t * 1181783497276652981ULL ; }xorshift+
ตัว สร้าง xorshift+สามารถลดอัตราความล้มเหลวได้น้อยกว่าMersenne TwisterหรือWELL ถึงหนึ่งลำดับขนาด การใช้งานตัวสร้าง xorshift+ ในภาษา C ดั้งเดิมที่ผ่านการทดสอบทั้งหมดจากชุด BigCrush สามารถสร้างตัวเลขสุ่มได้ในเวลาน้อยกว่า 10 รอบสัญญาณนาฬิกาบนx86 โดยทั่วไปแล้ว ต้องขอบคุณ การประมวลผลแบบไปป์ไลน์ ของคำสั่ง[ 12 ]
แทนที่จะใช้การคูณ สามารถใช้การบวกเป็นการแปลงแบบไม่เชิงเส้นที่เร็วกว่าได้ แนวคิดนี้ได้รับการเสนอครั้งแรกโดย Saito และ Matsumoto (ซึ่งเป็นผู้รับผิดชอบ Mersenne Twister ด้วย) ใน ตัวสร้าง XSaddซึ่งบวกเอาต์พุตที่ต่อเนื่องกันสองตัวของ ตัวสร้าง xorshift พื้นฐาน โดยอิงจากการเลื่อน 32 บิต[ 13 ]อย่างไรก็ตาม ข้อเสียอย่างหนึ่งของการบวกเอาต์พุตที่ต่อเนื่องกันคือ ในขณะที่ ตัวสร้าง xorshift128 พื้นฐาน มีการกระจายแบบเท่ากันใน 2 มิติ แต่ตัวสร้าง xorshift128+มีการกระจายแบบเท่ากันใน 1 มิติเท่านั้น[ 14 ]
XSaddมีจุดอ่อนบางประการในบิตลำดับต่ำของเอาต์พุต ซึ่งทำให้การทดสอบ BigCrush ล้มเหลวหลายครั้งเมื่อคำเอาต์พุตถูกกลับบิต เพื่อแก้ไขปัญหานี้ Vigna ได้แนะนำตระกูลxorshift+ [ 14 ]ซึ่งใช้การเลื่อนบิต 64 บิต ตัวสร้าง xorshift+แม้จะมีขนาดใหญ่ถึงxorshift1024+ก็ยังแสดงให้เห็นถึงความเป็นเส้นตรงที่ตรวจจับได้ในบิตลำดับต่ำของเอาต์พุต[ 5 ]ซึ่งผ่านการทดสอบ BigCrush แต่จะไม่ผ่านเมื่อใช้บิตลำดับต่ำสุด 32 บิตในลำดับย้อนกลับจากแต่ละคำ 64 บิต[ 5 ]ตัวสร้างนี้เป็นหนึ่งในตัวสร้างที่เร็วที่สุดที่ผ่านการทดสอบ BigCrush [ 12 ]
ตัวสร้าง xorshift128+ต่อไปนี้ใช้สถานะ 128 บิตและมีคาบสูงสุด 2 128 −1
#include <stdint.h>typedef struct { uint64_t x [ 2 ]; } XorShift128pState ;// ต้องมีการกำหนดค่าเริ่มต้นให้กับสถานะเพื่อไม่ให้เป็นศูนย์ทั้งหมดuint64_t xorshift128p ( XorShift128pState * state ) { uint64_t t = state -> x [ 0 ]; const uint64_t s = state -> x [ 1 ]; state -> x [ 0 ] = s ; t ^= t << 23 ; // a t ^= t >> 18 ; // b -- อีกครั้ง ค่าการเลื่อนและตัวคูณสามารถปรับได้t ^= s ^ ( s >> 5 ); // c state -> x [ 1 ] = t ; return t + s ; }xorshiftr+
ตัวสร้าง xorshiftr+ (r ย่อมาจาก reduced; อ่านว่า "xorshifter plus") ส่วนใหญ่ใช้ xorshift+ เป็นพื้นฐาน แต่มีการดัดแปลงทำให้เร็วขึ้นอย่างมาก (โดยเฉพาะบนอุปกรณ์ที่มีน้ำหนักเบา) และประสบความสำเร็จมากขึ้นในการทดสอบความสุ่ม (รวมถึงชุดทดสอบ TestU01 BigCrush) เมื่อเทียบกับรุ่นก่อนหน้า[ 15 ]เป็นหนึ่งในตัวสร้างที่เร็วที่สุดที่ผ่านการทดสอบทั้งหมดในชุดทดสอบ BigCrush ของ TestU01 เช่นเดียวกับ xorshift+ การใช้งานตัวสร้าง xorshiftr+ ในภาษา C ดั้งเดิมที่ผ่านการทดสอบทั้งหมดจากชุดทดสอบ BigCrush สามารถสร้างตัวเลขสุ่มได้ในเวลาน้อยกว่า 10 รอบสัญญาณนาฬิกาบนx86ต้องขอบคุณ การประมวลผลแบบไปป์ ไลน์ของคำสั่ง[ 12 ] [ 15 ]
ต่างจากxorshift+ xorshiftr +ไม่ได้คืนค่าผลรวมของตัวแปรสองตัวที่ได้มาจากสถานะโดยใช้ขั้นตอนแบบ xorshift แต่จะคืนค่าตัวแปรเดียวด้วยการดำเนินการสุดท้ายในรอบการทำงาน อย่างไรก็ตาม มันจะมีการบวกก่อนที่จะคืนค่า นั่นคือในขั้นตอนการปรับ seed สำหรับรอบถัดไป ดังนั้นจึงมีเครื่องหมาย "+" ในชื่อของอัลกอริทึม ขนาดของตัวแปร รวมถึงสถานะ สามารถเพิ่มขึ้นได้โดยไม่กระทบต่อคะแนนความสุ่ม แต่ประสิทธิภาพอาจลดลงในอุปกรณ์ที่มีน้ำหนักเบา
ตัวสร้าง xorshiftr128+ต่อไปนี้ใช้สถานะ 128 บิต (โดยมีตัวแปรสองตัว) และมีคาบสูงสุดที่ 2 128 −1
#include <stdint.h>typedef struct { uint64_t s [ 2 ]; // seeds } XorShiftR128PlusState ;// ต้องมีการกำหนดค่าเริ่มต้นให้กับสถานะเพื่อไม่ให้เป็นศูนย์ทั้งหมดuint64_t xorshiftr128plus ( XorShiftR128PlusState * state ) { uint64_t x = state -> s [ 0 ]; const uint64_t y = state -> s [ 1 ]; state -> s [ 0 ] = y ; x ^= x << 23 ; // shift & xor x ^= x >> 17 ; // shift & xor x ^= y ; // xor state -> s [ 1 ] = x + y ; return x ; }โซชิโร่
xoshiro (ย่อมาจาก "xor, shift, rotate") และ xoroshiro (ย่อมาจาก "xor, rotate, shift, rotate") ใช้การหมุนนอกเหนือจากการเลื่อน ตามที่ Vigna กล่าว พวกมันเร็วกว่าและให้ผลลัพธ์ที่มีคุณภาพดีกว่า xorshift [ 16 ] [ 17 ]
ตัวสร้างประเภทนี้มีรูปแบบสำหรับเอาต์พุต จำนวนเต็ม 32 บิตและ 64 บิตและเลขทศนิยม สำหรับเลขทศนิยม จะใช้ 53 บิตบน (สำหรับbinary64 ) หรือ 23 บิตบน (สำหรับbinary32 ) เนื่องจากบิตบนมีคุณภาพดีกว่าบิตล่างในตัวสร้างเลขทศนิยม อัลกอริทึมยังรวมถึงjumpฟังก์ชันที่กำหนดสถานะไปข้างหน้าด้วยจำนวนขั้นตอนที่กำหนด ซึ่งโดยปกติจะเป็นกำลังของสองที่ช่วยให้เธรดการทำงานหลายเธรดเริ่มต้นที่สถานะเริ่มต้นที่แตกต่างกันได้
สำหรับเอาต์พุต 32 บิต xoshiro128** และ xoshiro128+ จะเทียบเท่ากับ xoshiro256** และ xoshiro256+ ทุกประการ โดยใช้uint32_tแทนuint64_tและมีค่าคงที่การเลื่อน/หมุนที่แตกต่างกัน
เมื่อไม่นานมานี้ ตัวสร้าง xoshiro++ได้ถูกสร้างขึ้นเพื่อเป็นทางเลือกแทน ตัว สร้าง xoshiro**โดยใช้ในคอม ไพเลอร์ Fortran บางเวอร์ชัน เช่น GNU Fortran และในJavaและJulia [ 18 ]
xoshiro256++
xoshiro256++ คือตัวสร้างเลขสุ่ม 64 บิตอเนกประสงค์ของตระกูลนี้
// ดัดแปลงจากโค้ดที่อยู่ในเว็บไซต์ของ Sebastiano Vigna#include <stdint.h>uint64_t rol64 ( uint64_t x , int k ) { return ( x << k ) | ( x >> ( 64 - k )); }typedef struct { uint64_t s [ 4 ]; } Xoshiro256ppState ;uint64_t xoshiro256pp ( Xoshiro256ppState * state ) { uint64_t * s = state -> s ; const uint64_t result = rol64 ( s [ 0 ] + s [ 3 ], 23 ) + s [ 0 ]; const uint64_t t = s [ 1 ] << 17 ;s [ 2 ] ^= s [ 0 ]; s [ 3 ] ^= s [ 1 ]; s [ 1 ] ^= s [ 2 ]; s [ 0 ] ^= s [ 3 ];s [ 2 ] ^= t ; s [ 3 ] = rol64 ( s [ 3 ], 45 );ส่งคืนผลลัพธ์; }xoshiro256**
xoshiro256** ใช้การคูณแทนการบวกในฟังก์ชันเอาต์พุต อย่างไรก็ตาม ควรสังเกตว่าฟังก์ชันเอาต์พุตสามารถผกผันได้ ทำให้สามารถเปิดเผยสถานะพื้นฐานได้อย่างง่ายดาย[ 19 ]มันถูกใช้ในคอมไพเลอร์GNU Fortran , Lua (ตั้งแต่ Lua 5.4) และ เฟรมเวิร์ ก .NET (ตั้งแต่ .NET 6.0) [ 18 ]
// ดัดแปลงจากโค้ดที่อยู่ในเว็บไซต์ของ Sebastiano Vigna#include <stdint.h>uint64_t rol64 ( uint64_t x , int k ) { return ( x << k ) | ( x >> ( 64 - k )); }typedef struct { uint64_t s [ 4 ]; } Xoshiro256ssState ;uint64_t xoshiro256ss ( Xoshiro256ssState * state ) { uint64_t * s = state -> s ; const uint64_t result = rol64 ( s [ 1 ] * 5 , 7 ) * 9 ; const uint64_t t = s [ 1 ] << 17 ;s [ 2 ] ^= s [ 0 ]; s [ 3 ] ^= s [ 1 ]; s [ 1 ] ^= s [ 2 ]; s [ 0 ] ^= s [ 3 ];s [ 2 ] ^= t ; s [ 3 ] = rol64 ( s [ 3 ], 45 );ส่งคืนผลลัพธ์; }xoshiro256+
xoshiro256+ เร็วกว่า xoshiro256** ประมาณ 15% แต่บิตสามบิตล่างสุดมีความซับซ้อนเชิงเส้นต่ำ ดังนั้นจึงควรใช้เฉพาะกับผลลัพธ์จุดลอยตัวโดยการดึงบิต 53 บิตบนออกมาเท่านั้น
#include <stdint.h>uint64_t rol64 ( uint64_t x , int k ) { return ( x << k ) | ( x >> ( 64 - k )); }typedef struct { uint64_t s [ 4 ]; } Xoshiro256pState ;uint64_t xoshiro256p ( Xoshiro256pState * state ) { uint64_t * s = state -> s ; const uint64_t result = s [ 0 ] + s [ 3 ]; const uint64_t t = s [ 1 ] << 17 ;s [ 2 ] ^= s [ 0 ]; s [ 3 ] ^= s [ 1 ]; s [ 1 ] ^= s [ 2 ]; s [ 0 ] ^= s [ 3 ];s [ 2 ] ^= t ; s [ 3 ] = rol64 ( s [ 3 ], 45 );ส่งคืนผลลัพธ์; }โซโรชิโร่
หากพื้นที่หน่วยความจำมีจำกัด xoroshiro128** และxoroshiro128+จะเทียบเท่ากับ xoshiro256** และ xoshiro256+ เนื่องจากมีหน่วยความจำสถานะขนาดเล็กกว่า จึงไม่ค่อยเหมาะสำหรับ โปรแกรม แบบขนานขนาดใหญ่ นอกจากนี้ xoroshiro128+ ยังแสดงให้เห็นถึงการพึ่งพาเล็กน้อยในจำนวนประชากรซึ่งจะทำให้เกิดความล้มเหลวหลังจากนั้นผลลัพธ์ขนาด 5 เทราไบต์ผู้เขียนไม่เชื่อว่าสิ่งนี้จะสามารถตรวจพบได้ในโปรแกรมที่ใช้งานจริง แทนที่จะสืบทอดประเพณีของมาร์ซาเกลียต่อไปxorshiftในฐานะที่เป็นการดำเนินการพื้นฐานxoroshiro128+ใช้การแปลงเชิงเส้นแบบเลื่อน/หมุนที่ออกแบบโดยSebastiano Vignaร่วมกับ David Blackman ผลลัพธ์ที่ได้คือความเร็วและคุณภาพทางสถิติที่ดีขึ้นอย่างมาก[ 20 ]
xoroshiro64** และ xoroshiro64* เทียบเท่ากับ xoroshiro128** และ xoroshiro128+ แต่แตกต่างจากตัวสร้างค่า xoshiro ตรงที่ไม่ได้เป็นการแปลงค่าจากรุ่นที่มีความแม่นยำสูงกว่าโดยตรง
คุณภาพทางสถิติ
บิตต่ำสุดของเอาต์พุตที่สร้างขึ้นโดยxoroshiro128+มีคุณภาพต่ำ ผู้เขียนxoroshiro128+ยอมรับว่าไม่ผ่านการทดสอบทางสถิติทั้งหมด โดยระบุว่า
นี่คือ xoroshiro128+ 1.0 ซึ่งเป็นตัวสร้างเลขทศนิยมขนาดเล็กที่ดีที่สุดและเร็วที่สุดของเรา เราแนะนำให้ใช้บิตบนสำหรับการสร้างเลขทศนิยม เนื่องจากเร็วกว่า xoroshiro128** เล็กน้อย มันผ่านการทดสอบทั้งหมดที่เราทราบ ยกเว้นสี่บิตล่าง ซึ่งอาจไม่ผ่านการทดสอบความเป็นเชิงเส้น (และเฉพาะบิตเหล่านั้น) ดังนั้นหากความซับซ้อนเชิงเส้นต่ำไม่ถือเป็นปัญหา (ซึ่งมักจะเป็นเช่นนั้น) ก็สามารถใช้สร้างเอาต์พุต 64 บิตได้เช่นกัน ยิ่งไปกว่านั้น ตัวสร้างนี้มีการพึ่งพาค่า Hamming weight เพียงเล็กน้อย ทำให้การทดสอบของเรา ( http://prng.di.unimi.it/hwd.php ) ล้มเหลวหลังจากเอาต์พุต 5 TB เราเชื่อว่าความคลาดเคลื่อนเล็กน้อยนี้จะไม่ส่งผลกระทบต่อแอปพลิเคชันใดๆ หากคุณกังวล ให้ใช้ xoroshiro128** หรือ xoshiro256+
เราแนะนำให้ใช้การทดสอบเครื่องหมายเพื่อดึงค่าบูลีนแบบสุ่ม และใช้การเลื่อนบิตไปทางขวาเพื่อดึงชุดย่อยของบิต
ต้องมีการกำหนดค่าเริ่มต้นให้กับสถานะ เพื่อไม่ให้ค่าทุกค่าเป็นศูนย์ หากคุณมีค่าเริ่มต้นแบบ 64 บิต เราขอแนะนำให้ใช้ค่าเริ่มต้นนี้กับตัวสร้าง splitmix64 และใช้ผลลัพธ์ของมันเพื่อเติมค่า s
หมายเหตุ: พารามิเตอร์ (a=24, b=16, c=37) ของเวอร์ชันนี้ให้ค่าที่แตกต่างกันเล็กน้อย
ผลลัพธ์ที่ดีกว่าในการทดสอบของเราเมื่อเทียบกับเวอร์ชันปี 2016 (a=55, b=14, c=36) [ 21 ]
ข้อกล่าวอ้างเกี่ยวกับการสอบไม่ผ่านเหล่านี้สามารถตรวจสอบได้โดยการใช้ PractRand กับข้อมูลป้อนเข้า ซึ่งจะได้ผลลัพธ์ดังที่แสดงด้านล่าง:
การทดสอบ RNG โดยใช้ PractRand เวอร์ชัน 0.93 RNG = RNG_stdin64, seed = 0xfac83126 ชุดทดสอบ = ปกติ, การพับ = มาตรฐาน (64 บิต) rng=RNG_stdin64, seed=0xfac83126 ขนาดไฟล์ = 128 เมกะไบต์ (2^27 ไบต์), เวลา = 2.1 วินาที ชื่อการทดสอบ ข้อมูลดิบ ข้อมูลประมวลผล การประเมินผล [Low1/64]BRank(12):256(2) R= +3748 p~= 3e-1129 ล้มเหลว !!!!!!!! [Low1/64]BRank(12):384(1) R= +5405 p~= 3e-1628 FAIL !!!!!!!! ...และผลการทดสอบ 146 รายการโดยไม่มีความผิดปกติ
ผู้เขียนกล่าวต่อไปว่า:
เราแนะนำให้ใช้การทดสอบเครื่องหมายเพื่อแยกค่าบูลีนแบบสุ่ม[ 21 ]
ดังนั้น โปรแกรมเมอร์จึงควรเลือกบิตที่มีค่าสูงสุด (เช่น การทำให้ ได้ หัว/ก้อยโดยการเขียนrandom_number < 0แทนที่จะเป็น random_number & 1) การทดสอบแบบเดียวกันนี้ล้มเหลวในบางกรณีของMersenne TwisterและWELL
ปัญหาทางสถิติขยายออกไปไกลเกินกว่าบิตล่างไม่กี่บิต เนื่องจากล้มเหลวในการทดสอบ PractRand แม้ว่าจะถูกตัดทอน[ 22 ]และล้มเหลวในการทดสอบหลายรายการใน BigCrush แม้ว่าจะกลับบิตแล้วก็ตาม[ 23 ]
การเริ่มต้น
ในเอกสาร xoshiro แนะนำให้เริ่มต้นสถานะของตัวสร้างโดยใช้ตัวสร้างที่แตกต่างอย่างสิ้นเชิงจากตัวสร้างที่เริ่มต้นแล้ว รวมถึงตัวสร้างที่จะไม่ให้สถานะ "ศูนย์ทั้งหมด" ด้วย สำหรับตัวสร้างรีจิสเตอร์แบบเลื่อน สถานะนี้เป็นไปไม่ได้ที่จะหลุดพ้น[ 17 ] [ 24 ]ผู้เขียนแนะนำเป็นพิเศษให้ใช้ตัวสร้าง SplitMix64 จาก seed 64 บิต เวอร์ชันของตัวสร้าง SplitMix64 ถูกใช้ด้านล่าง
#include <stdint.h>typedef struct { uint64_t s ; } Mix64State ;uint64_t mix64 ( Mix64State * state ) { uint64_t result = ( state -> s += 0x9E3779B97F4A7C15 ); result = ( result ^ ( result >> 30 )) * 0xBF58476D1CE4E5B9 ; result = ( result ^ ( result >> 27 )) * 0x94D049BB133111EB ; return result ^ ( result >> 31 ); }typedef struct { uint32_t x [ 4 ]; } XorShift128State ;// สามารถทำเช่นเดียวกันสำหรับตัวสร้างอื่นๆ ได้void xorshift128_init ( XorShift128State * state , uint64_t seed ) { Mix64State smstate = { seed };uint64_t tmp = mix64 ( & smstate ); state -> x [ 0 ] = ( uint32_t ) tmp ; state -> x [ 1 ] = ( uint32_t )( tmp >> 32 );tmp = mix64 ( & smstate ); state -> x [ 2 ] = ( uint32_t ) tmp ; state -> x [ 3 ] = ( uint32_t )( tmp >> 32 ); }ดูเพิ่มเติม
หมายเหตุ
- ^ในภาษา C และภาษาอื่นๆ ส่วนใหญ่ที่ใช้ C เป็นพื้นฐาน
^แทนการดำเนินการXORระดับบิตและ<<แทนการเลื่อนบิตระดับบิต>>
อ่านเพิ่มเติม
- Brent, Richard P. (กรกฎาคม 2549). "เครื่องกำเนิดเลขสุ่มระยะยาวบางแบบโดยใช้การเลื่อนและการ XOR" . วารสาร ANZIAM . 48 : C188– C202. แสดงรายการเครื่องกำเนิดสัญญาณขนาดต่างๆ ที่มีสี่กะ (สองกะต่อคำป้อนกลับหนึ่งคำ)
ลิงก์ภายนอก
- Vigna, Sebastiano (2018). "เครื่องกำเนิด xoshiro / xoroshiro และการทดสอบ PRNG" . เก็บถาวรจากต้นฉบับเมื่อ 2018-05-04 . เรียกดูเมื่อ2018-05-04 .
สรุปเนื้อหา
ข้อมูลสำคัญจากบทความ
ข้อมูลสำคัญเกี่ยวกับ ซอร์ชิฟต์
เครื่องกำเนิดเลขสุ่ม Xorshift หรือที่เรียกว่า เครื่องกำเนิดเลขสุ่มแบบรีจิสเตอร์เลื่อน เป็นกลุ่มของ เครื่องกำเนิดเลขสุ่มเทียม ที่คิดค้นโดย George Marsaglia [ 1 ] เป็น กลุ่มย่อยของ...
ตัวอย่างการใช้งาน
เวอร์ชันC [ a ] ของอัลกอริธึม xorshift สามแบบ [ 1 ] : 4,5 มีให้ที่นี่ อัลกอริธึมแรกมีคำสถานะ 32 บิตหนึ่งคำ และคาบ 2 32 −1 อัลกอริธึมที่สองมีคำสถานะ 64 บิตหนึ่งคำ และคาบ 2 64 −1 อัลกอริธึมสุดท้ายมีคำสถานะ 32 บิตสี่คำ และคาบ 2 128 −1 อัลกอริธึม 128 บิตผ่าน...
การเปลี่ยนแปลงที่ไม่เป็นเชิงเส้น
ตัวสร้าง xorshift ทั้งหมดล้มเหลวในการทดสอบบางอย่างใน ชุดทดสอบ BigCrush นี่เป็นความจริงสำหรับตัวสร้างทั้งหมดที่ใช้ความสัมพันธ์เชิงเส้น เช่น Mersenne Twister หรือ WELL อย่างไรก็ตาม การสุ่มลำดับเอาต์พุตของตัวสร้างเหล่านี้เพื่อปรับปรุงคุณภาพนั้นทำได้ง่าย
xorwow
มาร์ซาเกลียเสนอให้สุ่มผลลัพธ์โดยการรวมเข้ากับตัวนับบวกแบบง่ายๆ โมดูล 2 32 (ซึ่งเขาเรียกว่า " ลำดับไวล์ " ตาม ทฤษฎีบทการกระจายเท่าๆ กันของไวล์ ) วิธีนี้จะเพิ่มคาบขึ้นอีกเท่าตัว เป็น 2 192 −2 32 :