লোকেরা কেন এলোমেলো সংখ্যার জেনারেটর ব্যবহার করার সময় সেখানে মডুলো পক্ষপাতিত্ব রয়েছে?


277

আমি এই প্রশ্নটি অনেক জিজ্ঞাসা করে দেখেছি তবে এর সত্যিকারের সঠিক উত্তর কখনও দেখেনি। সুতরাং আমি এখানে একটি পোস্ট করতে যাচ্ছি যাতে আশা করা rand()যায় যে সি ++ এর মতো একটি এলোমেলো সংখ্যার জেনারেটর ব্যবহার করার সময় কেন "মডুলো পক্ষপাত" ঠিক আছে তা লোকেদের বুঝতে সাহায্য করবে ।

উত্তর:


394

সুতরাং rand()একটি সিউডো-রেণ্ডম সংখ্যা উত্পাদক যা 0 মধ্যে একটি প্রাকৃতিক সংখ্যা বেছে এবং RAND_MAX, যা একটি ধ্রুবক সংজ্ঞায়িত হয় cstdlib(এই দেখতে নিবন্ধ একটি সাধারণ ওভারভিউ জন্যrand() )।

এখন আপনি যদি 0 এবং 2 বলার মধ্যে একটি এলোমেলো সংখ্যা তৈরি করতে চান তবে কি হবে? ব্যাখ্যার খাতিরে, ধরুন RAND_MAX10 এবং আমি কল করে 0 এবং 2 এর মধ্যে একটি এলোমেলো সংখ্যা উত্পন্ন করার সিদ্ধান্ত নিয়েছি rand()%3। তবে, rand()%3সমান সম্ভাব্যতার সাথে 0 এবং 2 এর মধ্যে সংখ্যা তৈরি করে না!

rand()0, 3, 6, বা 9, যখন ফেরত দেয় rand()%3 == 0 । সুতরাং, পি (0) = 4/11

যখন rand()1, 4, 7 বা 10, ফেরত দেয় rand()%3 == 1 । সুতরাং, পি (1) = 4/11

rand()2, 5, বা 8, যখন রিটার্ন দেয় rand()%3 == 2 । সুতরাং, পি (2) = 3/11

এটি সমান সম্ভাবনার সাথে 0 এবং 2 এর মধ্যে সংখ্যা উত্পন্ন করে না। অবশ্যই ছোট পরিসরের জন্য এটি সবচেয়ে বড় সমস্যা নাও হতে পারে তবে বৃহত্তর পরিসরের জন্য এটি বিতরণকে কমিয়ে দিতে পারে, ছোট সংখ্যার পক্ষপাতিত্ব করে।

সুতরাং rand()%nসমান সম্ভাবনার সাথে কখন 0 থেকে এন -1 এ সংখ্যার একটি পরিসর ফেরত দেবে? যখন RAND_MAX%n == n - 1। এই ক্ষেত্রে, আমাদের আগের অনুমানের সাথে rand()0 এবং RAND_MAXসমান সম্ভাবনার সাথে একটি সংখ্যা ফিরে আসে , n এর মডুলো ক্লাসগুলিও সমানভাবে বিতরণ করা হবে।

তাহলে আমরা কীভাবে এই সমস্যার সমাধান করব? একটি অপরিশোধিত উপায় হ'ল আপনার পছন্দসই পরিসরে একটি নম্বর না পাওয়া পর্যন্ত এলোমেলো সংখ্যা উত্পন্ন করা অবধি:

int x; 
do {
    x = rand();
} while (x >= n);

তবে এটি নিম্ন মানের জন্য অকার্যকর n, যেহেতু আপনার কেবলমাত্র n/RAND_MAXআপনার সীমার মধ্যে একটি মূল্য পাওয়ার সম্ভাবনা রয়েছে এবং তাই আপনাকে গড়ে RAND_MAX/nকল করতে rand()হবে।

একটি আরও দক্ষ সূত্র পদ্ধতির জন্য দৈর্ঘ্য দ্বারা বিস্তৃত কিছু বৃহত্তর পরিসর গ্রহণ করা হবে n, যেমন RAND_MAX - RAND_MAX % n, এলোমেলো সংখ্যা তৈরি করা অবিরত রাখুন যতক্ষণ না আপনি পরিসীমাটিতে থাকা একটি পেয়ে যান এবং তারপরে মডুলাসটি গ্রহণ করেন:

int x;

do {
    x = rand();
} while (x >= (RAND_MAX - RAND_MAX % n));

x %= n;

ছোট মানগুলির জন্য n, এটির জন্য খুব কমই একাধিক কল প্রয়োজন হবে rand()


কাজ উদ্ধৃত এবং আরও পড়া:



6
RAND_MAX%n == n - 1__ সম্পর্কে ভাবনার আরেকটি উপায় (RAND_MAX + 1) % n == 0। কোড পড়ার সময়, আমি % something == 0এটি গণনার অন্যান্য পদ্ধতির চেয়ে আরও সহজেই "সমানভাবে বিভাজক" হিসাবে বুঝতে আগ্রহী । অবশ্যই, আপনার সি ++ stdlib হয়েছে থাকে RAND_MAXহিসাবে একই মান হিসাবে INT_MAX, (RAND_MAX + 1)নিশ্চয় কাজ করবে না; সুতরাং মার্কের গণনাটি নিরাপদ বাস্তবায়ন থেকে যায়।
স্লিপ ডি থম্পসন

খুব সুন্দর উত্তর!
সায়ালী সোনাওয়ান

আমি নীটপিকিং করতে পারি, তবে লক্ষ্য যদি নষ্ট বিটগুলি হ্রাস করা হয় তবে আমরা প্রান্তের অবস্থার জন্য এটি সামান্য উন্নতি করতে পারলাম যেখানে RAND_MAX (আরএম) এন দ্বারা সমানভাবে বিভাজক হওয়ার চেয়ে মাত্র 1 কম। এই পরিস্থিতিতে, কোনও বিট দ্বারা নষ্ট হওয়ার দরকার নেই where এক্স> = (আরএম - আরএম% এন) করছেন যা এন এর ছোট মানগুলির জন্য খুব কম মূল্য, তবে এন এর বড় মানগুলির জন্য বৃহত্তর মান হয়ে যায় S স্লিপ ডি থম্পসন যেমন উল্লেখ করেছেন, একটি সমাধান রয়েছে যা কেবলমাত্র কাজ করবে যখন INT_MAX (IM)> RAND_MAX তবে যখন তারা সমান হয় তখন ব্রেক হয়। তবে এর জন্য একটি সহজ সমাধান রয়েছে যা আমরা X> = (আরএম - আরএম% এন) হিসাবটি নিম্নরূপে সংশোধন করতে পারি:
বেন পারসোনিক

