কিভাবে সংক্ষিপ্তভাবে, বহনযোগ্যভাবে এবং পুরোপুরি mt19937 PRNG বীজ করা যায়?


112

আমি অনেক উত্তর দেখতে পেয়েছি বলে মনে হচ্ছে যাতে কেউ <random>সাধারণত এ জাতীয় কোড সহ এলোমেলো সংখ্যা তৈরি করতে ব্যবহার করার পরামর্শ দেয় :

std::random_device rd;  
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 5);
dis(gen);

সাধারণত এটি কিছু ধরণের "অপরিষ্কার ঘৃণা" প্রতিস্থাপন করে যেমন:

srand(time(NULL));
rand()%6;

আমরা কম এন্ট্রপি প্রদান করে, পূর্বাভাসযোগ্য, এবং শেষ ফলাফলটি অ-অভিন্ন বলে বিতর্ক করে আমরা পুরানো পথে সমালোচনা করতে পারি ।time(NULL)time(NULL)

তবে এগুলি সমস্ত নতুন উপায়ে সত্য: এটির মধ্যে কেবল একটি ঝকঝকে ব্যহ্যাবরণ রয়েছে।

  • rd()একক প্রদান unsigned int। এটিতে কমপক্ষে 16 টি বিট রয়েছে এবং সম্ভবত 32 টি রয়েছে M এটি এমটি এর 19937 বিট রাজ্যের বীজ বপন করার পক্ষে যথেষ্ট নয়।

  • ব্যবহার std::mt19937 gen(rd());gen()(32 বিটের সাথে seeding এবং প্রথম আউটপুট দিকে তাকিয়ে) একটি ভাল আউটপুট বিতরণ দেয় না। 7 এবং 13 কখনই প্রথম আউটপুট হতে পারে না। দুটি বীজ 0. উত্পাদন করে 12 টি বীজ 1226181350 উত্পাদন করে ( লিঙ্ক )

  • std::random_deviceস্থির বীজ সহ সাধারণ পিআরএনজি হিসাবে কার্যকর হতে পারে এবং কখনও কখনও প্রয়োগ করা হয়। সুতরাং এটি প্রতিটি রান একই ক্রম উত্পাদন করতে পারে। ( লিংক ) এই চেয়ে আরও খারাপ time(NULL)

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

এর আলোকে, আমার প্রশ্নটি হল যে কেউ সি ++ তে কীভাবে সংলগ্নভাবে, বহনযোগ্যভাবে এবং পুরোপুরিভাবে mt19937 PRNG বীজ করতে পারে?

উপরের বিষয়গুলি দেওয়া, একটি ভাল উত্তর:

  • Mt19937 / mt19937_64 সম্পূর্ণরূপে বীজ করতে হবে।
  • কেবলমাত্র std::random_deviceবা time(NULL)এন্ট্রপির উত্স হিসাবে নির্ভর করতে পারে না ।
  • বুস্ট বা অন্যান্য লিবারীর উপর নির্ভর করা উচিত নয়।
  • অল্প সংখ্যক লাইনে এমন ফিট করা উচিত যাতে এটি উত্তরের মতো অনুলিপি-অনুলিপিযুক্ত হয়।

থটস

  • আমার বর্তমান চিন্তাভাবনাটি হ'ল আউটপুটগুলি std::random_deviceছড়িয়ে দেওয়া যায় (সম্ভবত XOR এর মাধ্যমে) time(NULL), ঠিকানা স্পেসের র্যান্ডমাইজেশন থেকে প্রাপ্ত মানগুলি এবং একটি হার্ড-কোডেড ধ্রুবক (যা বিতরণের সময় সেট করা যেতে পারে) এন্ট্রপিতে সেরা চেষ্টা করার শট পেতে।

  • std::random_device::entropy() না কি একটি ভাল লক্ষণ দিতে std::random_deviceকি হতে পারে বা পারে না।


24
@ ফ্যাবিয়েন: এ সম্পর্কে বহনযোগ্য কী? এটি একটি সি ++ প্রশ্ন, লিনাক্সের প্রশ্ন নয়।
অরবিটে

6
আমার ব্যক্তিগত এই ভেবে যে সম্ভবত মান থেকে আকৃষ্ট করা ছিল std::random_device, time(NULL),, এবং ফাংশন ঠিকানাগুলি তারপর একসঙ্গে XORed সেরা-প্রচেষ্টা এনট্রপি উৎস এক ধরনের উত্পাদন করতে।
রিচার্ড

5
এটি করা ভাল হবে যদি do_random_ ডিভাইস_অ্যাক্টিচিউলি_ ওয়ার্ক () এর মতো কোনও ফাংশন থাকলে যাতে কেউ অন্তত কৌতূহলজনকভাবে হ্রাস করতে পারে বা ব্যবহারকারীর জন্য সতর্কতা বা ত্রুটি তৈরি করতে পারে।

4
সঠিক সমাধানটি সংক্ষিপ্ত নয়, সংক্ষিপ্ত সমাধানটি যথাযথ হবে না। আমি আমার বীজ 11 লাইব্রেরিতে আমার ব্যবহারটি হ'ল মূলত আপনি std::random_deviceযে প্ল্যাটফর্মগুলিতে আপনার প্রোগ্রামটি চালানোর পরিকল্পনা করছেন সেগুলি যথাযথভাবে প্রয়োগ করা এবং একটি সহায়ক ফাংশন সরবরাহ করুন যা একটি বীজযুক্ত জেনারেটর তৈরি করে ( seed11::make_seeded<std::mt19937>())
মিলেনিয়ামব্যাগ

