র্যান্ড ()% 6 পক্ষপাতদুষ্ট কেন?


109

কিভাবে স্ট্যান্ড :: র‌্যান্ড ব্যবহার করবেন তা পড়ার সময়, আমি এই কোডটি cppreferences.comপেয়েছি

int x = 7;
while(x > 6) 
    x = 1 + std::rand()/((RAND_MAX + 1u)/6);  // Note: 1+rand()%6 is biased

ডান দিকের অভিব্যক্তিটি কী ভুল? এটি চেষ্টা করে দেখুন এবং এটি নিখুঁতভাবে কাজ করে।


24
নোট করুন যে পাশা জন্য ব্যবহার করা আরও ভালstd::uniform_int_distribution
কালেথ

1
@ ক্যালথ হ্যাঁ, এই কোডটি কেন 'ভুল' ছিল তা কেবল বুঝতে
পেরেছিল

15
"ভুল" থেকে "পক্ষপাতদুষ্ট" পরিবর্তন হয়েছে
কিবিবি

3
rand()সাধারণ বাস্তবায়নের ক্ষেত্রে খুব খারাপ, আপনি পাশাপাশি xkcd আরএনজি ব্যবহার করতে পারেন । সুতরাং এটি ভুল কারণ এটি ব্যবহার করে rand()
কোডসইনচাওস