এক্স> = আরএম - (((আরএম% এন) + 1)% এন)
বেন পারসোনিক

সমস্যাটির বিশদ বর্ণনা করে এবং উদাহরণ কোড সমাধান দিয়ে একটি অতিরিক্ত উত্তর পোস্ট করেছি giving
বেন পারসোনিক

36

একটি এলোমেলো নির্বাচন নির্বাচন পক্ষপাত অপসারণ করার একটি ভাল উপায়।

হালনাগাদ

আমরা কোডটি দ্রুত তৈরি করতে পারতাম যদি আমরা কোনও এক্সকে রেঞ্জ দ্বারা বিভাজ্য অনুসন্ধান করি n

// Assumptions
// rand() in [0, RAND_MAX]
// n in (0, RAND_MAX]

int x; 

// Keep searching for an x in a range divisible by n 
do {
    x = rand();
} while (x >= RAND_MAX - (RAND_MAX % n)) 

x %= n;

উপরের লুপটি খুব দ্রুত হওয়া উচিত, গড়ে ১ টি পুনরাবৃত্তি বলুন।


2
ইয়াক :- পি ডাবলে রূপান্তর করা, তারপরে MAX_UPPER_LIMIT / RAND_MAX দ্বারা গুণ করা অনেক বেশি পরিষ্কার এবং আরও ভাল সম্পাদন করে।
বালক

22
@ বয়সি: আপনি বিষয়টি মিস করেছেন। যদি মানগুলি যে rand()ফিরে আসতে পারে তার সংখ্যা যদি একাধিক না হয় n, তবে আপনি যা-ই করুন না কেন আপনি অবশ্যম্ভাবীভাবে 'মডুলো বায়াস' পাবেন, যদি না আপনি সেই মানগুলির কিছুটি বাদ দেন। ব্যবহারকারী 1413793 এটি দুর্দান্তভাবে ব্যাখ্যা করেছে (যদিও উত্তরটিতে প্রস্তাবিত সমাধানটি সত্যই ইয়কি)।
টনিকে

4
টোনিকে আমার ক্ষমা চাই, আমি এই বিষয়টিটি মিস করলাম না। যথেষ্ট কঠোর ভাবেননি, এবং ভেবেছিলেন যে পক্ষপাত কেবলমাত্র একটি স্পষ্ট মডুলাস অপারেশন ব্যবহারের পদ্ধতিতে প্রয়োগ করা হবে। আমাকে ঠিক করার জন্য ধন্যবাদ :-)
বয়সি

অপারেটর অগ্রাধিকার RAND_MAX+1 - (RAND_MAX+1) % nসঠিকভাবে কাজ করে তবে আমি এখনও মনে করি এটি RAND_MAX+1 - ((RAND_MAX+1) % n)স্পষ্টতা হিসাবে লেখা উচিত ।
লিনাস আরভার

4
এটি RAND_MAX == INT_MAX (বেশিরভাগ সিস্টেমে যেমন হয় তেমন) কাজ করবে না । উপরের @ ব্যবহারকারী 1413793- এ আমার দ্বিতীয় মন্তব্য দেখুন।
ব্লুরাজা - ড্যানি পিফ্লুঘিওফট

19

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

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

আবার, সর্বোত্তম সমাধানটি কেবল এটি সরবরাহ arc4random_uniformকরে এমন প্ল্যাটফর্মগুলিতে ব্যবহার করা বা আপনার প্ল্যাটফর্মের জন্য অনুরূপ সীমাবদ্ধ সমাধান (যেমন Random.nextIntজাভাতে)। এটি আপনাকে কোনও কোড ব্যয় না করে সঠিক কাজ করবে। এটি প্রায় সবসময় সঠিক কল করা is

আপনার যদি না থাকে arc4random_uniform, তবে আপনি কীভাবে এটি বিস্তৃত পরিসীমা আরএনজির শীর্ষে প্রয়োগ করা হয় ঠিক তা দেখার জন্য ওপেনসোর্সের শক্তিটি ব্যবহার করতে পারেন ( ar4randomএই ক্ষেত্রে, তবে অনুরূপ পদ্ধতি অন্যান্য আরএনজির উপরেও কাজ করতে পারে)।

ওপেনবিএসডি বাস্তবায়ন এখানে :

/*
 * Calculate a uniformly distributed random number less than upper_bound
 * avoiding "modulo bias".
 *
 * Uniformity is achieved by generating new random numbers until the one
 * returned is outside the range [0, 2**32 % upper_bound).  This
 * guarantees the selected random number will be inside
 * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
 * after reduction modulo upper_bound.
 */
u_int32_t
arc4random_uniform(u_int32_t upper_bound)
{
    u_int32_t r, min;

    if (upper_bound < 2)
        return 0;

    /* 2**32 % x == (2**32 - x) % x */
    min = -upper_bound % upper_bound;

    /*
     * This could theoretically loop forever but each retry has
     * p > 0.5 (worst case, usually far better) of selecting a
     * number inside the range we need, so it should rarely need
     * to re-roll.
     */
    for (;;) {
        r = arc4random();
        if (r >= min)
            break;
    }

    return r % upper_bound;
}

যারা এই জাতীয় জিনিস বাস্তবায়নের প্রয়োজন তাদের জন্য এই কোডটিতে সর্বশেষ প্রতিশ্রুতিবদ্ধ মন্তব্যটি লক্ষ্য করার মতো:

2**32 % upper_boundহিসাবে গণনা করতে arc4random_uniform () পরিবর্তন করুন -upper_bound % upper_bound। কোডটি সরল করে আইএলপি 32 এবং এলপি 64 উভয় আর্কিটেকচারে এটি একই করে তোলে এবং P৪-বিটের অবশিষ্টের পরিবর্তে ৩২-বিট অবশিষ্টের ব্যবহার করে এলপি architect64 আর্কিটেকচারে কিছুটা দ্রুত।

জর্ডেন ভার্ওয়ার দ্বারা প্রযুক্তিতে @ ওকে ডেরাডে প্রেরিত; ডিজেএম বা অটো থেকে কোনও আপত্তি নেই

জাভা বাস্তবায়নও সহজে খুঁজে পাওয়া যায় (আগের লিঙ্কটি দেখুন):

