একটি ব্যাপ্তির মধ্যে থেকে কিভাবে এলোমেলো পূর্ণসংখ্যার সংখ্যা তৈরি করা যায়


108

এটি আগের পোস্ট করা প্রশ্নটির অনুসরণ:

কিভাবে সি এলোমেলো নম্বর জেনারেট করবেন?

আমি একটি নির্দিষ্ট পরিসরের মধ্যে যেমন একটি মৃত্যুর দিকের নকল করতে 1 থেকে 6 এর মতো এলোমেলো সংখ্যা তৈরি করতে সক্ষম হতে চাই।

আমি কীভাবে এটি করতে যাব?


3
আপনি যে প্রশ্নের উত্তরটি উল্লেখ করেছেন সেটির দ্বিতীয় উত্তরটি যদি আপনার দিকে তাকান তবে আপনার কাছে উত্তর রয়েছে। র্যান্ড ()% 6.
ম্যাটস ফ্রেড্রিকসন

2
এটি কীভাবে কাজ করে তা আমি বুঝতে পারি নি, তাই আমি স্বচ্ছতার জন্য পৃথক প্রশ্ন করার সিদ্ধান্ত নিয়েছি।
জ্যামি কিলিং

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

2
@ ম্যাট র‌্যান্ড ()% 6 কোনও 0 ফিরিয়ে দিতে পারে a
new123456

আপনি কি stackoverflow.com/a/6852396/419 এর সাথে যুক্ত উত্তরটির পরিবর্তে গ্রহণযোগ্য উত্তর হিসাবে চিহ্নিত করতে পারেন :) ধন্যবাদ
কেভ

উত্তর:


173

এখনও পর্যন্ত সমস্ত উত্তর গাণিতিকভাবে ভুল। প্রত্যাবর্তন ব্যবধানে rand() % Nসমানভাবে সংখ্যা দেয় না [0, N)যতক্ষণ না ফেরতের Nব্যবধানের দৈর্ঘ্যকে ভাগ করে rand()দেয় (অর্থাত্ 2 এর শক্তি)। তদ্ব্যতীত, মডিউলগুলি rand()স্বাধীন কিনা সে সম্পর্কে কারওই ধারণা নেই : এটি সম্ভবত সম্ভব যেগুলি 0, 1, 2, ...অভিন্ন, তবে খুব এলোমেলো নয়। এটি কেবল যুক্তিযুক্ত মনে করা একমাত্র rand()পোয়েসন বিতরণ রাখে: একই আকারের দুটি ননওভারল্যাপিং সাবিন্টারভাল সমান সম্ভাবনা এবং স্বাধীন। সীমাবদ্ধ মানগুলির জন্য, এটি একটি অভিন্ন বন্টনকে বোঝায় এবং এটিও নিশ্চিত করে যে এর মানগুলি rand()সুন্দরভাবে বিক্ষিপ্ত।

এর অর্থ হল এর ব্যাপ্তি পরিবর্তন করার একমাত্র সঠিক উপায় rand()এটি বাক্সগুলিতে বিভক্ত করা; উদাহরণস্বরূপ, RAND_MAX == 11এবং যদি আপনি একটি ব্যাপ্তি চান 1..6, আপনার {0,1}1, {2,3}2 থেকে 2 এবং আরও কিছু নির্ধারণ করা উচিত । এগুলি বিচ্ছিন্নতা, সমান আকারের অন্তর এবং এগুলি অভিন্ন এবং স্বতন্ত্রভাবে বিতরণ করা হয়।

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

সঠিক উপায় হল পূর্ণসংখ্যার গাণিতিক ব্যবহার করা। এটি হল, আপনি নীচের মতো কিছু চান:

#include <stdlib.h> // For random(), RAND_MAX