5
পাশে: আপনার দ্বিতীয় বুলেট নতুন কিছু যুক্ত করে না। আপনি অবাক হওয়ার মতো কিছু নেই যে আপনি 12 বার উপস্থিত হয়ে কিছু মান খুঁজে পেয়েছেন। আপনার কাছে আশা করা উচিত যে আপনার কাছে 2 values 32 স্বতন্ত্র, অভিন্নভাবে এলোমেলো নমুনা রয়েছে তা ধরে নিয়ে, 12 বারের মতো ঠিক তিনটি মান উপস্থিত হবে

উত্তর:


58

আমি সবচেয়ে বড় ত্রুটিটি যুক্তি দিয়ে বলব std::random_deviceযে কোনও সিএসপিআরএনজি উপলব্ধ না হলে এটি একটি নির্দোষ ফলব্যাকের অনুমতি দেওয়া হয়। এটিই পিআরএনজি ব্যবহার না করার একটি ভাল কারণ std::random_device, যেহেতু উত্পাদিত বাইটগুলি নির্জনবাদী হতে পারে। দুর্ভাগ্যক্রমে এটি কখন ঘটে তা অনুসন্ধান করার জন্য, বা নিম্নমানের এলোমেলো সংখ্যার পরিবর্তে ব্যর্থতার জন্য অনুরোধ করার জন্য একটি API সরবরাহ করে না।

এটি হ'ল, কোনও সম্পূর্ণ পোর্টেবল সমাধান নেই: তবে, একটি শালীন, ন্যূনতম পদ্ধতির রয়েছে। sysrandomPRNG বীজ করতে আপনি কোনও সিএসপিআরএনজি ( নীচে হিসাবে সংজ্ঞায়িত ) এর চারপাশে একটি ন্যূনতম মোড়ক ব্যবহার করতে পারেন ।

উইন্ডোজ


আপনি নির্ভর করতে পারেন CryptGenRandom, একটি সিএসপিআরএনজি। উদাহরণস্বরূপ, আপনি নিম্নলিখিত কোড ব্যবহার করতে পারেন:

bool acquire_context(HCRYPTPROV *ctx)
{
    if (!CryptAcquireContext(ctx, nullptr, nullptr, PROV_RSA_FULL, 0)) {
        return CryptAcquireContext(ctx, nullptr, nullptr, PROV_RSA_FULL, CRYPT_NEWKEYSET);
    }
    return true;
}


size_t sysrandom(void* dst, size_t dstlen)
{
    HCRYPTPROV ctx;
    if (!acquire_context(&ctx)) {
        throw std::runtime_error("Unable to initialize Win32 crypt library.");
    }

    BYTE* buffer = reinterpret_cast<BYTE*>(dst);
    if(!CryptGenRandom(ctx, dstlen, buffer)) {
        throw std::runtime_error("Unable to generate random bytes.");
    }

    if (!CryptReleaseContext(ctx, 0)) {
        throw std::runtime_error("Unable to release Win32 crypt library.");
    }

    return dstlen;
}

ইউনিক্স-সদৃশ


অনেকগুলি ইউনিক্স-মতো সিস্টেমে আপনার যখন সম্ভব হয় তখন / dev / urandom ব্যবহার করা উচিত (যদিও এটি পসিক্স-কমপ্লায়েন্ট সিস্টেমে উপস্থিত থাকার গ্যারান্টিযুক্ত নয়)।

size_t sysrandom(void* dst, size_t dstlen)
{
    char* buffer = reinterpret_cast<char*>(dst);
    std::ifstream stream("/dev/urandom", std::ios_base::binary | std::ios_base::in);
    stream.read(buffer, dstlen);

    return dstlen;
}

অন্যান্য


যদি কোনও সিএসপিআরএনজি উপলব্ধ না হয় তবে আপনি নির্ভর করতে পারেন std::random_device। তবে সম্ভব হলে আমি এড়াতে পারব, যেহেতু বিভিন্ন সংকলক ( মূলত মিনজিডাব্লু ) এটি পিআরএনজি হিসাবে বাস্তবায়িত করে (বাস্তবে, প্রতিটি সময় একই ক্রম উত্পাদন করে মানুষকে সতর্ক করতে যে এটি সঠিকভাবে এলোমেলো নয়)।

seeding


এখন আমাদের ন্যূনতম ওভারহেড সহ টুকরো রয়েছে, আমরা আমাদের পিআরএনজি বীজ করতে এলোমেলো এন্ট্রপির পছন্দসই বিট তৈরি করতে পারি। উদাহরণটি PRNG বীজ করতে 32-বিট ব্যবহার করে (স্পষ্টতই অপ্রতুল) এবং আপনার এই মানটি বাড়ানো উচিত (যা আপনার সিএসপিআরএনজি উপর নির্ভরশীল)।

std::uint_least32_t seed;    
sysrandom(&seed, sizeof(seed));
std::mt19937 gen(seed);

তুলনা বুস্ট