3
আমি এই জিনিসটি লিখেছি (ভাল, মন্তব্য নয় - এটি @ কুবি) এবং পিট বেকারের উত্তরটি যা ব্যাখ্যা করেছিল আমি সেসময় যা মনে রেখেছিলাম । (এফওয়াইআই, এটি মূলত লিবিস্টডিসি ++ 'এর সমান অ্যালগোরিদম uniform_int_distribution))
টিসি

উত্তর:


136

দুটি সমস্যা রয়েছে rand() % 6(এতে 1+উভয়ই সমস্যা প্রভাবিত করে না)।

প্রথমত, বেশ কয়েকটি জবাব যেমন উল্লেখ করেছে যে, যদি কম বিটগুলি rand()যথাযথভাবে অভিন্ন না হয় তবে অবশিষ্ট অপারেটরের ফলাফলও অভিন্ন নয়।

দ্বিতীয়ত, উত্পাদিত স্বতন্ত্র মানগুলির সংখ্যা যদি rand()6 এর একাধিক না হয়, তবে অবশিষ্টগুলি উচ্চ মানের তুলনায় আরও কম মান তৈরি করবে। rand()পুরোপুরি পুরোপুরি বিতরণ করা মানগুলি হলেও এটি সত্য ।

চূড়ান্ত উদাহরণ হিসাবে, ভান করুন যা rand()পরিসীমাটিতে সমানভাবে বিতরণ করা মানগুলি উত্পাদন করে [0..6]। আপনি যদি সেই মানগুলির জন্য অবশিষ্টগুলির দিকে লক্ষ্য করেন, যখন rand()পরিসীমাটিতে কোনও মান ফেরত দেয় [0..5], অবশিষ্টগুলি পরিসরে সমানভাবে বিতরিত ফলাফল উত্পন্ন করে [0..5]। যখন rand()returns রিটার্ন দেয়, তখন rand() % 60 প্রদান করে, যেমনটি rand()0 ফিরে এসেছে So সুতরাং আপনি অন্যান্য মান হিসাবে দ্বিগুণ হিসাবে একটি বন্টন পাবেন।

দ্বিতীয়টি হ'ল আসল সমস্যা rand() % 6

সমস্যাটি এড়ানোর উপায় হ'ল মানগুলি যা অ-ইউনিফর্ম নকল তৈরি করে তা বাতিল করা। আপনি 6 এর বৃহত্তর একাধিক গণনা করেন যা এর চেয়ে কম বা সমান হয় RAND_MAXএবং যখনই rand()একাধিকের চেয়ে বেশি বা সমান কোনও মান ফেরত দেয় আপনি এটিকে প্রত্যাখ্যান করেন এবং পুনরায় `র্যান্ড () কল করুন, যতবার প্রয়োজন ততবার।

তাই:

int max = 6 * ((RAND_MAX + 1u) / 6)
int value = rand();
while (value >= max)
    value = rand();

এটি প্রশ্নে থাকা কোডটির একটি পৃথক বাস্তবায়ন, কী চলছে তা আরও স্পষ্ট করে দেখানোর উদ্দেশ্যে।


2
আমি এই সাইটে কমপক্ষে একজনকে নিয়মিত একটি কাগজ তৈরি করার প্রতিশ্রুতি দিয়েছি তবে আমি মনে করি যে নমুনা দেওয়া এবং প্রত্যাখ্যান উচ্চ মুহূর্তগুলি ছুঁড়ে ফেলতে পারে ; যেমন ভেরিয়েন্স overinflate।
বাথশেবা

30
এই কৌশলটি যদি র্যান্ড_ম্যাক্স 32768 হয় তবে এটি কতটুকু পক্ষপাতিত্বের একটি গ্রাফ করেছি যা এটি কিছু বাস্তবায়নে রয়েছে। ericlippert.com/2013/12/16/…
এরিক লিপার্ট

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

4
@ এসএমএলটার্স: আপনার প্রথম বাক্যটি সত্য জেনারেটরের জন্য সঠিক , ছদ্ম জেনারেটরের পক্ষে অগত্যা সত্য নয়। আমি যখন অবসর নেব, আমি এই সম্পর্কে একটি কাগজ লিখতে যাচ্ছি।
বাথশেবা

2
@ অ্যান্টনি পাশের দিক দিয়ে চিন্তা করুন আপনি 1 এবং 3 এর মধ্যে একটি এলোমেলো সংখ্যা চান এবং আপনার কেবলমাত্র একটি স্ট্যান্ডার্ড 6-পক্ষীয় ডাই আছে have আপনি যদি 4-6 রোল করেন তবে 3 টি বিয়োগ করে আপনি এটি পেতে পারেন। তবে এর পরিবর্তে আপনি 1 এবং 5 এর মধ্যে একটি সংখ্যা চান তা বলুন a আপনি 6 টি রোল করার সময় যদি 5 টি বিয়োগ করেন তবে আপনি অন্য সংখ্যার চেয়ে দ্বিগুণ 1 সংখ্যার সাথে শেষ করবেন। সিপ্রেফারেন্স কোডটি মূলত এটিই করছে। সঠিক জিনিসটি হ'ল 6 টি পুনরায় তালিকাভুক্ত করা। পিট এখানে এটিই করছে: ডাই বিভক্ত করুন যাতে প্রতিটি সংখ্যা রোল করার একই পদ্ধতি রয়েছে এবং এমন কোনও সংখ্যা পুনরায় নথিভুক্ত করুন যা এমনকি বিভাগে ফিট করে না
রে

19

এখানে লুকানো গভীরতা রয়েছে:

  1. ছোট uমধ্যে ব্যবহার RAND_MAX + 1uRAND_MAXএকটি intপ্রকার হিসাবে সংজ্ঞায়িত করা হয় , এবং প্রায়শই এটি সম্ভব সবচেয়ে বড় int। আচরণকে RAND_MAX + 1হবে undefined যেমন দৃষ্টান্ত হিসেবে আপনি একটি সজল চাই signedপ্রকার। রচনা 1uবাহিনী রূপান্তরকে টাইপ RAND_MAXকরে unsigned, তাই ওভারফ্লো প্রবাহিত করে।

  2. ব্যবহারের % 6 করতে পারেন (কিন্তু প্রত্যেক বাস্তবায়নে std::randআমি দেখেছি নেই ) উপরে এবং উপস্থাপন বিকল্প পরলোক কোন অতিরিক্ত পরিসংখ্যানগত পক্ষপাত পরিচয় দিন। % 6বিপজ্জনক যেমন উদাহরণগুলি যেখানে সংখ্যার জেনারেটরের কম ক্রমের বিটগুলির মধ্যে পারস্পরিক সম্পর্ক রয়েছে, যেমন randআমি মনে করি, ১৯ the০ এর দশকে উচ্চ এবং নিম্ন বিটগুলি "চূড়ান্ত হিসাবে উল্টেছিল" ঝঙ্কার "। আরও বিবেচনাটি হ'ল 6 খুব ছোট সিএফ. RAND_MAX, সুতরাং RAND_MAX6 এর একাধিক না হলে একটি ন্যূনতম প্রভাব পড়বে , যা সম্ভবত এটি নয়।

উপসংহারে, আজকের দিনে, এর ট্র্যাক্টিবিলিটির কারণে, আমি ব্যবহার করব % 6। জেনারেটর নিজেই প্রবর্তনকালের বাইরে কোনও পরিসংখ্যানগত অসংগতি প্রবর্তন করার সম্ভাবনা নেই। আপনি যদি এখনও সন্দেহ করেন তবে আপনার ব্যবহারের ক্ষেত্রে এটির জন্য উপযুক্ত পরিসংখ্যানগত বৈশিষ্ট্য রয়েছে কিনা তা পরীক্ষা করে আপনার জেনারেটরটি পরীক্ষা করুন।


12
% 6rand()কবুতর-গর্ত নীতিটি যখনই উত্পন্ন স্বতন্ত্র মানের সংখ্যা 6. এর একাধিক হয় না তখন একটি পক্ষপাতমূলক ফলাফল তৈরি করে । মঞ্জুর, পক্ষপাত ছোট যখন RAND_MAX6 এর চেয়ে অনেক বড় হয় তবে এটি সেখানে। এবং বৃহত্তর লক্ষ্য রেঞ্জের জন্য প্রভাবটি অবশ্যই, বৃহত্তর।
পিট বেকার

2
@ পেটবেকার: সত্যই, আমার এটি পরিষ্কার করা উচিত। তবে মনে রাখবেন যে পূর্ণসংখ্যা বিভাগের কাটা প্রভাবের কারণে আপনি নমুনা পরিসর RAND_MAX এর কাছে পৌঁছানোর সাথে সাথে কবুতর-হোলিংও পাবেন।
বাথশেবা

2
@ বাথশেবা কি সেই কাটা কাটা প্রভাবের ফলে 6 টিরও বেশি বড় ফলাফল এবং এইভাবে পুরো অপারেশনটির পুনরাবৃত্তি কার্যকর করতে পারে না?
গেরহর্দ্ধ

1
@ গেরহর্দ: সঠিক আসলে, এটি ফলাফলের ঠিক দিকে নিয়ে যায় x==7। বুদ্ধিমানভাবে, আপনি পরিসীমাটি [0, RAND_MAX]7 টি সাবরেঞ্জে ভাগ করুন , একই আকারের 6 এবং শেষে একটি ছোট সাব্রেন্জ করুন। শেষ সাবরেঞ্জের ফলাফলগুলি বাতিল করা হয়েছে। এটি মোটামুটি সুস্পষ্ট যে আপনার শেষে দুটি ছোট উপ-রেঞ্জ থাকতে পারে না।
এমসাল্টার্স

@ এসএমএলটাররা: প্রকৃতপক্ষে। তবে মনে রাখবেন যে কাটা কাটার কারণে অন্য উপায় এখনও ভুগছে। আমার হাইপোথিসিসটি হ'ল পরেরটির জন্য লোকসচাষটি যেহেতু পরিসংখ্যানগত সমস্যাগুলি বোঝা শক্ত fall
বাথশেবা

13

এই উদাহরণ কোডটি চিত্রিত করে যে std::randলিগ্যাসি কার্গো কাল্ট বাল্ডারড্যাশের একটি ঘটনা যা আপনার ভ্রুকে যতবার দেখা হবে ততবার বাড়িয়ে তুলবে।

এখানে বেশ কয়েকটি সমস্যা রয়েছে:

চুক্তির লোকেরা সাধারণত ধরে নেয় - এমনকি দরিদ্র অসহায় আত্মারা যারা আরও ভাল জানেন না এবং অবিকল এই পদগুলিতে এটি ভাববেন না won't তা হল 0, 1, 2,…,, তে পূর্ণসংখ্যার উপর অভিন্ন বিতরণrand থেকে প্রাপ্ত নমুনাগুলি , এবং প্রতিটি কল একটি স্বতন্ত্র নমুনা দেয়।RAND_MAX

প্রথম সমস্যাটি হ'ল ধারণা করা চুক্তি, প্রতিটি কলটিতে স্বতন্ত্র ইউনিফর্মের এলোমেলো নমুনাগুলি আসলে ডকুমেন্টেশন বলে না not এবং বাস্তবে বাস্তবায়নগুলি historতিহাসিকভাবে স্বাধীনতার এমনকি বেস্ট সিমুলাক্রাম সরবরাহ করতে ব্যর্থ হয়েছিল। উদাহরণস্বরূপ, C99 §7.20.2.1 ' randফাংশন' বলছে, বিনা ছাড়াই:

randফাংশন পরিসীমা 0 মধ্যে সিউডো-রেণ্ডম পূর্ণসংখ্যার একটি ক্রম নির্ণয় RAND_MAX

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

সিতে একটি সাধারণ historicalতিহাসিক বাস্তবায়ন এইভাবে কাজ করে:

static unsigned int seed = 1;

static void
srand(unsigned int s)
{
    seed = s;
}

static unsigned int
rand(void)
{
    seed = (seed*1103515245 + 12345) % ((unsigned long)RAND_MAX + 1);
    return (int)seed;
}

এটিতে দুর্ভাগ্যজনক সম্পত্তি রয়েছে যে যদিও একটি একক নমুনা অভিন্ন র্যান্ডম বীজের অধীনে একত্রে বিতরণ করা যেতে পারে (যা এর নির্দিষ্ট মানের উপর নির্ভর করে RAND_MAX), এটি পরপর কলগুলিতে সমান এবং বিজোড় পূর্ণসংখ্যার মধ্যে বিকল্প হয় — পরে

int a = rand();
int b = rand();

(a & 1) ^ (b & 1)100% সম্ভাব্যতার সাথে অভিব্যক্তিটি 1 দেয়, যা সমান এবং বিজোড় পূর্ণসংখ্যার উপর সমর্থনযুক্ত কোনও বিতরণে স্বতন্ত্র এলোমেলো নমুনার ক্ষেত্রে নয় । সুতরাং, একটি কার্গো ধর্মগুচ্ছ উত্থিত হয়েছিল যে 'উন্নত র্যান্ডমনেস' এর অধরা জন্তুটিকে তাড়া করার জন্য লো-অর্ডার বিটগুলি ফেলে দেওয়া উচিত। (স্পোলার সতর্কতা: এটি কোনও প্রযুক্তিগত শব্দ নয় This এটি এমন একটি চিহ্ন যা আপনি যে গদ্যটি পড়ছেন তা তারা কীসের বিষয়ে কথা বলছেন তা জানে না বা মনে করে যে আপনি নিখরচায় রয়েছেন এবং অবশ্যই তাকে অবজ্ঞা করা উচিত))