// Assumes 0 <= max <= RAND_MAX
// Returns in the closed interval [0, max]
long random_at_most(long max) {
  unsigned long
    // max <= RAND_MAX < ULONG_MAX, so this is okay.
    num_bins = (unsigned long) max + 1,
    num_rand = (unsigned long) RAND_MAX + 1,
    bin_size = num_rand / num_bins,
    defect   = num_rand % num_bins;

  long x;
  do {
   x = random();
  }
  // This is carefully written not to overflow
  while (num_rand - defect <= (unsigned long)x);

  // Truncated division is intentional
  return x/bin_size;
}

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

আপনি যদি ডিফল্ট সীমার বাইরে এলোমেলো মান পেতে চান [0, RAND_MAX], তবে আপনাকে কিছু কৃপণ করতে হবে। সম্ভবত সবচেয়ে যুক্তিযুক্ত হ'ল এমন ফাংশনটি সংজ্ঞায়িত করা random_extended()যা nবিটগুলি টেনে নিয়ে (ব্যবহার করে random_at_most()) ফিরে আসে এবং তার চেয়ে কম এলোমেলো মান টানতে (এবং তার জায়গায় ) এর জায়গায় [0, 2**n)প্রয়োগ random_at_most()করে , ধরে নিলে এমন একটি সংখ্যার ধরণ রয়েছে যা ধরে রাখতে পারে একটি মান. অবশেষে, অবশ্যই, আপনি নেতিবাচক মান সহ, ব্যবহারের মান পেতে পারেন ।random_extended()random()2**n - 1RAND_MAX2**n[min, max]min + random_at_most(max - min)


1
@Adam Rosenfield, @ রায়ান রেইচ: একটি সম্পর্কিত প্রশ্ন যেখানে আদম উত্তর দিয়েছেন: stackoverflow.com/questions/137783/... , 'মডুলাস' ব্যবহার তারপর ভুল হবে No: সবচেয়ে সম্মত উত্তর নেই? ১.২১ থেকে ১..7 উত্পন্ন করার জন্য, রায়ান যে পদ্ধতিটি বর্ণনা করেছেন তা ব্যবহার করা উচিত lease দয়া করে আমি ভুল হলে আমাকে সংশোধন করুন।
অরবিন্দ

1
আরও পর্যালোচনা করার পরে, এখানে অন্য একটি সমস্যা হ'ল এটি যখন কাজ করবে না max - min > RAND_MAX, যা আমি উপরে উল্লিখিত ইস্যুটির চেয়ে গুরুতর (যেমন ভিসি ++ RAND_MAXএর কেবলমাত্র 32767 রয়েছে)।
ইন্টারজয়

2
লুপটি আরও পঠনযোগ্য হতে পারে। শর্তসাপেক্ষে অ্যাসাইনমেন্ট সম্পাদন করার পরিবর্তে আপনি সম্ভবত একটি চান do {} while()
জেজেপস্টার

4
আরে, এই উত্তরটি ধূমকেতু ওএস বইয়ের দ্বারা উদ্ধৃত করা হয়েছে;) প্রথমবার আমি দেখছি যে একটি শিক্ষণ বইয়ে
vpuente

3
এটি ওএসটিইপি বইতেও উদ্ধৃত করা হয়েছে :) পেজসসিএস.উইস.ইউইউকিউমারিজ / অস্টিপ (অধ্যায় 9, পৃষ্ঠা 4)
রাফাস্কার

33

@ রায়ান রিচের উত্তর অনুসরণ করে আমি ভেবেছিলাম যে আমি আমার ক্লিন আপ সংস্করণটি দেব। দ্বিতীয় বাউন্ড চেক দেওয়ার পরে প্রথম সীমা চেকের প্রয়োজন হয় না, এবং আমি এটি পুনরাবৃত্তির চেয়ে পুনরাবৃত্ত করে তুলেছি। এটি [মিনিট, সর্বাধিক], যেখানে max >= minএবং সীমাতে মানগুলি প্রদান করে 1+max-min < RAND_MAX

