একটি পিসিজি প্রয়োগ করুন


31

একটি আরও ভাল র্যান্ডম নম্বর জেনারেটর পিসিজি বাস্তবায়নের চেয়ে পিসি.এস.ইসের জন্য আর কী সমস্যা ? এই নতুন কাগজটি দ্রুত, কঠোর-পূর্বাভাস, ছোট, পরিসংখ্যানগতভাবে অনুকূল এলোমেলো সংখ্যা জেনারেটর উপস্থাপন করার দাবি করেছে।

এর সর্বনিম্ন সি বাস্তবায়ন প্রায় নয়টি লাইন:

// *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 )

প্রশ্নটি: আপনি আরও ভাল করতে পারেন?

বিধি

একটি প্রোগ্রাম লিখুন বা একটি ফাংশন সংজ্ঞায়িত করুন যা 32-বিট স্বাক্ষরযুক্ত পূর্ণসংখ্যায় পিসিজি প্রয়োগ করে। এটি মোটামুটি বিস্তৃত: আপনি একটি অসীম অনুক্রম প্রিন্ট করতে পারেন, কোনও pcg32_random_rফাংশন এবং সংশ্লিষ্ট কাঠামো সংজ্ঞায়িত করতে পারেন etc.

আপনাকে অবশ্যই নীচের সি ফাংশনের সমানভাবে আপনার এলোমেলো নম্বর জেনারেটর বীজ করতে সক্ষম হতে হবে:

// 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:)

প্রথমে বীজ ছাড়াই এলোমেলো নম্বর জেনারেটরকে কল করা অপরিজ্ঞাত আচরণ।

আপনার জমাটি সহজেই পরীক্ষা করতে, যাচাই করে নিন, যখন বীজযুক্ত হয় 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

তাহলে কি আপনার টাস্কের ভাষা সম্পর্কিত?
কিনার্ড

পছন্দ করেছেন সি কেবল একটি উদাহরণ।
wchargin

একটি ছোট জাভাস্ক্রিপ্ট বাস্তবায়ন দেখার জন্য অপেক্ষা করতে পারবেন না ..
ড্যানিয়েল বৈয়ার্ড

উত্তর:


17

সিজেম, 109 107 104 98 91 বাইট

এটি ASCII ব্যাপ্তির বাইরে কিছু অক্ষর ব্যবহার করে তবে সেগুলি সমস্তই বর্ধিত ASCII এর মধ্যে থাকে তাই আমি প্রতিটি অক্ষরকে বাইট হিসাবে গণনা করছি (ইউটিএফ -8 হিসাবে গণনা করার পরিবর্তে)।

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

এটি মূলত সি কোডের একটি সঠিক পোর্ট।

বীজ ফাংশন একটি সঞ্চিত একটি ব্লক Sএবং এলোমেলো ক্রিয়াকলাপ একটি সঞ্চিত একটি ব্লক RSপ্রত্যাশা করা হয় initstateএবং initseqস্ট্যাক এবং PRNG বীজ।Rস্ট্যাকের কোনও কিছুর প্রত্যাশা করে না এবং এটিতে পরবর্তী র্যান্ডম সংখ্যাটি ছেড়ে দেয়।

যেহেতু কল Rকরার আগে কল Sকরা সংজ্ঞায়িত আচরণ, তাই আমি প্রকৃতপক্ষে এর R মধ্যে সংজ্ঞা দিচ্ছি S, সুতরাং আপনি বীজ ব্লকটি ব্যবহার না করা অবধি Rকেবল একটি খালি স্ট্রিং এবং অকেজো।

stateপরিবর্তনশীল মধ্যে সংরক্ষিত হয় Aএবং incমধ্যে সংরক্ষিত হয় B

ব্যাখ্যা:

"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).";

এবং এখানে ওপি পরীক্ষার জোয়ার সমতুল্য:

42 52 S
{RN}16*

যা ঠিক একই সংখ্যা মুদ্রণ করে।

এটি এখানে পরীক্ষা করুন। স্ট্যাক এক্সচেঞ্জ দুটি মুদ্রিত অক্ষরকে আলাদা করে ফেলেছে, সুতরাং আপনি উপরের স্নিপেটটি অনুলিপি করলে এটি কার্যকর হবে না। পরিবর্তে অক্ষর কাউন্টার থেকে কোড অনুলিপি করুন ।


নিশ্চিত: বিজ্ঞাপন হিসাবে কাজ করে।
wchargin

11

সি, 195

আমি বুঝতে পারি যে কারও পক্ষে আরও কমপ্যাক্ট সি বাস্তবায়ন পোস্ট করা উচিত, এমনকি যদি এটি জয়ের কোনও সম্ভাবনা না থাকে। তৃতীয় লাইনে দুটি ফাংশন রয়েছে: 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-বিট মেশিনে আপনাকে পরিবর্তন #define L longকরতে আরও 5 বাইট যুক্ত করতে হবে#define L long long ( এই আদর্শ ডেমোটির মতো )।


নিশ্চিত করা হয়েছে: আমার জন্য বিজ্ঞাপন হিসাবে কাজ করে (জিসিসি ৪.৮.২ পুদিনা 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

রাজ্য ৪২ এবং সিকোয়েন্স ৫২ সহ বীজ সূচনা করুন the আপনি 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
             .
             .
             .

আমি সত্যিই অবাক হয়েছিলাম যে আমার নীচে বর্ণিত জুলিয়া সংস্করণটি সি (958 বাইট) এর নমুনা সমাধানের চেয়ে অনেক ছোট (543 বাইট)।

অবহেলিত সংস্করণ, 543 বাইট

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

আমি যেহেতু এক অভিনব প্রোগ্রামার, এটি কাজ করতে আমার প্রায় একদিন লেগেছিল। সর্বশেষ আমি প্রায় 18 বছর আগে সি (আসলে সি ++) তে কিছু কোডিংয়ের চেষ্টা করেছি, তবে অবশেষে অনেকগুলি গুগল-ফু আমাকে একটি কাজের জুলিয়া সংস্করণ তৈরি করতে সহায়তা করেছিল। আমার বলতে হবে, কোডগল্ফের কয়েক দিনের মধ্যে আমি অনেক কিছু শিখেছি। এখন আমি পিট সংস্করণে কাজ শুরু করতে পারি। এটি পুরোপুরি কাজ হতে চলেছে, তবে আমি সত্যিই পিটের জন্য একটি (ভাল) এলোমেলো নম্বর জেনারেটর চাই;)

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.