দ্বিতীয় সমস্যাটি হ'ল এমনকি যদি প্রতিটি কল 0, 1, 2,…, এ অভিন্ন র্যান্ডম বিতরণ থেকে স্বতন্ত্রভাবে নমুনা দেয়RAND_MAX তবে ফলাফলটি rand() % 6ডাই এর মতো 0, 1, 2, 3, 4, 5 এ অভিন্নভাবে বিতরণ করা হত না রোল, যদি না RAND_MAX-1 মডুলো to এর সাথে একত্রে হয় coun সরল পাল্টা নমুনা : যদি RAND_MAX=, হয় তবে তার থেকে rand()সমস্ত ফলাফলের সমান সম্ভাবনা থাকে 1/7, তবে এর থেকে rand() % 6ফলাফল 0 এর সম্ভাব্যতা 2/7 থাকে এবং অন্য সমস্ত ফলাফলের সম্ভাব্যতা থাকে 1/7 ।

এটি করার সঠিক উপায় হ'ল প্রত্যাখ্যানের নমুনা সহ: বার বারs 0, 1, 2,…, থেকে একটি স্বতন্ত্র ইউনিফর্মের এলোমেলো নমুনা আঁকুন RAND_MAXএবং প্রত্যাখ্যান করুন (উদাহরণস্বরূপ) ফলাফলগুলি 0, 1, 2,…, ((RAND_MAX + 1) % 6) - 1- যদি আপনি একটি পেয়ে থাকেন তবে যারা, আবার শুরু; অন্যথায়, ফলন s % 6