unsigned int rand_interval(unsigned int min, unsigned int max)
{
    int r;
    const unsigned int range = 1 + max - min;
    const unsigned int buckets = RAND_MAX / range;
    const unsigned int limit = buckets * range;

    /* Create equal size buckets all in a row, then fire randomly towards
     * the buckets until you land in one of them. All buckets are equally
     * likely. If you land off the end of the line of buckets, try again. */
    do
    {
        r = rand();
    } while (r >= limit);

    return min + (r / buckets);
}

28
দ্রষ্টব্য> রেঞ্জ> = RAND_MAX হলে এটি একটি অসীম লুপে আটকে যাবে Note আমি কীভাবে জানি আমাকে জিজ্ঞাসা করুন: /
জেজেস্টার 14

24
তুমি কিভাবে জান!?
চমত্কার মিস্টার ফক্স

1
নোট করুন যে আপনি একটি স্বাক্ষরবিহীন int (r> = সীমা) এর সাথে কোন int এর তুলনা করছেন। < এবং <= যেহেতু limitকোনও ইন্টি (এবং option bucketচ্ছিকভাবেও) তৈরি করে সমস্যাটি সহজেই সমাধান করা হয় । সম্পাদনা: আমি প্রস্তাব জমা দিয়েছি এবং সম্পাদনা করেছি। RAND_MAX / rangeINT_MAXbuckets * rangeRAND_MAX
rrrrrrrrrrrrrrrrrrrr

@ রায়ান রিচের সমাধান এখনও আমাকে আরও ভাল (নিম্ন পক্ষপাতদুষ্ট) বিতরণ দেয়
ভ্লাদিমির

20

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

r = (rand() % (max + 1 - min)) + min

9
রায়ের উত্তরে যেমন উল্লেখ করা হয়েছে, এটি পক্ষপাতদুষ্ট ফলাফল দেয়।
ডেভিড ওলবার

6
পক্ষপাতদুষ্ট ফলাফল, এর সাথে সম্ভাব্য intওভারফ্লো max+1-min
chux - মনিকা

1
এই কাজটি শুধুমাত্র পূর্ণসংখ্যার ন্যূনতম এবং সর্বাধিক দিয়ে। যদি ন্যূনতম এবং সর্বোচ্চটি ভাসমান হয়, তবে% অপারেশন করা সম্ভব নয়
তাইউলি ফ্রান্সেস্কো

17
unsigned int
randr(unsigned int min, unsigned int max)
{
       double scaled = (double)rand()/RAND_MAX;

       return (max - min +1)*scaled + min;
}

অন্যান্য বিকল্পের জন্য এখানে দেখুন ।


2
@ এসলট - সত্যই নয়। প্রতিটি সামান্য-উচ্চ-প্রতিকূল কেসগুলি আলাদাভাবে বিতরণ করে, এগুলিই। দ্বৈত গণিতটি এই ধারণাটি দেয় যে সেখানে আরও স্পষ্টতা রয়েছে, তবে আপনি খুব সহজেই সহজেই ব্যবহার করতে পারেন (((max-min+1)*rand())/RAND_MAX)+minএবং ঠিক একই ডিস্ট্রিবিউশনটি পেতে পারেন (ধরে নিই যে RAND_MAX ওভারফ্লো না হওয়ার জন্য যথেষ্ট পরিমাণের তুলনায় যথেষ্ট ছোট)।
স্টিভ 314

4
এই সামান্য বিপজ্জনক: এটা করার জন্য (খুব কমই) আগমন এই জন্য সম্ভব max + 1, যদি পারেন rand() == RAND_MAX, অথবা rand()খুব পাসে RAND_MAXএবং ভাসমান দফা ত্রুটি চূড়ান্ত ফলাফল গত ধাক্কা max + 1। নিরাপদে থাকার জন্য, আপনাকে ফলাফলটি ফেরত দেওয়ার আগে সীমার মধ্যে রয়েছে তা পরীক্ষা করা উচিত।
মার্ক ডিকিনসন

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