উত্স কোডটি তাত্ক্ষণিকভাবে দেখার পরে আমরা :: এলোমেলো_দেখার (সত্যিকারের সিএসপিআরএনজি) উন্নয়নের সমান্তরাল দেখতে পাই । MS_DEF_PROVউইন্ডোজে বুস্ট ব্যবহারগুলি সরবরাহ করে, যা এর জন্য সরবরাহকারী প্রকার PROV_RSA_FULL। শুধু অনুপস্থিত ক্রিপ্টোগ্রাফিক কনটেক্সট, যা দিয়ে কাজ করা যেতে পারে যাচাই করা হবে CRYPT_VERIFYCONTEXT। * নিক্সে, বুস্ট ব্যবহার করে /dev/urandom। আইই, এই সমাধানটি বহনযোগ্য, ভাল-পরীক্ষিত এবং সহজেই ব্যবহারযোগ্য।

লিনাক্স বিশেষায়িতকরণ


আপনি যদি সুরক্ষার জন্য সংক্ষিপ্ততা ত্যাগ করতে ইচ্ছুক getrandomহন তবে লিনাক্স ৩.১17 এবং তারপরে এবং সাম্প্রতিক সোলারিতে এটি একটি দুর্দান্ত পছন্দ। কার্নেলটি বুট করার পরেও তার সিএসপিআরএনজি আরম্ভ করে না দিলে এটি ব্লক করা ব্যতীত getrandomএকইরকম আচরণ করে /dev/urandom। নিম্নলিখিত স্নিপেটটি লিনাক্স getrandomউপলব্ধ কিনা এবং যদি ফিরে না আসে তা সনাক্ত করে /dev/urandom

#if defined(__linux__) || defined(linux) || defined(__linux)
#   // Check the kernel version. `getrandom` is only Linux 3.17 and above.
#   include <linux/version.h>
#   if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
#       define HAVE_GETRANDOM
#   endif
#endif

// also requires glibc 2.25 for the libc wrapper
#if defined(HAVE_GETRANDOM)
#   include <sys/syscall.h>
#   include <linux/random.h>

size_t sysrandom(void* dst, size_t dstlen)
{
    int bytes = syscall(SYS_getrandom, dst, dstlen, 0);
    if (bytes != dstlen) {
        throw std::runtime_error("Unable to read N bytes from CSPRNG.");
    }

    return dstlen;
}

#elif defined(_WIN32)

// Windows sysrandom here.

#else

// POSIX sysrandom here.

#endif

OpenBSD


সেখানে এক চূড়ান্ত সতর্কীকরণ হল: আধুনিক OpenBSD নেই /dev/urandom। পরিবর্তে আপনার জেন্টেন্ট্রপি ব্যবহার করা উচিত ।

#if defined(__OpenBSD__)
#   define HAVE_GETENTROPY
#endif

#if defined(HAVE_GETENTROPY)
#   include <unistd.h>

size_t sysrandom(void* dst, size_t dstlen)
{
    int bytes = getentropy(dst, dstlen);
    if (bytes != dstlen) {
        throw std::runtime_error("Unable to read N bytes from CSPRNG.");
    }

    return dstlen;
}

#endif

অন্যান্য চিন্তা


আপনার যদি ক্রিপ্টোগ্রাফিকভাবে সুরক্ষিত এলোমেলো বাইটের প্রয়োজন হয়, আপনার সম্ভবত পসিক্সের আনফারড খোলা / পঠন / বন্ধের সাথে fstream প্রতিস্থাপন করা উচিত। এটি উভয় কারণ basic_filebufএবং FILEএকটি অভ্যন্তরীণ বাফার ধারণ করে, যা একটি স্ট্যান্ডার্ড বরাদ্দকারীর মাধ্যমে বরাদ্দ করা হবে (এবং সেইজন্য স্মৃতি থেকে মুছে ফেলা হয় না)।

এটি সহজেই এতে পরিবর্তন করে sysrandomকরা যেতে পারে :

size_t sysrandom(void* dst, size_t dstlen)
{
    int fd = open("/dev/urandom", O_RDONLY);
    if (fd == -1) {
        throw std::runtime_error("Unable to open /dev/urandom.");
    }
    if (read(fd, dst, dstlen) != dstlen) {
        close(fd);
        throw std::runtime_error("Unable to read N bytes from CSPRNG.");
    }

    close(fd);
    return dstlen;
}

ধন্যবাদ


FILEবাফার রিডগুলি উল্লেখ করার জন্য বেন ভয়েগটকে বিশেষ ধন্যবাদ এবং তাই ব্যবহার করা উচিত নয়।

আমি উল্লেখ করার জন্য পিটার কর্ডেস getrandomএবং ওপেনবিএসডি এর অভাবকেও ধন্যবাদ জানাতে চাই /dev/urandom


11
আমি এটি অতীতে করেছি, তবে, বা কমপক্ষে একটি প্রশ্ন ডাব্লুটিএফ এই প্ল্যাটফর্মগুলির জন্য গ্রন্থাগারের লেখকরা আমাদের জন্য এটি করতে পারে না? আমি ফাইল অ্যাক্সেস এবং থ্রেডগুলি (উদাহরণস্বরূপ) গ্রন্থাগার বাস্তবায়নের দ্বারা বিমূর্ত করা প্রত্যাশা করি, তবে কেন এলোমেলো সংখ্যা জেনারেশন নয়?

2
এখানে ওপি: এই উত্তরটি বীজকে কিছুটা আরও ভালভাবে প্রদর্শন করলে ভাল লাগবে। যতটা সম্ভব, আমি উত্তরগুলির জন্য প্রত্যাশা করছি যা কপি-পাস্টেবল কোড উত্পন্ন করে যা কোডারের পক্ষে খুব বেশি প্রযুক্তিগত ব্যাখ্যা বা চিন্তাভাবনা না করে আমার প্রশ্নে পোস্ট করা সহজ উদাহরণের চেয়ে কাজটি আরও ভাল করে তোলে।
রিচার্ড

