ใช้ PCG


31

สิ่งที่เป็นปัญหาที่ดีกว่าสำหรับ PCG.SE กว่าที่จะใช้PCG, ที่ดีกว่าการสร้างตัวเลขสุ่ม ? กระดาษใหม่นี้อ้างว่าจะนำเสนอตัวสร้างตัวเลขสุ่มแบบสุ่มที่รวดเร็วและคาดเดายาก

การใช้ C น้อยที่สุดนั้นมีอยู่แค่เก้าบรรทัด

// *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org
// Licensed under Apache License 2.0 (NO WARRANTY, etc. see website)

typedef struct { uint64_t state;  uint64_t inc; } pcg32_random_t;

uint32_t pcg32_random_r(pcg32_random_t* rng)
{
    uint64_t oldstate = rng->state;
    // Advance internal state
    rng->state = oldstate * 6364136223846793005ULL + (rng->inc|1);
    // Calculate output function (XSH RR), uses old state for max ILP
    uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
    uint32_t rot = oldstate >> 59u;
    return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
}

(จาก: http://www.pcg-random.org/download.html )

คำถามคือคุณสามารถทำได้ดีกว่า

กฎระเบียบ

เขียนโปรแกรมหรือกำหนดฟังก์ชั่นที่ใช้ PCG กับเลขจำนวนเต็ม 32 บิตที่ไม่ได้ลงชื่อ สิ่งนี้ค่อนข้างกว้าง: คุณสามารถพิมพ์ลำดับอนันต์กำหนดpcg32_random_rฟังก์ชันและโครงสร้างที่สอดคล้องกัน ฯลฯ

คุณต้องสามารถสร้างตัวสร้างตัวเลขสุ่มของคุณเท่ากับฟังก์ชัน C ต่อไปนี้:

// pcg32_srandom(initstate, initseq)
// pcg32_srandom_r(rng, initstate, initseq):
//     Seed the rng.  Specified in two parts, state initializer and a
//     sequence selection constant (a.k.a. stream id)

void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate, uint64_t initseq)
{
    rng->state = 0U;
    rng->inc = (initseq << 1u) | 1u;
    pcg32_random_r(rng);
    rng->state += initstate;
    pcg32_random_r(rng);
}

(จากpcg_basic.c:37:)

การเรียกตัวสร้างตัวเลขสุ่มโดยไม่ต้องทำการเพาะมันเป็นพฤติกรรมที่ไม่ได้กำหนด

หากต้องการตรวจสอบการส่งของคุณได้อย่างง่ายดายตรวจสอบว่าเมื่อ seeded ด้วยinitstate = 42และinitseq = 52ผลลัพธ์คือ2380307335:

$ tail -n 8 pcg.c 
int main()
{
    pcg32_random_t pcg;
    pcg32_srandom_r(&pcg, 42u, 52u);

    printf("%u\n", pcg32_random_r(&pcg));
    return 0;
}
$ gcc pcg.c
$ ./a.out 
2380307335

เกณฑ์การให้คะแนน

คะแนนมาตรฐาน วัดเป็นไบต์ ต่ำสุดดีที่สุด ในกรณีที่เสมอกันการส่งก่อนหน้านี้จะชนะ ช่องโหว่มาตรฐานใช้

ตัวอย่างสารละลาย

คอมไพล์ภายใต้gcc -W -Wallหมดจด (เวอร์ชั่น 4.8.2)

เปรียบเทียบการส่งของคุณกับสิ่งนี้เพื่อให้แน่ใจว่าคุณได้รับลำดับเดียวกัน

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>

typedef struct { uint64_t state;  uint64_t inc; } pcg32_random_t;

uint32_t pcg32_random_r(pcg32_random_t* rng)
{
    uint64_t oldstate = rng->state;
    // Advance internal state
    rng->state = oldstate * 6364136223846793005ULL + (rng->inc|1);
    // Calculate output function (XSH RR), uses old state for max ILP
    uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
    uint32_t rot = oldstate >> 59u;
    return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
}

void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate, uint64_t initseq)
{
    rng->state = 0U;
    rng->inc = (initseq << 1u) | 1u;
    pcg32_random_r(rng);
    rng->state += initstate;
    pcg32_random_r(rng);
}

int main()
{
    size_t i;
    pcg32_random_t pcg;
    pcg32_srandom_r(&pcg, 42u, 52u);

    for (i = 0; i < 16; i++)
    {
        printf("%u\n", pcg32_random_r(&pcg));
    }
    return 0;
}

ลำดับ:

2380307335
948027835
187788573
3952545547
2315139320
3279422313
2401519167
2248674523
3148099331
3383824018
2720691756
2668542805
2457340157
3945009091
1614694131
4292140870

ดังนั้นภาษางานของคุณเกี่ยวข้องหรือไม่
Knerd

@Knerd Nope C เป็นเพียงตัวอย่าง
wchargin

แทบรอไม่ไหวที่จะเห็นการใช้งานจาวาสคริปต์เล็ก ๆ น้อย ๆ
Daniel Baird