3
ক্রিস্টোফের পরামর্শ অনুসারে যদি RAND_MAXপ্রতিস্থাপন করা RAND_MAX+1.0হয়, তবে আমি বিশ্বাস করি যে এটি + minপূর্ণরূপে গাণিতিক ব্যবহার করে সম্পন্ন হয়েছে: তবে এটি নিরাপদ return (unsigned int)((max - min + 1) * scaled) + min। (অ-স্পষ্ট) কারণটি হ'ল আইইইই 75৫৪ পাটিগণিত এবং গোল-অর্ধ-সম-এমনকি, এবং এটিও max - min + 1ডাবল হিসাবে ঠিক উপস্থাপনযোগ্য, তবে এটি একটি সাধারণ মেশিনে সত্য হবে), এটি সর্বদা সত্য যে এটির x * scaled < xজন্য যে কোনও ধনাত্মক দ্বিগুণ xএবং কোনও দ্বৈত scaledসন্তোষজনক 0.0 <= scaled && scaled < 1.0
মার্ক ডিকিনসন

1
এর জন্য ব্যর্থ randr(0, UINT_MAX): সর্বদা 0 উত্পাদন করে
চ্যাক্স -

12

আপনি কি শুধু করবেন না:

srand(time(NULL));
int r = ( rand() % 6 ) + 1;

%মডুলাস অপারেটর। মূলত এটি কেবল 6 দ্বারা ভাগ হবে এবং বাকীটি ফিরে আসবে ... 0 - 5 থেকে


1
এটি 1 - 6 থেকে ফলাফল দেবে That's এটিই 1+ এর জন্য।
আর্মস্ট্রোনস্ট

4
সাইমন, আমাকে যে কোনও জায়গায় ব্যবহারের ক্ষেত্রে একটি libc দেখান যেখানে rand()জেনারেটরের রাজ্যের নিম্ন-অর্ডার বিট অন্তর্ভুক্ত থাকে (যদি এটি এলসিজি ব্যবহার করে)। আমি এখন পর্যন্ত একটিও দেখিনি them এগুলির সবগুলিই (হ্যাঁ, এমএসভিসি সহ RAND_MAX মাত্র 32767 রয়েছে) নিম্ন-অর্ডার বিটগুলি সরিয়ে দেয়। মডুলাস ব্যবহারের জন্য অন্যান্য কারণে সুপারিশ করা হয় না, এটি কম সংখ্যার পক্ষে বন্টনকে কমিয়ে দেয়।
জোয়ে

@ জোহানেস: সুতরাং স্লট মেশিনগুলি মডিউল ব্যবহার করে না বলা নিরাপদ?
আর্মস্ট্রোনজেস্ট

আমি কীভাবে একটি 0 বাদ দেব? দেখে মনে হয় যে আমি যদি এটি 30 এর লুপে চালিত করি তবে সম্ভবত দ্বিতীয় বা তৃতীয়বার এটি চালায় এটিতে প্রায় 0 টির মতো অর্ধেক পথ রয়েছে। এটি কি একরকম ফ্লুক?
জেমি কিলিং

@ জোহানেস: আজকাল এটি খুব বেশি সমস্যা নয়, তবে traditionতিহ্যগতভাবে লো-অর্ডার বিটগুলি ব্যবহার করা ভাল নয়। c-faq.com/lib/randrange.html
jamesdlin

9

যারা পক্ষপাতিত্ব সমস্যাটি বোঝেন তবে প্রত্যাখ্যান-ভিত্তিক পদ্ধতির অনাকাঙ্ক্ষিত রান-টাইম দাঁড়াতে পারবেন না, তাদের এই সিরিজটি [0, n-1]বিরতিতে ক্রমহ্রাসমান কম পক্ষপাতমূলক এলোমেলো পূর্ণসংখ্যার উত্পাদন করে :

r = n / 2;
r = (rand() * n + r) / (RAND_MAX + 1);
r = (rand() * n + r) / (RAND_MAX + 1);
r = (rand() * n + r) / (RAND_MAX + 1);
...