4
আমি ভেবেছিলাম /dev/randomএকটি আরএনজি বীজ করার জন্য ভাল পছন্দ হবে তবে স্পষ্টতই /dev/urandomএখনও কমপিটেশনাল সুরক্ষিত হিসাবে বিবেচিত হয় এমনকি যখন /dev/randomকম উপলব্ধ এনট্রপির কারণে অবরুদ্ধ হয়, তাই urandomসম্ভবত ওয়ান-টাইম প্যাড ব্যতীত সকল কিছুর জন্য প্রস্তাবিত পছন্দ। এছাড়াও unix.stackexchange.com / প্রশ্নগুলি / ৩৪২২০৯ / দেখুন দেখুন । urandomযদিও বুটআপের খুব প্রথম থেকেই অনুমানযোগ্য বীজ থেকে সাবধান থাকুন ।
পিটার

2
লিনাক্সের getrandom(2)সিস্টেম কলটি খোলার এবং পড়ার মতো /dev/urandom, কার্নেলের এলোমেলো উত্সগুলি এখনও শুরু না করা হলে এটি ব্লক হয়ে যাবে। আমি মনে করি এটি অন্যান্য ক্ষেত্রে যেমন বাধা ছাড়াই আপনাকে প্রাথমিক-বুট নিম্ন-মানের-এলোমেলো সমস্যা থেকে বাঁচায় /dev/random
পিটার

1
@ পিটারকর্ডস, নিশ্চিতভাবেই, এবং এটি পাওয়া গেলে একটি দুর্দান্ত বিকল্প। তবে এটি বিএসডি বা অন্যান্য * নিক্সেসে কাজ করে না, যা /dev/urandomসাধারণত কিছু কাজ করে। পাইথন মেলিং তালিকার আলোচনার বিষয়টি আমি সাধারণত সাবস্ক্রাইব করি: বাগস.পিথন.অর্গ
আলেকজান্ডার হুজ্জাঘ

22

এক অর্থে, এটি বহনযোগ্যভাবে করা যায় না। এটি হ'ল, সি -++ চলমান একটি বৈধ সম্পূর্ণ-ডিটারমিনিস্টিক প্ল্যাটফর্ম ধারণা করা যেতে পারে (বলুন, এমন একটি সিমুলেটর যা মেশিন ক্লককে ডিটারনিস্টিকালি পদক্ষেপ নেয় এবং "নির্ধারিত" I / O সহ) যেখানে কোনও পিআরএনজি বীজ করার জন্য এলোমেলোতার কোনও উত্স নেই।


1
@ কেবেল্ডার: ১. ব্যবহারকারী বলছেন কে? ২. সমস্ত প্রোগ্রামের ব্যবহারকারীর ইন্টারঅ্যাকশন নেই এবং আপনি অবশ্যই ধরে নিতে পারবেন না যে সবসময়ই একজন ব্যবহারকারী
রয়েছেন

8
আমি এই প্রতিক্রিয়াটির প্রশংসা করি, তবে এও অনুভব করি যেহেতু কোনও প্রোগ্রামের উচিত সর্বোত্তম চেষ্টা করার একটি যুক্তিসঙ্গত প্রচেষ্টা করা উচিত।
রিচার্ড

3
@ রিচার্ড সম্মত হয়েছেন, তবে বিষয়টি হ'ল সি ++ স্ট্যান্ডার্ড লেখকদের এই ধরণের উদ্ভট পরিস্থিতি সামঞ্জস্য করতে হবে (বা অন্তত তাদের স্বল্পতম চেষ্টা করতে হবে)। এ কারণেই আপনি এই ধরণের ধরণের পছন্দসই স্ট্যান্ডার্ড সংজ্ঞা পেয়ে যান, যেখানে আপনি শালীন ফলাফল পেতে পারেন, তবে কম্পাইলারটি এখনও মানদণ্ডের সাথে সামঞ্জস্যপূর্ণ হতে পারে এমনকি যদি এটি কার্যকরীভাবে মূল্যহীন কিছু দেয় তবে। - সুতরাং আপনার বিধিনিষেধগুলি ("সংক্ষিপ্ত এবং অন্যান্য গ্রন্থাগারের উপর নির্ভর করতে পারে না") কোনও প্রতিক্রিয়া এড়িয়ে যায়, কারণ আপনার কার্যকরভাবে প্ল্যাটফর্ম-বাই-প্ল্যাটফর্ম / সংকলক-বাই-সংকলক বিশেষ কেসিং প্রয়োজন। (যেমন বুস্ট এত ভাল কী করে))
আরএম

2
@Richard এটা কি ব্যাখ্যা, যদিও, আপনি কি আপনি স্ট্যান্ডার্ড পেতে পাবেন কারণ ভাল করার কোন পোর্টেবল উপায় নেই। আপনি যদি আরও ভাল করতে চান (যা একটি মহৎ লক্ষ্য) তবে আপনাকে কিছু বৃহত্তর বা কম পরিমাণে ঘৃণা গ্রহণ করতে হবে :)
শখ