public int nextInt(int n) {
   if (n <= 0)
     throw new IllegalArgumentException("n must be positive");

   if ((n & -n) == n)  // i.e., n is a power of 2
     return (int)((n * (long)next(31)) >> 31);

   int bits, val;
   do {
       bits = next(31);
       val = bits % n;
   } while (bits - val + (n-1) < 0);
   return val;
 }

মনে রাখবেন যে arcfour_random() বাস্তবায়নের ক্ষেত্রে যদি প্রকৃত আরসি 4 অ্যালগরিদম ব্যবহার করে তবে আউটপুটটিতে অবশ্যই কিছু পক্ষপাত থাকবে। আশা করি আপনার লাইব্রেরি লেখকরা একই ইন্টারফেসের পিছনে আরও ভাল সিএসপিআরএনজি ব্যবহার শুরু করেছেন। আমি মনে করি বিএসডিগুলির একটি এখন বাস্তবায়নের জন্য চ্যাচ2020 অ্যালগরিদম ব্যবহার করে arcfour_random()। : RC4 আউটপুট গোঁড়ামির যা নিরাপত্তা বা এই ধরনের ভিডিও জুজু হিসাবে অন্যান্য সমালোচনামূলক অ্যাপ্লিকেশনের জন্য বেহুদা রেন্ডার আরো blog.cryptographyengineering.com/2013/03/...
rmalayter

2
@rmalayter আইওএস এবং ওএস এক্স-তে, আরক 4 ব্র্যান্ডম / dev / এলোমেলো থেকে পড়ে যা সিস্টেমের সর্বোচ্চ মানের এনট্রপি। (নামের "আরক 4" historicতিহাসিক এবং সামঞ্জস্যের জন্য সংরক্ষিত।)
রব নেপিয়ার

@ রব_নেপিয়ার জেনে রাখা ভাল, তবে /dev/randomঅতীতে কিছু প্ল্যাটফর্মগুলিতে আরসি 4 ব্যবহার করেছেন (লিনাক্স কাউন্টার মোডে SHA-1 ব্যবহার করে)। দুর্ভাগ্যক্রমে আমি অনুসন্ধানের মাধ্যমে যে ম্যান পেজগুলি পেয়েছি সেগুলি ইঙ্গিত করে যে আরসি 4 এখনও বিভিন্ন প্ল্যাটফর্মগুলিতে ব্যবহার করে arc4random(যদিও প্রকৃত কোডটি ভিন্ন হতে পারে)।
rmalayter

1
আমি বিভ্রান্ত তাই না -upper_bound % upper_bound == 0??
জন ম্যাকক্লাং

1
@ জোনমিসক্লুং -upper_bound % upper_boundসত্যিই 0 হবে যদি int32-বিটের চেয়ে প্রশস্ত হয়। এটি হওয়া উচিত (u_int32_t)-upper_bound % upper_bound)(ধরে u_int32_tনেওয়া একটি বিএসডি-ইস্মের জন্য uint32_t)।
ইয়ান অ্যাবট

14

সংজ্ঞা

মডুলো বায়াস হ'ল ইনপুট সেটটির একটি উপসেটে একটি আউটপুট সেট হ্রাস করার জন্য মডুলো গাণিতিক ব্যবহারের অন্তর্নিহিত পক্ষপাত। সাধারণভাবে, যখনই ইনপুট এবং আউটপুট সেটগুলির মধ্যে ম্যাপিং সমানভাবে বিতরণ করা হয় না তখন একটি পক্ষপাতিত্ব উপস্থিত থাকে, যেমন আউটপুট সেটটির আকার যখন ইনপুট সেটের আকারের বিভাজক না হয় তখন মডুলো গাণিতিক ব্যবহারের ক্ষেত্রে।

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

সমস্যার উদাহরণ

আসুন এই র্যান্ডম বিটগুলি ব্যবহার করে ডাই রোল (0 থেকে 5) সিমুলেট করার বিষয়টি বিবেচনা করুন। 6 টি সম্ভাবনা রয়েছে, সুতরাং 6 নম্বরটি উপস্থাপন করার জন্য আমাদের পর্যাপ্ত বিট প্রয়োজন, যা 3 বিট। দুর্ভাগ্যক্রমে, 3 টি এলোমেলো বিট 8 সম্ভাব্য ফলাফল দেয়:

000 = 0, 001 = 1, 010 = 2, 011 = 3
100 = 4, 101 = 5, 110 = 6, 111 = 7

মান মডিউল 6 গ্রহণের মাধ্যমে আমরা ঠিক ফলাফলের আকারটি হ্রাস করতে পারি, তবে এটি মডুলো পক্ষপাতিত্বের সমস্যাটি উপস্থাপন করে : 110একটি 0 দেয় এবং 111একটি ফলন দেয় This এই ডাইটি লোড হয়।

সম্ভাব্য সমাধান

পদ্ধতির 0:

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

পন্থা 1:

পরিবর্তে মডুলাস ব্যবহার, একটি সরল কিন্তু গাণিতিকভাবে সঠিক সমাধান ফলন বাতিল ফলাফল হয় 110এবং 111কেবল 3 টি নতুন বিটের সাথে আবার চেষ্টা করুন। দুর্ভাগ্যক্রমে, এর অর্থ হ'ল প্রতিটি রোলটিতে 25% সুযোগ রয়েছে যা পুনরায় রোলগুলির প্রত্যেকটি নিজেরাই অন্তর্ভুক্ত করে একটি পুনরায় রোলের প্রয়োজন হবে। এটি ব্যবহারের সবচেয়ে তুচ্ছ ব্যতীত সকলের জন্য স্পষ্টতই অবৈধ is

পদ্ধতির 2:

আরও বিট ব্যবহার করুন: 3 বিটের পরিবর্তে, 4 ব্যবহার করুন 16 এটি 16 সম্ভাব্য ফলাফল দেয়। অবশ্যই, ফলাফলের চেয়ে যে কোনও সময় পুনরায় ঘূর্ণায়মান 5 টিরও বেশি খারাপকে খারাপ করে তোলে (10/16 = 62.5%) যাতে একা সাহায্য না করে।

লক্ষ্য করুন যে 2 * 6 = 12 <16, তাই আমরা নিরাপদে 12 এর চেয়ে কম যে কোনও ফলাফল নিতে পারি এবং ফলাফলটি সমানভাবে বিতরণ করতে সেই মডুলো 6 হ্রাস করতে পারি। অন্যান্য 4 টি ফলাফল অবশ্যই বাতিল করতে হবে এবং তারপরে আগের পদ্ধতির মতো পুনরায় ঘূর্ণিত হবে।