คำตอบ:


17

CJam, 109 107 104 98 91 ไบต์

นี่ใช้อักขระบางตัวที่อยู่นอกช่วง ASCII แต่ทั้งหมดอยู่ในช่วงขยาย ASCII ดังนั้นฉันจึงนับอักขระแต่ละตัวเป็นไบต์ (แทนที่จะนับเป็น UTF-8)

{[2*0:A)|:B{AA"XQô-L-"256b*B1|+GG#%:A;__Im>^27m>_@59m>_@\m>@@~)31&m<|4G#%}:R~@A+:AR];}:S;

นี่เป็นพอร์ตที่แน่นอนของรหัส C

ฟังก์ชั่นเมล็ดเป็นบล็อกที่เก็บไว้ในและฟังก์ชั่นแบบสุ่มบล็อกเก็บไว้ในS คาดหวังและในกองซ้อนและเมล็ด PRNG ไม่ได้คาดหวังอะไรเลยในสแต็กและปล่อยให้มีการสุ่มหมายเลขถัดไปRSinitstateinitseqR

เนื่องจากการโทรRก่อนการโทรSนั้นเป็นพฤติกรรมที่ไม่ได้กำหนดฉันจึงกำหนดไว้R ภายใน Sดังนั้นจริงๆแล้วคุณจะใช้ seed block Rเป็นเพียงสตริงว่างเปล่าและไร้ประโยชน์

stateจะถูกเก็บไว้ในตัวแปรAและถูกเก็บไว้ในincB

คำอธิบาย:

"The seed block S:";
[       "Remember start of an array. This is to clear the stack at the end.";
2*      "Multiply initseq by two, which is like a left-shift by one bit.";
0:A     "Store a 0 in A.";
)|:B    "Increment to get 1, bitwise or, store in B.";
{...}:R "Store this block in R. This is the random function.";
~       "Evaluate the block.";
@A+:A   "Pull up initstate, add to A and store in A.";
R       "Evaluate R again.";
];      "Wrap everything since [ in an array and discard it.";

"The random block R:";
AA            "Push two A's, one of them to remember oldstate.";
"XQô-L-"256b* "Push that string and interpret the character codes as base-256 digits.
               Then multiply A by this.";
B1|+          "Take bitwise or of 1 and inc, add to previous result.";
GG#%:A;       "Take modulo 16^16 (== 2^64). Store in A. Pop.";
__            "Make two copies of old state.";
Im>^          "Right-shift by 18, bitwise xor.";
27m>_         "Right-shift by 27. Duplicate.";
@59m>         "Pull up remaining oldstate. Right-shift by 59.";
_@\m>         "Duplicate, pull up xorshifted, swap order, right-shift.";
@@            "Pull up other pair of xorshifted and rot.";
~)            "Bitwise negation, increment. This is is like multiplying by -1.";
31&           "Bitwise and with 31. This is the reason I can actually use a negative value
               in the previous step.";
m<|           "Left-shift, bitwise or.";
4G#%          "Take modulo 4^16 (== 2^32).";

และนี่คือสิ่งที่เทียบเท่ากับชุดทดสอบใน OP:

42 52 S
{RN}16*

ซึ่งพิมพ์ตัวเลขเดียวกันที่แน่นอน

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


ยืนยัน: ทำงานตามที่โฆษณาไว้
wchargin

11

C, 195

ฉันคิดว่าใครบางคนควรโพสต์การใช้งาน C ที่มีขนาดกะทัดรัดยิ่งขึ้นแม้ว่าจะไม่มีโอกาสชนะ บรรทัดที่สามมีสองฟังก์ชั่น: r()(เทียบเท่าpcg32_random_r()) และs()(เทียบเท่าpcg32_srandom_r()) บรรทัดสุดท้ายคือmain()ฟังก์ชันซึ่งไม่รวมอยู่ในการนับจำนวนอักขระ

#define U unsigned
#define L long
U r(U L*g){U L o=*g;*g=o*0x5851F42D4C957F2D+(g[1]|1);U x=(o>>18^o)>>27;U t=o>>59;return x>>t|x<<(-t&31);}s(U L*g,U L i,U L q){*g++=0;*g--=q+q+1;r(g);*g+=i;r(g);}
main(){U i=16;U L g[2];s(g,42,52);for(;i;i--)printf("%u\n",r(g));}

แม้ว่าคอมไพเลอร์จะบ่น แต่ก็ควรใช้งานได้กับเครื่อง 64 บิต ในเครื่อง 32 บิตคุณจะต้องเพิ่มอีก 5 ไบต์เพื่อเปลี่ยน#define L longเป็น#define L long long( เช่นในตัวอย่างการสาธิตแบบนี้ )


ได้รับการยืนยัน: ทำงานตามที่โฆษณาไว้สำหรับฉัน (GCC 4.8.2 ใน Mint 64- บิต)
wchargin

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

@WChargin อ่าางั้น ฉันนับ 195 ไบต์
ossifrage คลื่นไส้

5