unsigned int s;
while ((s = rand()) < ((unsigned long)RAND_MAX + 1) % 6)
    continue;
return s % 6;

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

পছন্দমত যা ফলাফলের যুগ্ম rand()আপনি প্রত্যাখ্যান অশরীরী দেওয়া যে আপনার 6. নীচের প্রতিটি পূর্ণসংখ্যা তাদের একটি সমান সংখ্যা মানচিত্র cppreference.com এ কোড একটি করে তোলে বিভিন্ন প্রথম সমস্যা হওয়ার কারণে, পছন্দ ওপরে যে কিছুই নিশ্চিত করা হয় বিতরণ বা ফলাফলের আউটপুটগুলির স্বাধীনতা rand()এবং অনুশীলনে নিম্ন-অর্ডার বিটগুলি প্রদর্শিত প্রদর্শিত প্যাটার্নগুলিকে 'যথেষ্ট এলোমেলো মনে হয় না' (পরের আউটপুটটি পূর্বেরটির একটি ডিস্ট্রিমেন্টিক ফাংশন মনে করবেন না)।

পাঠকের জন্য অনুশীলন: প্রমাণ করুন যে সিপ্রেফারেন্স ডটকমের কোডটি ডাই রোলসের rand()উপর 0, 1, 2,…, এর উপর অভিন্ন বিতরণ দেয় তবে ডাই রোলসের উপর একটি অভিন্ন বিতরণ দেয় RAND_MAX