1
@ রিচার্ড: কখনও কখনও আপনাকে কেবল স্বীকার করতে হয় যে এটি একটি মান-সম্মতিযুক্ত সি ++ বাস্তবায়ন যা কার্যকর নয় possible যেহেতু বাস্তবায়নগুলি লোকেদের কাজে লাগানোর জন্য নকশাকৃত যে কোনও কিছুর জন্য ব্যবহার করে , আপনাকে কখনও কখনও "কোনও বুদ্ধিমান বাস্তবায়ন যুক্তিসঙ্গত কিছু করবে" এর মতো যুক্তি দিয়ে বাঁচতে হবে। আমি আশা করি std::random_deviceযে এই বিভাগে হবে, কিন্তু কিছু বাস্তব বাস্তবায়ন একটি নির্দিষ্ট বীজ PRNG ব্যবহার করে তবে স্পষ্টতই এটি না! এটি আইনপোকলমের যুক্তি ছাড়িয়ে যায়।
পিটার কর্ডেস

14

std::seed_seqআলেকজান্ডার হুজাঘের এনট্রপি পাওয়ার পদ্ধতিটি ব্যবহার করে আপনি জেনারেটরের জন্য কমপক্ষে প্রয়োজনীয় রাষ্ট্রীয় আকারটি ব্যবহার করতে এবং এটি পূরণ করতে পারেন :

size_t sysrandom(void* dst, size_t dstlen); //from Alexander Huszagh answer above

void foo(){

    std::array<std::mt19937::UIntType, std::mt19937::state_size> state;
    sysrandom(state.begin(), state.length*sizeof(std::mt19937::UIntType));
    std::seed_seq s(state.begin(), state.end());

    std::mt19937 g;
    g.seed(s);
}

স্ট্যান্ডার্ড লাইব্রেরিতে ইউনিফর্মর্যান্ডম বিটজেনেটর থেকে বীজ বপনের জন্য সঠিকভাবে ব্যবহার করার জন্য যদি কোনও বীজসীমা পূরণ করার বা তৈরি করার উপযুক্ত উপায় ছিল তবে এটি আরও সহজ হবে।std::random_device


1
বীজ_সেকের সমস্যাগুলি রয়েছে, পিসিজিআরন্ডম.org
posts/

আপনি সিড_সেক থেকে বীজ এলে এলোমেলো সংখ্যা জেনারেটর পুরো অ্যারেটি ব্যবহার করবে এমন গ্যারান্টি দেওয়ার জন্য সি ++ স্ট্যান্ডার্ড বা কোনও কিছুই নেই। আপনি যদি কোনও বৈজ্ঞানিক সিমুলেশনের জন্য আরএনজি এবং ক্রিপ্টোগ্রাফির জন্য অবশ্যই ব্যবহার করেন তবে এই পদ্ধতিটি ব্যর্থতার দিকে পরিচালিত করবে। এর একমাত্র ব্যবহারের ক্ষেত্রে ভিডিওোগেমটি এলোমেলোভাবে করা, তবে সেখানে এটি ওভারকিল হবে।
Kostas

5

আমি যে বাস্তবায়নের বিষয়ে কাজ করছি state_sizeতা mt19937আরআরএনজির সম্পত্তি থেকে সুবিধা গ্রহণ করে সিদ্ধান্ত নিতে যে কতগুলি বীজ সরবরাহ করতে হবে:

using Generator = std::mt19937;

inline
auto const& random_data()
{
    thread_local static std::array<typename Generator::result_type, Generator::state_size> data;
    thread_local static std::random_device rd;

    std::generate(std::begin(data), std::end(data), std::ref(rd));

    return data;
}

inline
Generator& random_generator()
{
    auto const& data = random_data();

    thread_local static std::seed_seq seeds(std::begin(data), std::end(data));
    thread_local static Generator gen{seeds};

    return gen;
}

template<typename Number>
Number random_number(Number from, Number to)
{
    using Distribution = typename std::conditional
    <
        std::is_integral<Number>::value,
        std::uniform_int_distribution<Number>,
        std::uniform_real_distribution<Number>
    >::type;

    thread_local static Distribution dist;

    return dist(random_generator(), typename Distribution::param_type{from, to});
}

আমি মনে করি উন্নতির জন্য জায়গা রয়েছে কারণ এটি আকার এবং ব্যাপ্তির চেয়ে std::random_device::result_typeআলাদা হতে পারে std::mt19937::result_typeযাতে এটি সত্যই বিবেচনায় নেওয়া উচিত।

স্ট্যান্ড :: র্যান্ডম_ ডিভাইস সম্পর্কে একটি নোট ।

মতে C++11(/14/17)মান (গুলি):

26.5.6 বর্গ র্যান্ডম_দেব [ ডিভাইস ]

2 যদি বাস্তবায়নের সীমাবদ্ধতাগুলি অ-ডেটিমিনিস্টিক এলোমেলো সংখ্যা উত্পন্ন করতে প্রতিরোধ করে, বাস্তবায়নটি এলোমেলো সংখ্যা ইঞ্জিন নিযুক্ত করতে পারে।

এই উপায়ে বাস্তবায়নের শুধুমাত্র জেনারেট করতে পারেন নির্ণায়ক মান যদি এটা উৎপাদিত আসা বন্ধ করা হয় অ নির্ণায়ক কিছু সীমাবদ্ধতা দ্বারা বেশী।