এটি উচ্চ-নির্ভুলতা নির্দিষ্ট পয়েন্টের র্যান্ডম সংখ্যার i * log_2(RAND_MAX + 1)বিট সংশ্লেষ করে (যেখানে iপুনরাবৃত্তির সংখ্যা রয়েছে) এবং দীর্ঘ গুণ দ্বারা সঞ্চালিত হয় n

বিটের সংখ্যা যখন তুলনায় পর্যাপ্ত পরিমাণে বড় হয় n, তখন পক্ষপাতটি অল্প পরিমাণে ছোট হয়ে যায়।

( এই প্রশ্নে ) এর RAND_MAX + 1চেয়ে কম কিনা , বা এটি দুটির শক্তি না হলেও এটি গুরুত্বপূর্ণ নয়, তবে বড় হলে পূর্ণসংখ্যার ওভারফ্লো এড়াতে যত্ন নেওয়া উচিত ।nRAND_MAX * n


2
RAND_MAXপ্রায়শই হয় INT_MAX, তাই RAND_MAX + 1-> ইউবি (INT_MIN এর মতো)
chux - মনিকা পুনরায় স্থাপন করুন

@ chux এর অর্থ আমি " RAND_MAX * nবড় হলে পূর্ণসংখ্যার ওভারফ্লো এড়াতে যত্ন নেওয়া উচিত" এর অর্থ । আপনার প্রয়োজনীয়তার জন্য আপনার উপযুক্ত প্রকারের ব্যবহারের ব্যবস্থা করতে হবে।
sh1

@chux " RAND_MAXপ্রায়শই INT_MAX" হ্যাঁ, তবে কেবলমাত্র 16 বিট সিস্টেমে! যে কোনও যুক্তিযুক্তভাবে আধুনিক আর্কিটেকচার INT_MAX2 2 32/2 এবং 2 ^ 16/2 এ স্থাপন করবে এটি RAND_MAXকি একটি ভুল অনুমান?
বিড়াল

2
@ ক্যাট আজ পরীক্ষিত হয়েছে 32 32-বিট intসংকলক, আমি RAND_MAX == 32767একটিতে এবং RAND_MAX == 2147483647অন্যটিতে পেয়েছি । আমার সামগ্রিক অভিজ্ঞতা (দশক) এটি RAND_MAX == INT_MAXপ্রায়শই হয়। অতএব দ্বিমত পোষণ করুন যে যুক্তিসঙ্গতভাবে আধুনিক 32-বিট আর্কিটেকচারটির অবশ্যই একটি RAND_MAXপরিমাণ থাকবে 2^16 / 2। যেহেতু সি স্পিক অনুমতি দেয় 32767 <= RAND_MAX <= INT_MAX, আমি কোনও প্রবণতা না করে যে কোনও উপায়ে কোড করি।
chux - মনিকা পুনরায় ইনস্টল করুন

3
এখনও পূর্ণসংখ্যার ওভারফ্লো এড়াতে যত্ন নেওয়া উচিত "byেকে রাখা উচিত।
sh1

4

মডুলোর পক্ষপাত এড়াতে (অন্যান্য উত্তরে প্রস্তাবিত) আপনি সর্বদা ব্যবহার করতে পারেন:

arc4random_uniform(MAX-MIN)+MIN

যেখানে "MAX" হ'ল উপরের বাউন্ড এবং "MIN" নিম্ন সীমাবদ্ধ। উদাহরণস্বরূপ, 10 এবং 20 এর মধ্যে সংখ্যার জন্য:

arc4random_uniform(20-10)+10

arc4random_uniform(10)+10

"র্যান্ড ()% এন" ব্যবহারের চেয়ে সহজ সমাধান এবং ভাল।


1
ওহহু, এটি অন্যান্য উত্তরের চেয়ে এক বিলিয়ন গুণ ভাল। #include <bsd/stdlib.h>প্রথমে আপনার লক্ষ্য করা দরকার । এছাড়াও, উইন্ডোজটিতে মিনিজিডাব্লু বা সাইগউইন ছাড়া কীভাবে এটি পাবেন তা সম্পর্কে কোনও ধারণা?
বিড়াল