পাঠকের জন্য অনুশীলন: আপনি কেন এক বা অন্য সাবটাকে প্রত্যাখ্যান করতে পছন্দ করতে পারেন? দুটি ক্ষেত্রে প্রতিটি বিচারের জন্য কোন গণনার প্রয়োজন?

তৃতীয় সমস্যাটি হ'ল বীজের স্থান এত কম যে এমনকি বীজটি সমানভাবে বিতরণ করা হলেও, একটি শত্রু আপনার প্রোগ্রামের জ্ঞান এবং একটি ফলাফলের সাথে সজ্জিত তবে বীজটি সহজেই বীজ এবং তার পরবর্তী ফলাফলগুলির পূর্বাভাস দিতে পারে, যার ফলে তারা এতটা মনে হয় না makes সব পরে এলোমেলো। এমনকি ক্রিপ্টোগ্রাফির জন্য এটি ব্যবহার করার কথা ভাবেন না।

আপনার চার বছর বয়সী মামাতো ভাইয়ের সাথে std::uniform_int_distributionডাইসে std::mt19937খেলতে আপনি উপযুক্ত র্যান্ডম ডিভাইস এবং আপনার জনপ্রিয় এলোমেলো ইঞ্জিনের মতো জনপ্রিয় র্যান্ডম ইঞ্জিনের সাথে অভিনব ওভাররেঞ্জিনারিড রুট এবং সি ++ 11 এর ক্লাসে যেতে পারেন , তবে তাও যাচ্ছে না ক্রিপ্টোগ্রাফিক কী উপাদান তৈরির জন্য উপযুক্ত হতে পারেন — এবং মার্স্নিন টুইস্টার একটি সিএনপি-র একটি অশ্লীল সেটআপের সময় ক্যাশে মাল্টি-কিলোবাইট স্টেট বিধ্বস্ত করার সাথে একটি ভয়াবহ স্পেস হগও তাই এটি এমনকি খারাপ, যেমন সমান্তরাল মন্টি কার্লো সিমুলেশনগুলির সাথেও খারাপ is উপ-গুণাবলীর পুনরুত্পাদনযোগ্য গাছ; এটির জনপ্রিয়তা সম্ভবত আকর্ষণীয় নাম থেকেই উদ্ভূত হয়। তবে আপনি এটি খেলনা পাশা উদাহরণস্বরূপ ঘূর্ণায়মান জন্য ব্যবহার করতে পারেন!

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


4
"একটি অশ্লীল সেটআপ সময়" আপনি যেভাবেই হোক না কেন একাধিক এলোমেলো সংখ্যা জেনারেটর (প্রতি থ্রেড) ব্যবহার করা উচিত নয়, সুতরাং আপনার প্রোগ্রামটি খুব দীর্ঘ সময় না চালিত হলে সেটআপের সময়টি সীমাবদ্ধ করা হবে।
জ্যাব

2
বিটিডব্লুকে বিভক্ত করে বুঝতে না পেরে যে প্রশ্নটির লুপ ঠিক একই (RAND_MAX + 1 )% 6মানগুলির ঠিক একই প্রত্যাখ্যানের নমুনা করছে । আপনার সম্ভাব্য ফলাফলগুলি কীভাবে আপনার উপ-বিভাগকে বিভক্ত করে তা বিবেচনা করে না । আপনি এগুলি যে কোনও জায়গা থেকে [0, RAND_MAX)এটিকে প্রত্যাখ্যান করতে পারবেন , যতক্ষণ না স্বীকৃত ব্যাপ্তির আকার 6.. এর একাধিক, আপনি কোনও ফলাফল প্রত্যাখ্যান করতে পারেন x>6এবং আপনার %6আর প্রয়োজন হবে না ।
এমসাল্টার্স