MinGWকম্পাইলার Windowsবিখ্যাত উপলব্ধ করা হয় না অ নির্ণায়ক তার থেকে মানগুলি std::random_deviceথাকা সত্ত্বেও তাদের অপারেটিং সিস্টেম থেকে সহজে প্রাপ্তিসাধ্য হচ্ছে। সুতরাং আমি এটিকে একটি ত্রুটি হিসাবে বিবেচনা করি এবং বাস্তবায়ন এবং প্ল্যাটফর্মগুলির জুড়ে সম্ভবত একটি সাধারণ ঘটনা নয়।


1
এটি এমটি রাজ্য পূরণ করতে পারে তবে এখনও সম্পূর্ণর উপর নির্ভর করে std::random_deviceএবং তাই এটি থেকে উদ্ভূত সমস্যাগুলির পক্ষে ঝুঁকির মধ্যে রয়েছে।
রিচার্ড

1
আমি মনে করি আমি তাদের প্রশ্নের যথেষ্ট পরিমাণে স্পষ্ট করে বলেছি। যদিও স্পষ্ট করে / আলোচনা করে খুশি।
রিচার্ড

2
@ রিচার্ড কি এমন কোনও বাস্তব সিস্টেম রয়েছে যা বাস্তবে যুক্তিসঙ্গত বাস্তবায়ন করে না std::random_device? আমি জানি যে স্ট্যান্ডার্ডটি PRNGপিছনে পড়ার অনুমতি দেয় তবে আমি মনে করি এগুলি কেবল নিজেকে আবৃত করা কারণ এটি দাবি করা কঠিন যে প্রতিটি ডিভাইস যা ব্যবহার করে C++তার একটি অ-নিষ্ক্রিয় র্যান্ডম উত্স থাকে। এবং যদি তারা না করে তবে আপনি কীভাবে এটি করতে পারেন?
গালিক

5
পছন্দ করুন আমার উদ্দেশ্যটি হল আমার "পোর্টেবল সলিউশন" ডিভাইসের উপর নির্ভরশীল করা কারণ ডিভাইসটি যদি অ-নিরস্ত জেনারেটরকে সমর্থন করে তবে তা করা উচিত std::random_device। আমি বিশ্বাস করি যে এটি আদর্শের চেতনা। সুতরাং আমি অনুসন্ধান করেছি এবং এটি কেবল MinGWএটির ক্ষেত্রেই ভেঙে গেছে can আমি খুঁজে পাওয়া অন্য যে কোনও কিছুই এই সমস্যাটির প্রতিবেদন করছে বলে মনে হয় না। সুতরাং, আমার লাইব্রেরিতে আমি কেবল MinGWঅসমর্থিত হিসাবে চিহ্নিত করেছি । যদি আরও বিস্তৃত সমস্যা হয় তবে আমি এটি আবার চিন্তা করব। আমি এখনই তার প্রমাণ দেখতে পাচ্ছি না।
গালিক

5
আমি সত্যিই হতাশ হয়েছি যে মিনজিডাব্লু std::random_deviceপ্ল্যাটফর্মের এলোমেলো ক্ষমতা সরবরাহ করে না এমন ফর্মের মাধ্যমে এটি সবার জন্য নষ্ট করছে। নিম্ন-মানের বাস্তবায়নগুলি বিদ্যমান এপিআইয়ের উদ্দেশ্যকে পরাস্ত করে। আইএমও যদি এটি কাজ না করা অবধি কেবল এটিকে বাস্তবায়ন না করে তবে এটি আরও ভাল। (বা আরও ভাল, যদি উচ্চ মানের মানের এলোমেলোতা না পাওয়া যায় তবে এআইপি ব্যর্থতার অনুরোধের জন্য যদি কোনও উপায় সরবরাহ করে, তবে মিনজিডাব্লু সুরক্ষা ঝুঁকি সৃষ্টি করতে পারে যখন গেমস বা অন্য যাই হোক না কেন বিভিন্ন বীজ দেওয়ার সময় সুরক্ষা ঝুঁকি সৃষ্টি করতে পারে।)
পিটার

2

সময় ব্যবহার করে বীজ বপনে কোনও ভুল নেই, ধরে নিই যে এটির সুরক্ষিত হওয়ার দরকার নেই (এবং আপনি এটি বলতেন না) didn't অন্তর্দৃষ্টিটি হ'ল আপনি হ্যাশিং ব্যবহার করে অ-র‌্যান্ডমকে ঠিক করতে পারেন। আমি ভারী মন্টি কার্লো সিমুলেশনের জন্য এবং বিশেষত সমস্ত ক্ষেত্রে এটি পর্যাপ্তরূপে কাজ করে দেখেছি।

এই পদ্ধতির একটি দুর্দান্ত বৈশিষ্ট্য হ'ল এটি অন্যান্য-সত্য-এলোমেলো বীজের সেটগুলি থেকে সূচনাতে সাধারণীকরণ করে। উদাহরণস্বরূপ, আপনি যদি প্রতিটি থ্রেডের নিজস্ব আরএনজি রাখতে চান (থ্রেডসফটিটির জন্য), আপনি কেবল হ্যাশ থ্রেড আইডির ভিত্তিতে আরম্ভ করতে পারেন।

নীচে একটি এসএসসিসিই রয়েছে , যা আমার কোডবেস থেকে বিচ্ছুরিত হয়েছে (সরলতার জন্য; কিছু ওও সমর্থন কাঠামোকে সমর্থন করেছে):

#include <cstdint> //`uint32_t`
#include <functional> //`std::hash`
#include <random> //`std::mt19937`
#include <iostream> //`std::cout`

static std::mt19937 rng;