1
না, এটি অন্যান্য উত্তরগুলির চেয়ে ভাল নয়, কারণ অন্যান্য উত্তরগুলি বেশি জেনেরিক। এখানে আপনি আরক 4 ব্র্যান্ডম-এ সীমাবদ্ধ রয়েছেন, অন্যান্য উত্তরগুলি আপনাকে একটি ভিন্ন এলোমেলো উত্স চয়ন করতে, বিভিন্ন সংখ্যা-ধরণের সাথে পরিচালনা করার অনুমতি দেয় ... এবং সর্বশেষে তবে তারা সমস্যাটি বুঝতে কাউকে সহায়তা করতে পারে। ভুলে যাবেন না যে প্রশ্নটি অন্যান্য লোকেদের জন্যও আকর্ষণীয়, যাদের কিছু বিশেষ প্রয়োজনীয়তা থাকতে পারে বা আরক 4 ব্র্যান্ডম অ্যাক্সেস নাও থাকতে পারে ... তবুও, যদি আপনার এটিতে অ্যাক্সেস থাকে এবং দ্রুত সমাধান চান, তবে এটি অবশ্যই খুব ভাল উত্তর 😊
কে। বীরমান

4

রায়ান রিচের সমাধানের তুলনায় এখানে সামান্য সরল অ্যালগরিদম রয়েছে:

/// Begin and end are *inclusive*; => [begin, end]
uint32_t getRandInterval(uint32_t begin, uint32_t end) {
    uint32_t range = (end - begin) + 1;
    uint32_t limit = ((uint64_t)RAND_MAX + 1) - (((uint64_t)RAND_MAX + 1) % range);

    /* Imagine range-sized buckets all in a row, then fire randomly towards
     * the buckets until you land in one of them. All buckets are equally
     * likely. If you land off the end of the line of buckets, try again. */
    uint32_t randVal = rand();
    while (randVal >= limit) randVal = rand();

    /// Return the position you hit in the bucket + begin as random number
    return (randVal % range) + begin;
}

Example (RAND_MAX := 16, begin := 2, end := 7)
    => range := 6  (1 + end - begin)
    => limit := 12 (RAND_MAX + 1) - ((RAND_MAX + 1) % range)

The limit is always a multiple of the range,
so we can split it into range-sized buckets:
    Possible-rand-output: 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16
    Buckets:             [0, 1, 2, 3, 4, 5][0, 1, 2, 3, 4, 5][X, X, X, X, X]
    Buckets + begin:     [2, 3, 4, 5, 6, 7][2, 3, 4, 5, 6, 7][X, X, X, X, X]

1st call to rand() => 13
     13 is not in the bucket-range anymore (>= limit), while-condition is true
         retry...
2nd call to rand() => 7
     7 is in the bucket-range (< limit), while-condition is false
         Get the corresponding bucket-value 1 (randVal % range) and add begin
    => 3

1
RAND_MAX + 1সহজেই ওভারফ্লো intসংযোজন করতে পারে । সেক্ষেত্রে, (RAND_MAX + 1) % rangeসন্দেহজনক ফলাফল উত্পন্ন করবে। বিবেচনা করুন(RAND_MAX + (uint32_t)1)
chux - মনিকা

2

রায়ান সঠিক হলেও সমাধানটি এলোমেলোতার উত্স সম্পর্কে যা জানা যায় তার ভিত্তিতে অনেক সহজ হতে পারে। সমস্যাটিকে পুনরায় জানাতে:

  • এলোমেলোতার উত্স রয়েছে, [0, MAX)অভিন্ন বন্টনের পরিসীমাতে পূর্ণসংখ্যার সংখ্যা আউটপুট করে ।
  • লক্ষ্যটি হ'ল [rmin, rmax]যেখানে সীমিতভাবে বিতরণ করা এলোমেলো পূর্ণসংখ্যার সংখ্যা 0 <= rmin < rmax < MAX