প্রথমে ভাল লাগছে, তবে গণিতটি যাচাই করে দেখি:

4 discarded results / 16 possibilities = 25%

এই ক্ষেত্রে, 1 অতিরিক্ত বিট মোটেও সহায়তা করেনি !

ফলাফলটি দুর্ভাগ্যজনক, তবে আসুন 5 টি বিট দিয়ে আবার চেষ্টা করুন:

32 % 6 = 2 discarded results; and
2 discarded results / 32 possibilities = 6.25%

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

যদিও প্রদর্শিত হয়েছে , একটি অতিরিক্ত 1 বিট যুক্ত করা কোনও পরিবর্তন করতে পারে না। প্রকৃতপক্ষে যদি আমরা আমাদের রোলটি 6 বিটে বৃদ্ধি করি তবে সম্ভাবনা 6.25% থেকে যায়।

এটি আরও 2 টি প্রশ্ন জিজ্ঞাসা করে:

  1. যদি আমরা পর্যাপ্ত পরিমাণে বিট যোগ করি, তবে কি গ্যারান্টি রয়েছে যে বাতিল করার সম্ভাবনা হ্রাস পাবে?
  2. সাধারণ ক্ষেত্রে কত বিট যথেষ্ট ?

সাধারণ সমাধান

ধন্যবাদ প্রথম প্রশ্নের উত্তর হ্যাঁ। 6 এর সাথে সমস্যাটি 2 2 x x 6 6 2 এবং 4 এর মধ্যে ফ্লিপ হয় যা কাকতালীয়ভাবে একে অপরের থেকে 2 এর একাধিক হয়, যাতে এমনকি x> 1 এর জন্যও,

[2^x mod 6] / 2^x == [2^(x+1) mod 6] / 2^(x+1)

সুতরাং 6 নিয়মের পরিবর্তে ব্যতিক্রম। একইভাবে 2 টির পরপর শক্তি পাওয়া যায় এমন বৃহত মডুলি সন্ধান করা সম্ভব তবে অবশেষে এটি অবশ্যই চারপাশে আবৃত হবে এবং বাতিল করার সম্ভাবনা হ্রাস পাবে।

আরও প্রমাণ না দিয়ে, সাধারণভাবে প্রয়োজনীয় বিটের দ্বিগুণ ব্যবহার করা একটি ছোট, সাধারণত তুচ্ছ, বাতিল করার সুযোগ সরবরাহ করে।

ধারণার প্রমাণ

এখানে একটি উদাহরণ প্রোগ্রাম যা এলোমেলো বাইট সরবরাহের জন্য ওপেনএসএসএল এর লাইবক্রিপো ব্যবহার করে। সংকলন করার সময়, যে লাইব্রেরির সাথে -lcryptoসর্বাধিক প্রত্যেকের উপলব্ধ থাকা উচিত তা লিঙ্ক করতে ভুলবেন না।

#include <iostream>
#include <assert.h>
#include <limits>
#include <openssl/rand.h>

volatile uint32_t dummy;
uint64_t discardCount;

uint32_t uniformRandomUint32(uint32_t upperBound)
{
    assert(RAND_status() == 1);
    uint64_t discard = (std::numeric_limits<uint64_t>::max() - upperBound) % upperBound;
    uint64_t randomPool = RAND_bytes((uint8_t*)(&randomPool), sizeof(randomPool));

    while(randomPool > (std::numeric_limits<uint64_t>::max() - discard)) {
        RAND_bytes((uint8_t*)(&randomPool), sizeof(randomPool));
        ++discardCount;
    }

    return randomPool % upperBound;
}

int main() {
    discardCount = 0;

    const uint32_t MODULUS = (1ul << 31)-1;
    const uint32_t ROLLS = 10000000;

    for(uint32_t i = 0; i < ROLLS; ++i) {
        dummy = uniformRandomUint32(MODULUS);
    }
    std::cout << "Discard count = " << discardCount << std::endl;
}

আমি বেশিরভাগ শর্তে কতগুলি রি-রোল আসলে ঘটে তা দেখার জন্য MODULUSএবং ROLLSমানগুলির সাথে খেলতে উত্সাহিত করি । সন্দেহবাদী ব্যক্তি ফাইলটি গণনা করা মানগুলি সংরক্ষণ করতে এবং বিতরণটি স্বাভাবিকভাবে প্রদর্শিত হবে কিনা তা যাচাই করতে পারে।


আমি সত্যিই আশা করি কেউ আপনার অভিন্ন র্যান্ডম বাস্তবায়ন অন্ধভাবে অনুলিপি করেনি। randomPool = RAND_bytes(...)লাইন সবসময় পরিণাম ডেকে আনবে randomPool == 1কথন কারণে। এটি সর্বদা বাতিল এবং পুনরায় রোলের ফলস্বরূপ। আমি মনে করি আপনি একটি পৃথক লাইনে ঘোষণা করতে চেয়েছিলেন। ফলস্বরূপ, এর ফলে 1প্রতিটি পুনরাবৃত্তির জন্য আরএনজি ফিরে আসে ।
কিউস - মোনিকা

পরিষ্কার হওয়ার জন্য , ওপেনএসএসএল ডকুমেন্টেশন অনুসারে randomPoolসর্বদা মূল্যায়ন করা হবে কারণ এটি সর্বদা দৃ .়তার সাথে ধন্যবাদ বলে সফল হবে । 1RAND_bytes()RAND_status()
কিউস - মোনিকা

9

মডুলো ব্যবহার নিয়ে দুটি স্বাভাবিক অভিযোগ রয়েছে।

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

  • কিছু ধরণের জেনারেটরের কম পরিমাণে কিছু প্যারামিটারের তুলনায় তাদের কম উল্লেখযোগ্য বিটগুলি কম এলোমেলো করে থাকে তবে দুঃখের বিষয় those পরামিতিগুলির মধ্যে আরও একটি আকর্ষণীয় বৈশিষ্ট্য রয়েছে (যেমন 2 এর পাওয়ার চেয়ে RAND_MAX কম থাকতে সক্ষম হয়েছে)। সমস্যাটি সুপরিচিত এবং দীর্ঘ সময়ের জন্য গ্রন্থাগার বাস্তবায়ন সম্ভবত সমস্যা এড়াতে পারে (উদাহরণস্বরূপ সি স্ট্যান্ডার্ডে নমুনা র্যান্ড () প্রয়োগটি এই ধরণের জেনারেটর ব্যবহার করে তবে ১ less টি কম উল্লেখযোগ্য বিট ফেলে দেয়) তবে কেউ কেউ অভিযোগ করতে চান যে এবং আপনার ভাগ্য হতে পারে