static void seed(uint32_t seed) {
    rng.seed(static_cast<std::mt19937::result_type>(seed));
}
static void seed() {
    uint32_t t = static_cast<uint32_t>( time(nullptr) );
    std::hash<uint32_t> hasher; size_t hashed=hasher(t);
    seed( static_cast<uint32_t>(hashed) );
}

int main(int /*argc*/, char* /*argv*/[]) {
    seed();
    std::uniform_int_distribution<> dis(0, 5);
    std::cout << dis(rng);
}

1
আমি আপনার সাথে একমত যে সময়ের সাথে বীজ বোধ করা সম্ভবত অনুশীলনে যথেষ্ট ভাল, যদি আপনার সুরক্ষিত না হওয়ার দরকার হয়। তবে আমি আপনার বাকি উত্তরগুলির সাথে একমত হতে পারি না। সময়ের হ্যাশ দিয়ে বপন করা সময়ের সাথে বপন করার চেয়ে ভাল নয়।
ডিডাব্লু

@ ডিডব্লিউ অনুগতভাবে, এটি আরও ভাল। কারণ হ্যাশ সান্তার এবং ধারন মূল্যবোধের অনেক বৃহত্তর পরিসর (সাথে বীজ নিজে চেষ্টা 1এবং 2কর এবং দেখ যে তাদের দ্বারা উত্পন্ন ভাসে ক্রম সত্যিই অপসরণ হতে কিছু সময় নেয়)।
আইমলেটটি

আমি দেখতে পাচ্ছি না কেন এটি গুরুত্বপূর্ণ। আমরা একবারে কেবল একটি একা বীজের উপর দৌড়াচ্ছি। বীজের সম্ভাব্য মানগুলির স্থান (বীজের এনট্রপি) একইভাবে হয় - হ্যাশিং এন্ট্রপি বাড়ায় না। হ্যাশিং কেন ভাল হয় তা বোঝাতে আপনি প্রশ্নটি সম্পাদনা করতে পারেন?
ডিডাব্লু

0

এই প্রশ্নে এখানে আমার নিজের ছুরিকা:

#include <random>
#include <chrono>
#include <cstdint>
#include <algorithm>
#include <functional>
#include <iostream>

uint32_t LilEntropy(){
  //Gather many potential forms of entropy and XOR them
  const  uint32_t my_seed = 1273498732; //Change during distribution
  static uint32_t i = 0;        
  static std::random_device rd; 
  const auto hrclock = std::chrono::high_resolution_clock::now().time_since_epoch().count();
  const auto sclock  = std::chrono::system_clock::now().time_since_epoch().count();
  auto *heap         = malloc(1);
  const auto mash = my_seed + rd() + hrclock + sclock + (i++) +
    reinterpret_cast<intptr_t>(heap)    + reinterpret_cast<intptr_t>(&hrclock) +
    reinterpret_cast<intptr_t>(&i)      + reinterpret_cast<intptr_t>(&malloc)  +
    reinterpret_cast<intptr_t>(&LilEntropy);
  free(heap);
  return mash;
}

//Fully seed the mt19937 engine using as much entropy as we can get our
//hands on
void SeedGenerator(std::mt19937 &mt){
  std::uint_least32_t seed_data[std::mt19937::state_size];
  std::generate_n(seed_data, std::mt19937::state_size, std::ref(LilEntropy));
  std::seed_seq q(std::begin(seed_data), std::end(seed_data));
  mt.seed(q);
}

int main(){
  std::mt19937 mt;
  SeedGenerator(mt);

  for(int i=0;i<100;i++)
    std::cout<<mt()<<std::endl;
}

এখানে ধারণাটি হ'ল এন্ট্রপির অনেকগুলি সম্ভাব্য উত্স (দ্রুত সময়, ধীর সময় std::random-device, স্ট্যাটিক ভেরিয়েবল অবস্থান, গাদা লোকেশন, ফাংশন অবস্থান, লাইব্রেরির অবস্থানসমূহ, প্রোগ্রাম-নির্দিষ্ট মান) একত্রিত করার জন্য এক্সওআর ব্যবহার করা যা শুরু করার সময় সর্বোত্তম প্রচেষ্টা করার চেষ্টা করতে পারে mt19937। যতক্ষণ অন্তত একবার উত্স "ভাল" হয়, ফলাফল কমপক্ষে সেই "ভাল" হবে।

এই উত্তরটি সংক্ষিপ্ত নয় যতটা পছন্দনীয় হবে এবং যুক্তিটির এক বা একাধিক ভুল থাকতে পারে। তাই আমি এটিকে অগ্রগতিমূলক কাজ হিসাবে বিবেচনা করছি। আপনার মতামত থাকলে মন্তব্য করুন।


3
ঠিকানাগুলিতে খুব কম এলোমেলো থাকতে পারে। আপনার সর্বদা একই বরাদ্দ থাকে, তাই ছোট এম্বেড থাকা সিস্টেমে যেখানে আপনি পুরো স্মৃতিতে অ্যাক্সেস পেয়ে থাকেন সেখানে প্রতিবার একই ফলাফল পাওয়া যায়। আমি বলব এটি সম্ভবত একটি বড় ব্যবস্থার পক্ষে যথেষ্ট ভাল তবে এটি একটি মাইক্রোকন্ট্রোলারকে ছাড়িয়ে যেতে পারে।
মেনেনডাল