12
আমি এই উত্তরটি নিয়ে বেশ খুশি নই। ভাড়াগুলি ভাল হতে পারে তবে আপনি এটিকে ভুল দিকে নিয়ে যাচ্ছেন। উদাহরণস্বরূপ, আপনি অভিযোগ করেন যে "আরও ভাল র্যান্ডমনেস" কোনও প্রযুক্তিগত শব্দ নয় এবং এটি অর্থহীন। এটি অর্ধেক সত্য। হ্যাঁ, এটি কোনও প্রযুক্তিগত শব্দ নয়, তবে এটি প্রসঙ্গে একটি পুরোপুরি অর্থপূর্ণ শর্টহ্যান্ড। এটি বোঝানোর জন্য যে এই জাতীয় পদ ব্যবহারকারীরাই হয় অজ্ঞ বা দূষিত, নিজেই এইগুলির মধ্যে একটি। "ভাল র্যান্ডমনেস" সুনির্দিষ্টভাবে সংজ্ঞায়িত করা খুব শক্ত হতে পারে তবে যখন কোনও ফাংশন আরও ভাল বা খারাপ এলোমেলো বৈশিষ্ট্যের ফলস্বরূপ ফলাফল দেয় তখন তা উপলব্ধি করা সহজ।
কনরাড রুডল্ফ

3
আমি এই উত্তরটি পছন্দ করেছি। এটি কিছুটা কৌতুকপূর্ণ, তবে এটি প্রচুর ভাল পটভূমির তথ্য পেয়েছে। মনে রাখবেন, প্রকৃত বিশেষজ্ঞরা কেবল কখনও হার্ডওয়ার এলোমেলো জেনারেটর ব্যবহার করেন, সমস্যাটি খুব কঠিন।
টাইগার

10
আমার জন্য এটি বিপরীত। যদিও এটিতে ভাল তথ্য রয়েছে, এটি মতামত ব্যতীত অন্য কোনও কিছু হিসাবে আসতে পারে না। উপকারিতা একদিকে।
মিস্টার লিস্টার

2

আমি কোনও উপায়ে অভিজ্ঞ সি ++ ব্যবহারকারী নই, তবে দেখার জন্য আগ্রহী যে অন্য উত্তরগুলি সত্যিকারের std::rand()/((RAND_MAX + 1u)/6)চেয়ে কম পক্ষপাতদুষ্ট বলে বিবেচনা করা হয় কিনা 1+std::rand()%6। সুতরাং আমি উভয় পদ্ধতির জন্য ফলাফলগুলি সারণী করতে একটি পরীক্ষা প্রোগ্রাম লিখেছিলাম (আমি যুগে যুগে সি ++ লিখিনি, দয়া করে এটি পরীক্ষা করে দেখুন)। কোড চালানোর জন্য একটি লিঙ্ক এখানে পাওয়া যায় । এটি নিম্নলিখিত হিসাবে পুনরুত্পাদন:

// Example program
#include <cstdlib>
#include <iostream>
#include <ctime>
#include <string>

int main()
{
    std::srand(std::time(nullptr)); // use current time as seed for random generator

    // Roll the die 6000000 times using the supposedly unbiased method and keep track of the results

    int results[6] = {0,0,0,0,0,0};

    // roll a 6-sided die 20 times
    for (int n=0; n != 6000000; ++n) {
        int x = 7;
        while(x > 6) 
            x = 1 + std::rand()/((RAND_MAX + 1u)/6);  // Note: 1+rand()%6 is biased

        results[x-1]++;
    }

    for (int n=0; n !=6; n++) {
        std::cout << results[n] << ' ';
    }

    std::cout << "\n";


    // Roll the die 6000000 times using the supposedly biased method and keep track of the results

    int results_bias[6] = {0,0,0,0,0,0};

    // roll a 6-sided die 20 times
    for (int n=0; n != 6000000; ++n) {
        int x = 7;
        while(x > 6) 
            x = 1 + std::rand()%6;

        results_bias[x-1]++;
    }

    for (int n=0; n !=6; n++) {
        std::cout << results_bias[n] << ' ';
    }
}

এরপরে আমি এর আউটপুট নিয়েছি এবং ফলাফল chisq.testপ্রত্যাশার চেয়ে উল্লেখযোগ্যভাবে পৃথক কিনা তা দেখতে চি-বর্গ পরীক্ষা চালাতে আর-তে ফাংশনটি ব্যবহার করেছি । এই স্ট্যাকেক্সচেঞ্জ প্রশ্নটি ডাই ফেয়ারনেস পরীক্ষা করতে চি-স্কোয়ার টেস্ট ব্যবহারের আরও বিশদে চলে যায়: ডাই সুষ্ঠু কিনা তা আমি কীভাবে পরীক্ষা করতে পারি? । কয়েকটি রানের ফলাফল এখানে:

> ?chisq.test
> unbias <- c(100150, 99658, 100319, 99342, 100418, 100113)
> bias <- c(100049, 100040, 100091, 99966, 100188, 99666 )

> chisq.test(unbias)

Chi-squared test for given probabilities

data:  unbias
X-squared = 8.6168, df = 5, p-value = 0.1254

> chisq.test(bias)

Chi-squared test for given probabilities

data:  bias
X-squared = 1.6034, df = 5, p-value = 0.9008

> unbias <- c(998630, 1001188, 998932, 1001048, 1000968, 999234 )
> bias <- c(1000071, 1000910, 999078, 1000080, 998786, 1001075   )
> chisq.test(unbias)

Chi-squared test for given probabilities

data:  unbias
X-squared = 7.051, df = 5, p-value = 0.2169

> chisq.test(bias)

Chi-squared test for given probabilities

data:  bias
X-squared = 4.319, df = 5, p-value = 0.5045

> unbias <- c(998630, 999010, 1000736, 999142, 1000631, 1001851)
> bias <- c(999803, 998651, 1000639, 1000735, 1000064,1000108)
> chisq.test(unbias)

Chi-squared test for given probabilities

data:  unbias
X-squared = 7.9592, df = 5, p-value = 0.1585

> chisq.test(bias)

Chi-squared test for given probabilities

data:  bias
X-squared = 2.8229, df = 5, p-value = 0.7273

আমি যে তিনটি রান করেছিলাম, উভয় পদ্ধতির জন্য p- মান সর্বদা তাত্পর্য (0.05) পরীক্ষা করতে ব্যবহৃত আলফা মানগুলির চেয়ে বেশি ছিল greater এর অর্থ হ'ল আমরা তাদের উভয়কেই পক্ষপাতদুষ্ট বলে বিবেচনা করব না। মজার বিষয় হল, ধারণা করা হয় নিরপেক্ষ পদ্ধতিতে ধারাবাহিকভাবে কম পি-মান রয়েছে যা এটি ইঙ্গিত দেয় যে এটি সম্ভবত আরও পক্ষপাতদুষ্ট হতে পারে। সাবধানতা অবলম্বন করা হচ্ছে যে আমি কেবল 3 রান করেছি।

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

মূলত, সংক্ষেপে, তিনি কেবলমাত্র সঠিক বীজ এবং পরীক্ষাগুলির সংখ্যা পাওয়ার জন্য ঘটলেন যার ফলে তিনি কোনও ভুল ফল পাচ্ছেন।


তোমার বাস্তবায়ন আপনার পক্ষ থেকে একটি ভুল বোঝাবুঝি কারণে মারাত্মক ত্রুটি রয়েছে: উদ্ধৃত উত্তরণ হয় না তুলনা rand()%6সঙ্গে rand()/(1+RAND_MAX)/6। বরং, এটি প্রত্যাহারের নমুনার সাথে বাকী অংশটি সরাসরি গ্রহণের সাথে তুলনা করছে (ব্যাখ্যাটির জন্য অন্যান্য উত্তর দেখুন)। ফলস্বরূপ, আপনার দ্বিতীয় কোডটি ভুল ( whileলুপটি কিছুই করে না)। আপনার পরিসংখ্যানগত পরীক্ষারও সমস্যা রয়েছে (আপনি কেবল দৃ rob়তার জন্য আপনার পরীক্ষার পুনরাবৃত্তি চালাতে পারবেন না, আপনি সংশোধন করেননি,…)।
কনরাড রুডল্ফ

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

আমি আসলে পুনরাবৃত্তি চালানো। ইচ্ছাকৃতভাবে বীজ সেট করা হয়নি যেহেতু একটি মানহীন বীজ std::srand(এবং এর ব্যবহার না করে <random>) দিয়ে একটি এলোমেলো বীজ স্থাপন করা বেশ শক্ত এবং এটির কোডটি বাদ দিয়ে বাকী কোড থেকে সরে যেতে চাই না। এটি গণনার ক্ষেত্রেও অপ্রাসঙ্গিক: সিমুলেশনে একই ক্রমের পুনরাবৃত্তি সম্পূর্ণভাবে গ্রহণযোগ্য। অবশ্যই বিভিন্ন বীজ হবে ভিন্ন ফলাফল উত্পাদ, এবং কিছু অ উল্লেখযোগ্য হতে হবে। পি-ভ্যালু কীভাবে সংজ্ঞায়িত হয় তার ভিত্তিতে এটি সম্পূর্ণ প্রত্যাশিত।
কনরাড রুডল্ফ