আমার অভিজ্ঞতা অনুসারে, যদি বিনের সংখ্যা (বা "বাক্সগুলি") মূল সংখ্যাগুলির পরিসরের তুলনায় উল্লেখযোগ্য পরিমাণে ছোট হয় এবং মূল উত্সটি ক্রিপ্টোগ্রাফিকভাবে শক্তিশালী হয় - তবে এই সমস্ত রাগামেরোলের মধ্য দিয়ে যাওয়ার দরকার নেই, এবং সাধারণ মডুলো বিভাগ হবে যথেষ্ট (যেমন output = rnd.next() % (rmax+1), যদি rmin == 0), এবং এলোমেলো সংখ্যাগুলি সরবরাহ করে যা অভিন্নভাবে "যথেষ্ট" বিতরণ করা হয় এবং গতির কোনও ক্ষতি ছাড়াই। মূল ফ্যাক্টরটি হল এলোমেলো উত্স (অর্থাত্ বাচ্চারা, বাড়িতে এটি চেষ্টা করবেন না rand())।

বাস্তবে এটি কীভাবে কাজ করে তার একটি উদাহরণ / প্রমাণ এখানে। আমি 1 থেকে 22 পর্যন্ত এলোমেলো সংখ্যা উত্পন্ন করতে চেয়েছিলাম, একটি ক্রিপ্টোগ্রাফিকভাবে শক্তিশালী উত্স রয়েছে যা এলোমেলো বাইট তৈরি করেছিল (ইন্টেল আরডিআরএন্ডের উপর ভিত্তি করে)। ফলাফলগুলি হ'ল:

Rnd distribution test (22 boxes, numbers of entries in each box):     
 1: 409443    4.55%
 2: 408736    4.54%
 3: 408557    4.54%
 4: 409125    4.55%
 5: 408812    4.54%
 6: 409418    4.55%
 7: 408365    4.54%
 8: 407992    4.53%
 9: 409262    4.55%
10: 408112    4.53%
11: 409995    4.56%
12: 409810    4.55%
13: 409638    4.55%
14: 408905    4.54%
15: 408484    4.54%
16: 408211    4.54%
17: 409773    4.55%
18: 409597    4.55%
19: 409727    4.55%
20: 409062    4.55%
21: 409634    4.55%
22: 409342    4.55%   
total: 100.00%