1
আমার অনুমান যে &i ^ &myseedএকা একের তুলনায় যথেষ্ট কম এনট্রোপি থাকা উচিত, যেহেতু উভয়ই একই অনুবাদ ইউনিটে স্থিতিশীল স্টোরেজ সময়কাল সহ অবজেক্ট এবং তাই সম্ভবত এটি একসাথে কাছাকাছি থাকার সম্ভাবনা রয়েছে। এবং আপনি কি বিশেষত আরম্ভের সময় থেকে বিশেষ মানটি ব্যবহার করবেন বলে মনে করছেন না myseed?
aschepler

7
ডিলোক্যাটেড পয়েন্টারগুলিকে ints এ রূপান্তর করা অপরিজ্ঞাত আচরণ; এটি উপস্থিত থাকা অবস্থায় এটি করুন। ^একটি ভয়ঙ্কর হ্যাশ সংযোগকারী; যদি দুটি মান উভয়ই এনট্রপি প্রচুর পরিমাণে থাকে তবে একে অপরের তুলনায় সামান্য হয় তবে এটি এটিকে সরিয়ে দেয়। +সাধারণত উন্নত হয় (যেমন x + x কেবলমাত্র x এর মধ্যে 1 বিট ইন্ট্রপি জ্বালায়, যখন x ^ x তাদের সমস্তটি পোড়ায়)। ফাংশন থ্যাড নিরাপদ নয় আমার সন্দেহ ( rd())
ইয়াক্ক - অ্যাডাম নেভ্রামামন্ট

2
ওহ এবং +আমি স্বাক্ষরবিহীন মানে ( +স্বাক্ষরযুক্ত ইউবি-টোপ)। এগুলি কিছুটা হাস্যকর ইউবি ক্ষেত্রে হলেও আপনি পোর্টেবল বলেছিলেন। সম্ভব হলে কোনও ফাংশনের ঠিকানাটি অবিচ্ছেদ্য মান হিসাবে পাওয়া বিবেচনা করুন (এটি যদি অনিশ্চিত হয়?)
ইয়াক্ক - অ্যাডাম নেভ্রামামন্ট

1
@ জেনারেল্ডাল: এমনকি একটি সম্পূর্ণ-শক্তি পিসিতে, যদিও বরাদ্দগুলি বিভিন্ন শারীরিক অবস্থানগুলি (প্রক্রিয়াটির বাহ্যিক মেশিনের অবস্থার উপর নির্ভর করে) পেতে পারে, পয়েন্টারগুলি প্রক্রিয়া ভার্চুয়াল অ্যাড্রেস স্পেস দ্বারা বিমূর্ত করা হয় এবং সম্ভবত উচ্চ পুনরাবৃত্তিযোগ্য, বিশেষত ASLR কার্যকর হয় না।
বেন ভয়েগট

0
  • সিউডোরানডম নম্বর জেনারেটর (পিআরএনজি) বীজ করতে জেন্টেন্ট্রপি () ব্যবহার করুন।
  • যদি আপনি এলোমেলো মান চান (তবে পরিবর্তে, বলুন /dev/urandomবা বলুন /dev/random) চান তবে গেট্রেন্ডম () ব্যবহার করুন ।

লিনাক্স, সোলারিস এবং ওপেনবিএসডি এর মতো আধুনিক ইউনিক্স-এর মতো সিস্টেমে এটি উপলব্ধ।


-2

প্রদত্ত প্ল্যাটফর্মের এন্ট্রপির কোনও উত্স থাকতে পারে, যেমন /dev/random। যুগের পর থেকে ন্যানোসেকেন্ডগুলি std::chrono::high_resolution_clock::now()সম্ভবত স্ট্যান্ডার্ড লাইব্রেরির সেরা বীজ।

(uint64_t)( time(NULL)*CLOCKS_PER_SEC + clock() )সুরক্ষা-সমালোচনামূলক নয় এমন অ্যাপ্লিকেশনগুলির জন্য আমি এর আগে এনট্রপির আরও বিট পাওয়ার মতো কিছু ব্যবহার করেছি ।


2
আপনার সত্যই ব্যবহার করা উচিত /dev/urandom, বিশেষত এরকম ক্ষেত্রে। /dev/randomব্লক, এবং প্রায়শই এটি করার উপযুক্ত কারণ ছাড়াই ([কতগুলি ভিন্ন ওএস / / ডি / এলোমেলোভাবে উত্পাদিত বাইটের এলোমেলোতা অনুমান করে সে সম্পর্কে দীর্ঘ বিবরণ সন্নিবেশ করান]))।
আলেকজান্ডার হুজ্জাহ

2
@ আলেকজান্দার হুজাঘাগ সত্য, যদিও আমাকে এমন সিস্টেমে কোড করতে হয়েছিল যেখানে /dev/urandomঅস্তিত্ব ছিল না, এবং ব্লক করার বিকল্প ছিল নির্ধারণবাদ। একটি বাক্সে /dev/hwrngবা /dev/hw_randomপাশাপাশি থাকতে পারে, যা আরও ভাল হওয়া উচিত।
ডেভিস্লোর

ঠিক আছে, আমি বলেছিলাম, "যেমন /dev/random," এবং এটি লিনাক্সের /dev/randomবিরুদ্ধে বনাম সম্পর্কে একটি পবিত্র যুদ্ধের সূত্রপাত করেছিল /dev/urandomযা আমি উদাহরণটি দেওয়ার সময় উদ্দেশ্য করি নি ..
ডেভিসর
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.