จูเลีย 218 199 191 ไบต์

การเปลี่ยนชื่อชนิดข้อมูลรวมถึงลูกเล่นเล็ก ๆ น้อย ๆ ช่วยให้ฉันลดความยาวลงได้อีก 19 ไบต์ ส่วนใหญ่โดยละเว้นการกำหนดประเภท:: Int64สองรายการ

type R{T} s::T;c::T end
R(s,c)=new(s,c);u=uint32
a(t,q)=(r.s=0x0;r.c=2q|1;b(r);r.s+=t;b(r))
b(r)=(o=uint64(r.s);r.s=o*0x5851f42d4c957f2d+r.c;x=u((o>>>18$o)>>>27);p=u(o>>>59);x>>>p|(x<<-p&31))

คำอธิบายของชื่อ (ตามชื่อในรุ่นที่ไม่ได้บรรจุด้านล่าง):

# R     : function Rng
# a     : function pcg32srandomr
# b     : function pcg32randomr
# type R: type Rng
# r.s   : rng.state
# r.c   : rng.inc
# o     : oldstate
# x     : xorshifted
# t     : initstate
# q     : initseq
# p     : rot
# r     : rng
# u     : uint32

เริ่มต้นเมล็ดด้วยสถานะ 42 และลำดับ 52 เนื่องจากโปรแกรมขนาดเล็กคุณต้องระบุชนิดข้อมูลอย่างชัดเจนในระหว่างการเริ่มต้นตอนนี้ (บันทึกรหัส 14 ไบต์หรือมากกว่านั้น) คุณสามารถละเว้นการกำหนดประเภทอย่างชัดเจนในระบบ 64 บิต:

r=R(42,52) #on 64-bit systems or r=R(42::Int64,52::Int64) on 32 bit systems
a(r.s,r.c)

สร้างตัวเลขสุ่มชุดแรก:

b(r)

ผล:

julia> include("pcg32golfed.jl")
Checking sequence...
result round 1: 2380307335
target round 1: 2380307335   pass
result round 2: 948027835
target round 2: 948027835   pass
result round 3: 187788573
target round 3: 187788573   pass
             .
             .
             .

ฉันประหลาดใจจริง ๆ แม้แต่รุ่นจูเลียที่ยังไม่ถูกตรึงของฉันด้านล่างก็เล็กกว่า (543 ไบต์) มากกว่าโซลูชันตัวอย่างใน C (958 ไบต์)

Ungolfed version 543 bytes

type Rng{T}
    state::T
    inc::T
end

function Rng(state,inc)
    new(state,inc)
end

function pcg32srandomr(initstate::Int64,initseq::Int64)
    rng.state =uint32(0)
    rng.inc   =(initseq<<1|1)
    pcg32randomr(rng)
    rng.state+=initstate
    pcg32randomr(rng)
end

function pcg32randomr(rng)
    oldstate  =uint64(rng.state)
    rng.state =oldstate*uint64(6364136223846793005)+rng.inc
    xorshifted=uint32(((oldstate>>>18)$oldstate)>>>27)
    rot       =uint32(oldstate>>>59)
    (xorshifted>>>rot) | (xorshifted<<((-rot)&31))
end

คุณเริ่มต้นเมล็ด (สถานะเริ่มต้น = 42, เริ่มต้นลำดับ = 52) ด้วย:

rng=Rng(42,52)
pcg32srandomr(rng.state,rng.inc)

จากนั้นคุณสามารถสร้างตัวเลขสุ่มด้วย:

pcg32randomr(rng)

นี่คือผลลัพธ์ของสคริปต์ทดสอบ:

julia> include("pcg32test.jl")
Test PCG
Initialize seed...
Checking sequence...
result round 1: 2380307335
target round 1: 2380307335   pass
result round 2: 948027835
target round 2: 948027835   pass
result round 3: 187788573
target round 3: 187788573   pass
             .
             .
             .
result round 14: 3945009091
target round 14: 3945009091   pass
result round 15: 1614694131
target round 15: 1614694131   pass
result round 16: 4292140870
target round 16: 4292140870   pass

ในฐานะที่ฉันเป็นโปรแกรมเมอร์สุดซึ้งฉันต้องใช้เวลาเกือบหนึ่งวันกว่าจะได้ทำงาน ครั้งสุดท้ายที่ฉันลองเขียนโค้ดใน C (จริง ๆ C ++) เกือบ 18 ปีที่แล้ว แต่ google-fu ในที่สุดก็ช่วยให้ฉันสร้าง Julia รุ่นที่ใช้งานได้ ฉันต้องบอกว่าฉันได้เรียนรู้มากมายระหว่าง codegolf เพียงไม่กี่วัน ตอนนี้ฉันสามารถเริ่มทำงานกับรุ่น Piet ได้แล้ว นั่นเป็น gonna เป็นจำนวนมากทั้งจากการทำงาน แต่ฉันจริงๆต้องการ (ดี) เครื่องกำเนิดไฟฟ้าจำนวนสุ่มสำหรับ Piet;)

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