এটি আমার ইউনিফর্মের যতটা প্রয়োজন ঠিক ততই কাছাকাছি (ফেয়ার ডাইস থ্রো, ডাব্লুডাব্লুআইআই সিফার মেশিনের মতো ক্রিপ্টোগ্রাফিকভাবে শক্তিশালী কোডবুক তৈরি করা http://users.telenet.be/d.rijmenants/en/kl-7sim.htm , ইত্যাদি) )। আউটপুট কোনও প্রশংসনীয় পক্ষপাত প্রদর্শন করে না।

এখানে ক্রিপ্টোগ্রাফিকভাবে শক্তিশালী (সত্য) এলোমেলো সংখ্যা জেনারেটরের উত্স: ইন্টেল ডিজিটাল র‌্যান্ডম নম্বর জেনারেটর এবং একটি নমুনা কোড যা -৪-বিট (স্বাক্ষরযুক্ত) এলোমেলো সংখ্যা তৈরি করে।

int rdrand64_step(unsigned long long int *therand)
{
  unsigned long long int foo;
  int cf_error_status;

  asm("rdrand %%rax; \
        mov $1,%%edx; \
        cmovae %%rax,%%rdx; \
        mov %%edx,%1; \
        mov %%rax, %0;":"=r"(foo),"=r"(cf_error_status)::"%rax","%rdx");
        *therand = foo;
  return cf_error_status;
}

আমি এটিকে ম্যাক ওএস এক্সে ঝাঁকুনি -6.0.1 (সরাসরি) দিয়ে এবং gcc-4.8.3 দিয়ে "-ওয়া, কিউ" পতাকা ব্যবহার করে সংকলিত করেছি (কারণ জিএএস এই নতুন নির্দেশাবলী সমর্থন করে না)।


সঙ্গে সংকলিত gcc randu.c -o randu -Wa,q(উবুন্টু 16 জিসিসি 5.3.1) অথবা clang randu.c -o randu(ঝনঝন 3.8.0) কাজ করে, কিন্তু রানটাইম এ কোর ডাম্প Illegal instruction (core dumped)। কোন ধারনা?
বিড়াল

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

আপনার সত্যই ভাল পয়েন্ট আছে। আমি এখনও যা পাই না তা হ'ল যা খুব ভুল rand()। আমি কয়েকটি পরীক্ষার চেষ্টা করেছি এবং এই প্রশ্নটি পোস্ট করেছি তবে আমি এখনও একটি নির্দিষ্ট উত্তর খুঁজে পাচ্ছি না।
myradio

1

যেমনটি আগে বলা হয়েছিল যে মডুলো পর্যাপ্ত নয় কারণ এটি বিতরণকে স্কিউ করে। আমার কোডটি এখানে যা বিটগুলি বন্ধ করে রাখে এবং বিতরণটি স্কিউড না হয় তা নিশ্চিত করার জন্য সেগুলি ব্যবহার করে।

static uint32_t randomInRange(uint32_t a,uint32_t b) {
    uint32_t v;
    uint32_t range;
    uint32_t upper;
    uint32_t lower;
    uint32_t mask;

    if(a == b) {
        return a;
    }

    if(a > b) {
        upper = a;
        lower = b;
    } else {
        upper = b;
        lower = a; 
    }

    range = upper - lower;

    mask = 0;
    //XXX calculate range with log and mask? nah, too lazy :).
    while(1) {
        if(mask >= range) {
            break;
        }
        mask = (mask << 1) | 1;
    }


    while(1) {
        v = rand() & mask;
        if(v <= range) {
            return lower + v;
        }
    }

}

নিম্নলিখিত সহজ কোডটি আপনাকে বিতরণটি দেখতে দেয়:

int main() {

    unsigned long long int i;


    unsigned int n = 10;
    unsigned int numbers[n];


    for (i = 0; i < n; i++) {
        numbers[i] = 0;
    }

    for (i = 0 ; i < 10000000 ; i++){
        uint32_t rand = random_in_range(0,n - 1);
        if(rand >= n){
            printf("bug: rand out of range %u\n",(unsigned int)rand);
            return 1;
        }
        numbers[rand] += 1;
    }

    for(i = 0; i < n; i++) {
        printf("%u: %u\n",i,numbers[i]);
    }

}

আপনি র্যান্ড () থেকে সংখ্যাগুলি প্রত্যাখ্যান করার সময় বেশ অদক্ষ হয়ে ওঠেন। এটি বিশেষত অক্ষম হবে যখন পরিসীমাটির আকার হবে যা 2 ^ কে + 1 হিসাবে লেখা যেতে পারে Then তারপরে ধীর র্যান্ড () কল থেকে আপনার সমস্ত প্রচেষ্টাগুলির প্রায় অর্ধেকটি শর্ত দ্বারা প্রত্যাখাত হবে। RAND_MAX মডুলো সীমাটি গণনা করা ভাল। মত: v = rand(); if (v > RAND_MAX - (RAND_MAX % range) -> reject and try again; else return v % range;আমি বুঝতে পারি যে মডুলো মাস্কিংয়ের চেয়ে অনেক ধীর গতি সম্পন্ন অপারেশন, তবে আমি এখনও মনে করি ..... এটি পরীক্ষা করা উচিত।
inসিস্টিন শানিং-জোহানসেন

rand()পরিসীমাতে একটি প্রদান intকরে [0..RAND_MAX]। এই ব্যাপ্তিটি সহজেই একটি সাবজেক্ট হতে পারে uint32_tএবং তারপরে randomInRange(0, ,b)আর কোনও ক্ষেত্রে রেঞ্জের মান উৎপন্ন করে না (INT_MAX...b]
chux -

0

পরিসরে একটি ভাসমান পয়েন্ট নম্বর [0,1] প্রদান করবে:

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