মত কিছু ব্যবহার

int alea(int n){ 
 assert (0 < n && n <= RAND_MAX); 
 int partSize = 
      n == RAND_MAX ? 1 : 1 + (RAND_MAX-n)/(n+1); 
 int maxUsefull = partSize * n + (partSize-1); 
 int draw; 
 do { 
   draw = rand(); 
 } while (draw > maxUsefull); 
 return draw/partSize; 
}

0 এবং n এর মধ্যে একটি এলোমেলো সংখ্যা তৈরি করতে উভয় সমস্যা এড়ানো হবে (এবং এটি RAND_MAX == INT_MAX দিয়ে উপচে পড়া এড়ানো)

বিটিডাব্লু, সি ++ 11 র্যান্ড () এর চেয়ে হ্রাস এবং অন্যান্য জেনারেটরের স্ট্যান্ডার্ড উপায়গুলি প্রবর্তন করেছিল।


n == RAND_MAX? 1: (RAND_MAX-1) / (n + 1): আমি এখানে ধারণাটি বুঝতে পারি যে প্রথমে RAND_MAX কে সমান পৃষ্ঠার আকার N তে ভাগ করে নেওয়া উচিত, তারপরে N এর মধ্যে বিচ্যুতি ফিরিয়ে আনতে হবে, তবে আমি কোডটি এইটিতে ঠিক ম্যাপ করতে পারি না।
zinking

1
নিষ্ক্রিয় সংস্করণটি (RAND_MAX + 1) / (n + 1) হওয়া উচিত কারণ এন +1 বালতিতে ভাগ করার জন্য RAND_MAX + 1 মান রয়েছে। RAND_MAX + 1 গণনা করার সময় যদি ওভারফ্লো এড়ানোর জন্য আদেশ করা হয় তবে এটি 1+ (RAND_MAX-n) / (n + 1) এ রূপান্তরিত হতে পারে। N + 1 গণনা করার সময় ওভারফ্লো এড়ানোর জন্য, কেস n == RAND_MAX প্রথমে চেক করা হবে।
এপ্রোগ্রামার

+ প্লাস, বিভাজন করা পুনঃজেনারেট সংখ্যার সাথে তুলনায় আরও ব্যয়বহুল বলে মনে হচ্ছে।
zinking

4
মডুলো নেওয়া এবং ভাগ করার একই খরচ হয়। কিছু আইএসএ এমনকি একটি নির্দেশ প্রদান করে যা সবসময় উভয়ই সরবরাহ করে। সংখ্যার পুনঃনির্মাণের ব্যয় n এবং RAND_MAX এর উপর নির্ভর করবে। যদি রা RAMAMAX এর ক্ষেত্রে n ছোট হয় তবে এটির জন্য অনেক বেশি খরচ হতে পারে। এবং স্পষ্টতই আপনি সিদ্ধান্ত নিতে পারেন যে পক্ষপাতিত্বগুলি আপনার আবেদনের জন্য গুরুত্বপূর্ণ নয়; আমি এগুলি এড়াতে কেবল একটি উপায় দিই।
এপ্রোগ্রামার

9

মার্ক এর সমাধান (গৃহীত সমাধান) প্রায় নিখুঁত।

int x;

do {
    x = rand();
} while (x >= (RAND_MAX - RAND_MAX % n));

x %= n;

23 মার্চ 25 '16 এ সম্পাদিত

এমেরি 39 কে 21170211 চিহ্নিত করুন

তবে এটির একটি সতর্কতা রয়েছে যা কোনও অবস্থাতেই RAND_MAX( RM1) একাধিক N(যেখানে N= সম্ভাব্য বৈধ ফলাফলের সংখ্যা) এর চেয়ে 1 কম ফলাফলের 1 বৈধ ফলাফলের ফলাফলকে বাতিল করে দেয় ।

অর্থাত্, যখন 'বাতিল হওয়া মানের গণনা' ( D) সমান হয় N, তখন সেগুলি আসলে একটি বৈধ সেট ( V), কোনও অবৈধ সেট নয় I)।

এটি কী কারণে ঘটে তা এক পর্যায়ে মার্ক Nএবং এর মধ্যে পার্থক্যের দৃষ্টি হারায় Rand_Max

Nএমন একটি সেট যা বৈধ সদস্যদের মধ্যে কেবল ধনাত্মক পূর্ণসংখ্যার সমন্বিত থাকে, কারণ এতে প্রতিক্রিয়াগুলির একটি সংখ্যা রয়েছে যা বৈধ হবে। (যেমন: সেট N= {1, 2, 3, ... n })

Rand_max তবে এমন একটি সেট যা (আমাদের উদ্দেশ্য হিসাবে সংজ্ঞায়িত করা হয়েছে) এতে নন-নেতিবাচক পূর্ণসংখ্যার সংখ্যা অন্তর্ভুক্ত রয়েছে।

এটি সর্বাধিক জেনেরিক ফর্মের মধ্যে যা এখানে সংজ্ঞাযুক্ত তা হ'ল Rand Maxসমস্ত বৈধ ফলাফলের সেট, যা তাত্ত্বিকভাবে নেতিবাচক সংখ্যা বা অ-সংখ্যাগত মান অন্তর্ভুক্ত করতে পারে।

সুতরাং Rand_Max"সম্ভাব্য প্রতিক্রিয়াগুলি" এর সেট হিসাবে আরও ভালভাবে সংজ্ঞায়িত করা হয়েছে।

তবে Nবৈধ প্রতিক্রিয়াগুলির সেটের মধ্যে মানগুলির গণনার বিরুদ্ধে পরিচালিত হয়, সুতরাং আমাদের নির্দিষ্ট ক্ষেত্রে যেমন সংজ্ঞায়িত Rand_Maxকরা হয় তবে এটি মোট সংখ্যার চেয়ে কম মান হবে।

মার্কের সমাধানটি ব্যবহার করে, মানগুলি বাতিল করা হয় যখন: এক্স => আরএম - আরএম% এন

EG: 

Ran Max Value (RM) = 255
Valid Outcome (N) = 4

When X => 252, Discarded values for X are: 252, 253, 254, 255

So, if Random Value Selected (X) = {252, 253, 254, 255}