1
ইঁদুর, আমি আমার পুনরাবৃত্তিতে একটি ভুল করেছি; এবং আপনি ঠিক বলেছেন, পুনরাবৃত্ত রানগুলির 95 তম কোয়ান্টাইল পি = 0.05 এর খুব কাছাকাছি - অর্থাত্ ঠিক তখন আমরা যা প্রত্যাশা করব তা বাতিল হয়ে যাবে। সংক্ষেপে, আমার স্ট্যান্ডার্ড গ্রন্থাগার প্রয়োগের std::randফলন উল্লেখযোগ্যভাবে ভাল কয়েন টস সিমুলেশনগুলি একটি ডি 6 এর জন্য এলোমেলো বীজের পরিসীমা জুড়ে।
কনরাড রুদল্ফ

1
পরিসংখ্যানগত তাত্পর্য গল্পের একটি অংশ। আপনার কাছে নাল হাইপোথিসিস (অভিন্নভাবে বিতরণ করা) এবং একটি বিকল্প অনুমান (মডুলো পক্ষপাত) আছে - আসলে বিকল্প অনুমানের একটি পরিবার, পছন্দ অনুসারে সূচিত RAND_MAX, যা মডুলো পক্ষপাতিত্বের প্রভাব আকার নির্ধারণ করে । পরিসংখ্যানগত তাত্পর্য হ'ল নাল অনুমানের অধীনে সম্ভাবনা যা আপনি এটিকে মিথ্যাভাবে প্রত্যাখ্যান করেন। পরিসংখ্যানগত শক্তি কী - একটি বিকল্প অনুমানের অধীনে সম্ভাবনা যা আপনার পরীক্ষা নাল অনুমানটি সঠিকভাবে প্রত্যাখ্যান করে? rand() % 6RAND_MAX = 2 ^ 31 - 1 এ আপনি কি এইভাবে সনাক্ত করতে পারবেন ?
স্কাইয়ামিশ অসিফ্রেজ

2

বাইনারি অঙ্কের একটি স্ট্রিম হিসাবে কাজ করা হিসাবে কোনও এলোমেলো নম্বর জেনারেটর সম্পর্কে ভাবতে পারে। জেনারেটরটি স্ট্রम्सটিকে টুকরো টুকরো করে কাটা দিয়ে সংখ্যায় পরিণত করে। যদি std:randফাংশনটি RAND_MAX32767 এর সাথে কাজ করে , তবে এটি প্রতিটি স্লাইসে 15 বিট ব্যবহার করছে।

যখন কোনও সংখ্যার মডিউলগুলি 0 এবং 32767 সমেত অন্তর্ভুক্ত করে তখন তারা দেখতে পায় যে 5462 '0 এবং' 1 এর মধ্যে কেবল 5461 '2', '3', '4' এবং '5 এর রয়েছে। সুতরাং ফলাফল পক্ষপাতদুষ্ট। RAND_MAX মানটি যত বড় হবে তত কম পক্ষপাত হবে, তবে এটি অনিবার্য।

যা পক্ষপাতদুষ্ট নয় তা হ'ল একটি পরিসীমা [0 .. (2 ^ n) -1]। আপনি 3 বিট বের করে, 0..7 রেঞ্জের পূর্ণসংখ্যায় রূপান্তর করে এবং 6 এবং 7 প্রত্যাখ্যান করে 0..5 পরিসরে একটি (তাত্ত্বিকভাবে) আরও ভাল নম্বর তৈরি করতে পারেন।

কেউ আশা করে যে বিট স্ট্রিমের প্রতিটি বিটের যেখানেই এটি স্ট্রিমে বা অন্য বিটের মানগুলি নির্বিশেষে '0' বা '1' হওয়ার সমান সুযোগ রয়েছে। এটি অনুশীলনে ব্যতিক্রমীভাবে কঠিন। সফটওয়্যার PRNGs বিভিন্ন বিভিন্ন বাস্তবায়ন গতি এবং মানের মধ্যে বিভিন্ন আপস প্রস্তাব। একটি লিনিয়ার কংগ্রেসিভ জেনারেটর যেমন std::randসর্বনিম্ন মানের জন্য দ্রুত গতি সরবরাহ করে। একটি ক্রিপ্টোগ্রাফিক জেনারেটর সর্বনিম্ন গতির জন্য সর্বোচ্চ মানের প্রস্তাব দেয়।

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