Number of discarded Values (I) = RM % N + 1 == N

 IE:

 I = RM % N + 1
 I = 255 % 4 + 1
 I = 3 + 1
 I = 4

   X => ( RM - RM % N )
 255 => (255 - 255 % 4) 
 255 => (255 - 3)
 255 => (252)

 Discard Returns $True

উপরের উদাহরণে আপনি দেখতে পাচ্ছেন যে এক্স এর মান যখন আমরা (প্রাথমিক ফাংশন থেকে প্রাপ্ত এলোমেলো সংখ্যা) 252, 253, 254 বা 255 হয় তখনও আমরা এটিকে বাতিল করব যদিও এই চারটি মান প্রত্যাবর্তিত মানগুলির একটি বৈধ সেটকে অন্তর্ভুক্ত করে ।

IE: যখন প্রত্যাখ্যান করা মূল্যগুলির গণনা (I) = N (বৈধ ফলাফলের সংখ্যা) তখন প্রত্যাবর্তনের মানগুলির একটি বৈধ সেটটি মূল ফাংশন দ্বারা বাতিল করা হবে।

যদি আমরা ডি হিসাবে N এবং RM মানগুলির মধ্যে পার্থক্য বর্ণনা করি, যেমন:

D = (RM - N)

তারপরে ডিটির মান আরও ছোট হওয়ার সাথে সাথে এই পদ্ধতির কারণে অবিযুক্ত পুনরায় রোলসের শতাংশ প্রতিটি প্রাকৃতিক গুণায় বৃদ্ধি পায়। (যখন RAND_MAX একটি প্রধান সংখ্যার সমান নয় এটি বৈধ উদ্বেগের বিষয়)

উদাহরণ:

RM=255 , N=2 Then: D = 253, Lost percentage = 0.78125%

RM=255 , N=4 Then: D = 251, Lost percentage = 1.5625%
RM=255 , N=8 Then: D = 247, Lost percentage = 3.125%
RM=255 , N=16 Then: D = 239, Lost percentage = 6.25%
RM=255 , N=32 Then: D = 223, Lost percentage = 12.5%
RM=255 , N=64 Then: D = 191, Lost percentage = 25%
RM=255 , N= 128 Then D = 127, Lost percentage = 50%

যেহেতু প্রয়োজনীয় রেরোলসের শতাংশ এনএম-এর কাছাকাছি পৌঁছেছে, তাই তার কোড চলমান সিস্টেমের সীমাবদ্ধতা এবং যে মানগুলি অনুসন্ধান করা হচ্ছে তার উপর নির্ভর করে এটি বিভিন্ন ধরণের মূল্যবোধে বৈধ উদ্বেগের বিষয় হতে পারে।

এটি এড়াতে আমরা এখানে একটি সাধারণ সংশোধন করতে পারি:

 int x;

 do {
     x = rand();
 } while (x > (RAND_MAX - ( ( ( RAND_MAX % n ) + 1 ) % n) );

 x %= n;

এটি সূত্রটির আরও সাধারণ সংস্করণ সরবরাহ করে যা আপনার সর্বাধিক মানগুলি সংজ্ঞায়িত করতে মডুলাস ব্যবহারের অতিরিক্ত অদ্ভুততার জন্য দায়ী।

RAND_MAX এর জন্য একটি ছোট মান ব্যবহারের উদাহরণ যা এন এর গুণক is

মার্ক'রিজিনাল সংস্করণ:

RAND_MAX = 3, n = 2, Values in RAND_MAX = 0,1,2,3, Valid Sets = 0,1 and 2,3.
When X >= (RAND_MAX - ( RAND_MAX % n ) )
When X >= 2 the value will be discarded, even though the set is valid.

সাধারণ সংস্করণ 1:

RAND_MAX = 3, n = 2, Values in RAND_MAX = 0,1,2,3, Valid Sets = 0,1 and 2,3.
When X > (RAND_MAX - ( ( RAND_MAX % n  ) + 1 ) % n )
When X > 3 the value would be discarded, but this is not a vlue in the set RAND_MAX so there will be no discard.

অতিরিক্ত হিসাবে, যে ক্ষেত্রে RA এর মান RA এর মধ্যে নম্বর হওয়া উচিত END_BOLD; এই ক্ষেত্রে, আপনি RA =MAND_MAX = INT_MAX ব্যতীত N = RAND_MAX +1 সেট করতে পারেন।

লুপ-ওয়াইজ আপনি কেবল এন = 1 ব্যবহার করতে পারেন, এবং এক্স এর কোনও মান গ্রহণ করা হবে তবে আপনার চূড়ান্ত গুণকটির জন্য একটি আইএফ বিবৃতি দেবে। তবে আপনার কাছে এমন কোড রয়েছে যা ফাংশনটিকে এন = 1 দিয়ে ডাকা হলে একটি 1 ফেরত দেওয়ার বৈধ কারণ থাকতে পারে ...

সুতরাং 0 ব্যবহার করা ভাল, যা সাধারণত ডিভ 0 ত্রুটি সরবরাহ করে, যখন আপনি এন = RAND_MAX + 1 রাখতে চান

সাধারণ সংস্করণ 2:

int x;

if n != 0 {
    do {
        x = rand();
    } while (x > (RAND_MAX - ( ( ( RAND_MAX % n ) + 1 ) % n) );

    x %= n;
} else {
    x = rand();
}

এই উভয় সমাধানই অযথা বাতিল হওয়া বৈধ ফলাফল নিয়ে সমস্যাটি সমাধান করে যা যখন আরএম + 1 এন এর পণ্য হয় তখনই ঘটবে।

দ্বিতীয় সংস্করণে প্রান্তের কেস দৃশ্যাবলীটিও কভার করা হয় যখন আপনাকে RAND_MAX এর মধ্যে থাকা সম্ভাব্য মানগুলির মোট সম্ভাব্য সেটটি সমান করতে প্রয়োজন হয়।

উভয় মধ্যে পরিবর্তিত পদ্ধতির একই এবং বৈধ এলোমেলো সংখ্যা প্রদান এবং বাতিল করা মানগুলি হ্রাস করার প্রয়োজনের আরও সাধারণ সমাধানের অনুমতি দেয়।

পুনরাবৃত্তি করতে:

বেসিক জেনারেল সলিউশন যা চিহ্নের উদাহরণকে প্রসারিত করে:

// Assumes:
//  RAND_MAX is a globally defined constant, returned from the environment.
//  int n; // User input, or externally defined, number of valid choices.

 int x;

 do {
     x = rand();
 } while (x > (RAND_MAX - ( ( ( RAND_MAX % n ) + 1 ) % n) ) );

 x %= n;

বর্ধিত সাধারণ সমাধান যা RAND_MAX + 1 = n এর একটি অতিরিক্ত দৃশ্যের মঞ্জুরি দেয়:

// Assumes:
//  RAND_MAX is a globally defined constant, returned from the environment.
//  int n; // User input, or externally defined, number of valid choices.

int x;

if n != 0 {
    do {
        x = rand();
    } while (x > (RAND_MAX - ( ( ( RAND_MAX % n ) + 1 ) % n) ) );

    x %= n;
} else {
    x = rand();
}

কিছু ভাষায় (বিশেষত বর্ণিত ভাষাগুলি) তুলনায় অপারেশনের গণনার সময়কারীর বাইরে শর্তগুলি দ্রুত ফলাফলের দিকে নিয়ে যেতে পারে কারণ এটি এক-সময় গণনা যতই পুনরায় চেষ্টা করার প্রয়োজন হয় না। YMMV!

// Assumes:
//  RAND_MAX is a globally defined constant, returned from the environment.
//  int n; // User input, or externally defined, number of valid choices.

int x; // Resulting random number
int y; // One-time calculation of the compare value for x

if n != 0 {
    y = RAND_MAX - ( ( ( RAND_MAX % n ) + 1 ) % n) 
    do {
        x = rand();
    } while (x > y);

    x %= n;
} else {
    x = rand();
}

এটা বলা নিরাপদ নয় যে মার্কের সমাধানের সমস্যাটি হ'ল তিনি RAND_MAX এবং n কে একই "পরিমাপের একক" হিসাবে দেখেন যখন বাস্তবে তারা দুটি ভিন্ন জিনিস বোঝায়? যদিও n ফলাফলগুলির "সম্ভাবনার সংখ্যা" উপস্থাপন করে, RAND_MAX কেবলমাত্র মূল সম্ভাবনার সর্বাধিক মানকে উপস্থাপন করে, যেখানে RAND_MAX + 1 সম্ভাবনার মূল সংখ্যা। আমি অবাক হয়েছি যেহেতু তিনি মনে করছেন যে তিনি এন এবং আরএএ এমএএএমএক্স সমীকরণের সাথে একই জিনিস নন বলে মনে হয়েছে:RAND_MAX%n = n - 1
ড্যানিলো সুজা মরিস

@ ড্যানিলোসুজা মরিজেস আপনাকে ড্যানিলো ধন্যবাদ, আপনি বিষয়টি খুব সংক্ষেপে রেখেছেন। আমি কেন এবং কীভাবে এটির পাশাপাশি তিনি কী করছেন তা প্রদর্শনের জন্য গিয়েছিলাম, তবে মনে হয় না যে আমি কীভাবে এবং কীভাবে যুক্তির বিবরণে এতটা গুটিয়ে গিয়েছি যে তিনি স্পষ্টতই কী ভুল করছেন, তা বলতে পেরেছি? কেন একটি সমস্যা আছে, যে আমি ইস্যুতে কি আছে তা পরিষ্কার করে বলছি না। আপনি কি আপত্তি করেন যদি আমি এখানে আমার নিজের সংক্ষিপ্তসার হিসাবে এখানে যা লিখেছি তার কিছুটি ব্যবহার করার জন্য যেটি গ্রহণযোগ্য সমাধানটি করছে যা শীর্ষের নিকটে সম্বোধন করা প্রয়োজন তা করার জন্য আমি আমার সংক্ষিপ্তসার হিসাবে ব্যবহার করেছি?
বেন পার্সোনিক

এইটা চমৎকার হবে. এটির জন্য যান
ড্যানিলো সুজা মোরিস

1

এর RAND_MAXমান সহ 3(বাস্তবে এটি এর চেয়ে অনেক বেশি হওয়া উচিত তবে পক্ষপাতটি এখনও বিদ্যমান থাকবে) এই গণনাগুলি থেকে বোঝা যায় যে এখানে একটি পক্ষপাতিত্ব রয়েছে:

1 % 2 = 1 2 % 2 = 0 3 % 2 = 1 random_between(1, 3) % 2 = more likely a 1

এই ক্ষেত্রে, % 2যখন আপনি 0এবং এর মধ্যে একটি এলোমেলো সংখ্যা চান তখন আপনার যা করা উচিত নয় 1। আপনি যদিও 0এবং এর 2মাধ্যমে একটি এলোমেলো নম্বর পেতে পারেন % 3, কারণ এই ক্ষেত্রে: এর RAND_MAXএকাধিক 3

আরেকটি পদ্ধতি

আরও সহজ সরল তবে অন্যান্য উত্তরগুলি যুক্ত করার জন্য, এখানে পক্ষপাতিত্ব ছাড়াই 0এবং এর n - 1ফলে nবিভিন্ন সম্ভাবনার মধ্যে একটি এলোমেলো সংখ্যা পাওয়ার জন্য আমার সমাধান এটি।

  • সম্ভাবনার সংখ্যা এনকোড করতে প্রয়োজনীয় বিটের সংখ্যা (বাইট নয়) আপনার প্রয়োজনীয় র্যান্ডম ডেটার বিটের সংখ্যা
  • এলোমেলো বিট থেকে নম্বর এনকোড
  • যদি এই সংখ্যাটি থাকে তবে >= nপুনরায় চালু করুন (কোনও মডিউল নেই)।

সত্যিই এলোমেলো ডেটা প্রাপ্ত করা সহজ নয়, তবে কেন প্রয়োজনের চেয়ে বেশি বিট ব্যবহার করুন।

সিউডো-র্যান্ডম সংখ্যার জেনারেটর থেকে বিটের ক্যাশে ব্যবহার করে নীচে স্মলটকের একটি উদাহরণ। আমি কোনও সুরক্ষার বিশেষজ্ঞ না তাই আপনার নিজের ঝুঁকিতে ব্যবহার করুন।

next: n

    | bitSize r from to |
    n < 0 ifTrue: [^0 - (self next: 0 - n)].
    n = 0 ifTrue: [^nil].
    n = 1 ifTrue: [^0].
    cache isNil ifTrue: [cache := OrderedCollection new].
    cache size < (self randmax highBit) ifTrue: [
        Security.DSSRandom default next asByteArray do: [ :byte |
            (1 to: 8) do: [ :i |    cache add: (byte bitAt: i)]
        ]
    ].
    r := 0.
    bitSize := n highBit.
    to := cache size.
    from := to - bitSize + 1.
    (from to: to) do: [ :i |
        r := r bitAt: i - from + 1 put: (cache at: i)
    ].
    cache removeFrom: from to: to.
    r >= n ifTrue: [^self next: n].
    ^r

-1

হিসাবে গৃহীত উত্তর ইঙ্গিত, "মডিউল বায়াস" এর শিকড় কম মান রয়েছে RAND_MAX। তিনি RAND_MAX(10) এর একটি অত্যন্ত ছোট মান ব্যবহার করে দেখান যে যদি RAND_MAX 10 হয়, তবে আপনি 0 ব্যবহার করে 0 এবং 2 এর মধ্যে একটি সংখ্যা তৈরি করার চেষ্টা করেছিলেন, নিম্নলিখিত ফলাফলের ফলাফল হবে:

rand() % 3   // if RAND_MAX were only 10, gives
output of rand()   |   rand()%3
0                  |   0
1                  |   1
2                  |   2
3                  |   0
4                  |   1
5                  |   2
6                  |   0
7                  |   1
8                  |   2
9                  |   0

সুতরাং 0 এর 4 আউটপুট (4/10 সুযোগ) এবং 1 এবং 2 এর 3 টি আউটপুট (প্রতিটি 3-10 টি সম্ভাবনা) রয়েছে।

সুতরাং এটি পক্ষপাতদুষ্ট। কম সংখ্যার বাইরে আসার আরও ভাল সম্ভাবনা রয়েছে।

তবে এটি কেবলমাত্র যখন RAND_MAXছোট হয় তখন এটি স্পষ্টতই প্রদর্শিত হয় । বা আরও সুনির্দিষ্টভাবে, যখন আপনার সংখ্যাটি পরিবর্তিত হচ্ছে তার তুলনায় বড়RAND_MAX

লুপিংয়ের চেয়ে আরও ভাল সমাধান (যা অত্যন্ত অক্ষম এবং এমনকি এটিরও পরামর্শ দেওয়া উচিত নয়) হ'ল অনেক বড় আউটপুট পরিসর সহ একটি পিআরএনজি ব্যবহার করা। Mersenne প্রতারক অ্যালগরিদম 4.294.967.295 সর্বোচ্চ আউটপুট হয়েছে। যেমন MersenneTwister::genrand_int32() % 10সমস্ত উদ্দেশ্য এবং উদ্দেশ্যে কাজ করা সমানভাবে বিতরণ করা হবে এবং মডুলোর পক্ষপাত প্রভাব সমস্ত কিন্তু অদৃশ্য হয়ে যাবে।


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

কারণ সর্বোচ্চ মানটি বিজোড়, MT::genrand_int32()%2সময়টির 0 (50 + 2.3e-8)% এবং সময়ের 1 (50 - 2.3e-8)% বাছাই করে। আপনি যদি কোনও ক্যাসিনোর আরজিএন তৈরি না করেন (যার জন্য আপনি সম্ভবত আরও বৃহত্তর পরিসরের আরজিএন ব্যবহার করেন), কোনও ব্যবহারকারীর সময়ের অতিরিক্ত 2.3e-8% লক্ষ্য করা যাচ্ছে না। আপনি এখানে খুব গুরুত্বপূর্ণ সংখ্যার কথা বলছেন।
bobobobo

7
লুপিং সেরা সমাধান best এটি "উত্কৃষ্টভাবে অক্ষম" নয়; সবচেয়ে খারাপ গড় ক্ষেত্রে পুনরাবৃত্তির দ্বিগুণেরও কম প্রয়োজন। একটি উচ্চ RAND_MAXমান ব্যবহার করা মডুলোর পক্ষপাত হ্রাস করবে, তবে এটি নির্মূল করবে না। লুপিং হবে।
জারেড নীলসেন

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

-3

আমি ভন নিউমানের আনবিয়েড কয়েন ফ্লিপ পদ্ধতির জন্য কেবল একটি কোড লিখেছি, যা তাত্ত্বিকভাবে এলোমেলো সংখ্যা জেনারেশন প্রক্রিয়াটিতে কোনও পক্ষপাতদুষ্ট করা উচিত। আরও তথ্য পাওয়া যাবে ( http://en.wikedia.org/wiki/Fair_coin )

int unbiased_random_bit() {    
    int x1, x2, prev;
    prev = 2;
    x1 = rand() % 2;
    x2 = rand() % 2;

    for (;; x1 = rand() % 2, x2 = rand() % 2)
    {
        if (x1 ^ x2)      // 01 -> 1, or 10 -> 0.
        {
            return x2;        
        }
        else if (x1 & x2)
        {
            if (!prev)    // 0011
                return 1;
            else
                prev = 1; // 1111 -> continue, bias unresolved
        }
        else
        {
            if (prev == 1)// 1100
                return 0;
            else          // 0000 -> continue, bias unresolved
                prev = 0;
        }
    }
}

এটি মডুলো পক্ষপাতিত্বকে সম্বোধন করে না। এই প্রক্রিয়াটি কিছুটা প্রবাহে পক্ষপাত দূর করতে ব্যবহার করা যেতে পারে। যাইহোক, একটি বিট স্ট্রিম থেকে 0 থেকে n পর্যন্ত এমন এক বিতরণে পৌঁছতে যেখানে n এর চেয়ে দুটির শক্তির চেয়ে কম নয়, তার জন্য মডুলো পক্ষপাতিত্বের প্রয়োজন হয়। সুতরাং এই সমাধানটি এলোমেলো সংখ্যা জেনারেশন প্রক্রিয়ার কোনও পক্ষপাত
রিক

2
@ রিক হুঁ 1 এবং 100 এর মধ্যে একটি এলোমেলো সংখ্যা তৈরি করার সময় ভন নিউমানের পদ্ধতির মডুলো পক্ষপাত দূর করার পদ্ধতির যৌক্তিক বর্ধন হবে: ক) rand() % 100100 বার কল করুন । খ) সমস্ত ফলাফল পৃথক হলে, প্রথমটি নিন। গ) অন্যথায়, গোটো এ এটি কাজ করবে, তবে প্রায় 10 ^ 42 এর প্রত্যাশিত সংখ্যার সাথে আপনাকে বেশ ধৈর্য ধরতে হবে। এবং অমর।
মার্ক অ্যামেরি

@ মার্কআমেরি অবশ্যই কাজ করা উচিত। যদিও এটি সঠিকভাবে প্রয়োগ করা হয়নি তবে এই অ্যালগরিদমটি অনুসন্ধান করছেন। else if(prev==2) prev= x1; else { if(prev!=x1) return prev; prev=2;}
রিক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.