একটি ব্যাপ্তি থেকে এলোমেলো পূর্ণসংখ্যার উত্পাদন করা


157

আমার একটি ফাংশন প্রয়োজন যা প্রদত্ত পরিসরে (সীমান্তের মান সহ) এলোমেলো পূর্ণসংখ্যার উত্পন্ন করবে। আমি অযৌক্তিক মানের / এলোমেলোতা প্রয়োজনীয়তা নেই, আমার চারটি প্রয়োজনীয়তা রয়েছে:

  • আমার তা দ্রুত হওয়া দরকার আমার প্রকল্পে লক্ষ লক্ষ (বা কখনও কখনও কয়েক মিলিয়ন) এলোমেলো সংখ্যাও তৈরি করা দরকার এবং আমার বর্তমান জেনারেটরের কাজটি একটি বাধা হিসাবে প্রমাণিত হয়েছে।
  • আমার এটি যুক্তিসঙ্গতভাবে অভিন্ন হতে হবে (র্যান্ডের ব্যবহার () পুরোপুরি ভাল)।
  • সর্বনিম্ন সর্বাধিক ব্যাপ্তি <0, 1> থেকে <-32727, 32727> এ যে কোনও হতে পারে।
  • এটি বীজযোগ্য হতে হবে।

আমার কাছে বর্তমানে সি ++ কোড রয়েছে:

output = min + (rand() * (int)(max - min) / RAND_MAX)

সমস্যাটি হ'ল এটি সত্যই অভিন্ন নয় - সর্বোচ্চ তখনই ফিরে আসে যখন র্যান্ড () = RAND_MAX (ভিজ্যুয়াল সি ++ এর জন্য এটি 1/32727)। এটি <-1, 1> এর মতো ছোট রেঞ্জের জন্য প্রধান সমস্যা, যেখানে শেষ মানটি কখনই ফিরে আসে না।

সুতরাং আমি কলম এবং কাগজ ধরলাম এবং নীচের সূত্রটি নিয়ে এসেছি (যা অন্তর্নিহিত (এন + 0.5) পূর্ণসংখ্যার বৃত্তাকার কৌশল):

এখানে চিত্র বর্ণনা লিখুন

তবে এটি এখনও আমাকে অভিন্ন বিতরণ দেয় না। 10000 নমুনা দিয়ে পুনরাবৃত্তি আমাকে মান মান -1, 0. 1 এর জন্য 37:50:13 অনুপাত দেয়।

আপনি কি আরও ভাল সূত্র প্রস্তাব করতে পারেন? (বা এমনকি পুরো ছদ্ম-এলোমেলো সংখ্যা জেনারেটর ফাংশন)



3
@ বিল ম্যাগগ্রিফ: হ্যাঁ এটি একই সমস্যা আছে। সরলিকৃত সংস্করণটি হল: আপনি 3 বাচ্চাদের মধ্যে 10 টি টুকরো টুকরো করে সমানভাবে ভাগ করতে পারেন (ক্যান্ডির কোনও ভাঙা ছাড়াই)? উত্তরটি হ'ল আপনি পারবেন না - আপনাকে প্রতিটি বাচ্চাকে তিনটি দিতে হবে, এবং দশমকে কাউকে দিতে হবে না।
জেরি কফিন


3
অ্যান্ড্রু কোইনিগ নিবন্ধটি দেখুন "একটি সাধারণ সমস্যা যা প্রায়শই সঠিকভাবে সমাধান করা যায় না": drdobbs.com/blog/archives/2010/11/a_simple_proble.html
জিন বুশুয়েভ

1
@ জিন বুশুয়েভ: অ্যান্ড্রু এবং আমি দুজনেই এই বিষয়টিকে নিয়ে বেশ কিছুদিন ধরে ক্ষতিগ্রস্থ হয়েছি। দেখুন: groups.google.com/group/comp.lang.c++/browse_frm/thread/… , এবং: গ্রুপ. google.comggp
জেরি কফিন

উত্তর:


105

একটি দ্রুত, আপনার চেয়ে কিছুটা ভাল, তবে এখনও সঠিকভাবে অভিন্ন বিতরণ সমাধান নয়

output = min + (rand() % static_cast<int>(max - min + 1))

ব্যাপ্তির আকার 2 এর পাওয়ার ব্যতীত, এই পদ্ধতিটি গুণমান নির্বিশেষে পক্ষপাতযুক্ত অ-ইউনিফর্ম বিতরণ সংখ্যার উত্পাদন করেrand() । এই পদ্ধতির গুণমানের একটি বিস্তৃত পরীক্ষার জন্য, দয়া করে এটি পড়ুন


2
ধন্যবাদ, দ্রুত টেস্টগুলি থেকে এটি আমার পক্ষে যথেষ্ট ভাল বলে মনে হচ্ছে - -1, 0, 1 এর বিতরণটি প্রায় 33:33:33 :33
মাতাজ জাবস্কি

3
এটি সর্বদা সর্বোচ্চ মান প্রদান করে returns আমি কি এখানে কিছু মিস করছি? : |
রোহন-প্যাটেল

15
rand()সি ++ তে ক্ষতিকারক হিসাবে বিবেচিত হওয়া উচিত যা অভিন্নভাবে বিতরণ করা হয়েছে এবং আসলে এলোমেলোভাবে এমন কিছু পাওয়ার আরও অনেক ভাল উপায় রয়েছে।
Mgetz

1
এটি কি 100% সময়ের মধ্যে সত্যিই একটি সঠিক নম্বর দেয়? : আমি কিছু অন্যান্য Stackoverflow উত্তর এখানে যে recursion ব্যবহার করছে এটি "সঠিক ভাবে" করতে পেয়েছি stackoverflow.com/a/6852396/623622
Czarek Tomczak

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

296

সবচেয়ে সহজ (এবং তাই সেরা) সি ++ (2011 মান ব্যবহার করে) উত্তরটি

#include <random>

std::random_device rd;     // only used once to initialise (seed) engine
std::mt19937 rng(rd());    // random-number engine used (Mersenne-Twister in this case)
std::uniform_int_distribution<int> uni(min,max); // guaranteed unbiased

auto random_integer = uni(rng);

চাকাটি নতুন করে আবিষ্কার করার দরকার নেই। পক্ষপাতিত্ব নিয়ে চিন্তা করার দরকার নেই। এলোমেলো বীজ হিসাবে সময় ব্যবহার সম্পর্কে চিন্তা করার দরকার নেই।


1
আজকাল এর উত্তর হওয়া উচিত । আরও বৈশিষ্ট্যগুলির জন্য সিউডো-এলোমেলো সংখ্যা জেনারেশন রেফারেন্স
alextoind

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

1
@ অ্যালবার্টোম, দুর্ভাগ্যক্রমে, আপনার যে তুলনাটি উল্লেখ করা হয়েছে তা যথেষ্ট বিশদ সরবরাহ করে না এবং পুনরুত্পাদনযোগ্য নয়, যা এটি সন্দেহজনক করে তোলে (তদ্ব্যতীত, এটি ২০১৫ সাল থেকে, আমার উত্তর ২০১৩ সাল পর্যন্ত)। এটি ভাল হতে পারে যে আশেপাশে আরও ভাল পদ্ধতি রয়েছে (এবং ভবিষ্যতে আশা করা যায়, minstdএমন পদ্ধতি হবে) তবে এটি অগ্রগতি। এর দুর্বল বাস্তবায়ন হিসাবে random_device- এটি ভয়াবহ এবং এটি একটি বাগ হিসাবে বিবেচনা করা উচিত (সম্ভবত এটি সি ++ স্ট্যান্ডার্ডেরও যদি এটি অনুমতি দেয় তবে)।
ওয়াল্টার

1
আমি আপনার সাথে সম্পূর্ণ একমত; আমি আসলে আপনার প্রতি সমাধানের সমালোচনা করতে চাইনি, কেবল নৈমিত্তিক পাঠককে সতর্ক করতে চেয়েছিলাম যে সি ++ 11 এর প্রতিশ্রুতি থাকা সত্ত্বেও বিষয়টি সম্পর্কে চূড়ান্ত উত্তরটি এখনও লেখা যায়নি। আমি সম্পর্কিত প্রশ্নের উত্তর হিসাবে 2015 হিসাবে এই বিষয়টির একটি ওভারভিউ পোস্ট করতে যাচ্ছি ।
আলবার্তো এম

1
এটাই কি ‘সিম্পল’? আপনি কী ব্যাখ্যা করতে পারেন যে স্পষ্টতই সহজ সরল rand()কোনও বিকল্প নয় এবং এটি কি অ-সমালোচনামূলক ব্যবহারের জন্য যেমন একটি এলোমেলো পিভট সূচক তৈরির মতো গুরুত্বপূর্ণ? এছাড়াও, আমাকে কি টাইট লুপ / ​​ইনলাইনড ফাংশন random_device/ mt19937/ নির্মাণের বিষয়ে চিন্তা করতে হবে uniform_int_distribution? আমি বরং তাদের চারপাশে পাস পছন্দ করা উচিত?
bluenote10

60

যদি আপনার সংকলক সি ++ 0x সমর্থন করে এবং এটি ব্যবহার করা আপনার পক্ষে একটি বিকল্প হয় তবে নতুন মানক <random>শিরোনামটি আপনার প্রয়োজনগুলি পূরণ করবে likely এটির একটি উচ্চমান রয়েছে uniform_int_distributionযা সর্বনিম্ন এবং সর্বাধিক সীমা গ্রহণ করবে (আপনার প্রয়োজন মতো অন্তর্ভুক্ত) এবং আপনি এই বন্টনটি প্লাগ করতে বিভিন্ন এলোমেলো সংখ্যা জেনারেটরগুলির মধ্যে চয়ন করতে পারেন।

এখানে এমন কোড যা এক মিলিয়ন এলোমেলো intগুলি তৈরি করে যা একইভাবে বিতরণ করা হয় [-57, 365]। <chrono>আপনার সময়কালে নতুন স্ট্যান্ডার্ড সুবিধাটি ব্যবহার করেছি কারণ আপনি উল্লেখ করেছেন যে পারফরম্যান্স আপনার জন্য একটি প্রধান উদ্বেগ।

#include <iostream>
#include <random>
#include <chrono>

int main()
{
    typedef std::chrono::high_resolution_clock Clock;
    typedef std::chrono::duration<double> sec;
    Clock::time_point t0 = Clock::now();
    const int N = 10000000;
    typedef std::minstd_rand G;
    G g;
    typedef std::uniform_int_distribution<> D;
    D d(-57, 365);
    int c = 0;
    for (int i = 0; i < N; ++i) 
        c += d(g);
    Clock::time_point t1 = Clock::now();
    std::cout << N/sec(t1-t0).count() << " random numbers per second.\n";
    return c;
}

আমার জন্য (২.৮ গিগাহার্টজ ইন্টেল কোর আই ৫) এটি মুদ্রণ করে:

2.10268e + 07 প্রতি সেকেন্ডে এলোমেলো সংখ্যা।

আপনি জেনারেটরটি এর নির্মাতার কাছে কোনও ইনটি দিয়ে গিয়ে বীজ করতে পারেন:

    G g(seed);

যদি আপনি পরে আবিষ্কার করেন যে intআপনার বিতরণের জন্য আপনার প্রয়োজনীয় পরিসরটি অন্তর্ভুক্ত করে না, তবে এর uniform_int_distributionমতো পরিবর্তন করে প্রতিকার করা যেতে পারে (উদাহরণস্বরূপ long long):

    typedef std::uniform_int_distribution<long long> D;

আপনি যদি পরে দেখতে পান যে এটি minstd_randকোনও উচ্চ মানের মানের জেনারেটর নয়, তবে এটি সহজেই সরিয়ে নেওয়া যেতে পারে। উদাহরণ:

    typedef std::mt19937 G;  // Now using mersenne_twister_engine

এলোমেলো সংখ্যা জেনারেটরের উপর পৃথক নিয়ন্ত্রণ রাখা এবং এলোমেলো বিতরণটি বেশ মুক্ত হতে পারে।

আমি এই বিতরণের প্রথম 4 "মুহুর্তগুলি" ব্যবহার (ব্যবহার করে minstd_rand) গণনা করেছি (দেখানো হয়নি ) এবং বিতরণের গুণমানকে পরিমাপের প্রয়াসে তাদের তাত্ত্বিক মানগুলির সাথে তুলনা করেছি :

min = -57
max = 365
mean = 154.131
x_mean = 154
var = 14931.9
x_var = 14910.7
skew = -0.00197375
x_skew = 0
kurtosis = -1.20129
x_kurtosis = -1.20001

( x_উপসর্গটি "প্রত্যাশিত" বোঝায়)


3
এই উত্তরটি একটি সংক্ষিপ্ত সংক্ষিপ্ত কোড স্নিপেট ব্যবহার করতে পারে যা কেবলমাত্র এমন কোডটি দেখায় যা আসলে একটি পরিসীমা থেকে একটি এলোমেলো পূর্ণসংখ্যার উত্পাদন করতে প্রয়োজনীয়।
arekolek

সর্বনিম্ন বিতরণ কখনই পরিবর্তন হয় না এই সমস্যাটি দ্বারা সমস্যাটিকে আরও সহজ করা হয়েছে। আপনার যদি dপ্রতিটি পুনরাবৃত্তিতে বিভিন্ন সীমানা তৈরি করতে হয়? এটি কতটা লুপটি ধীর করবে?
কোয়ান্ট_দেব

15

আসুন সমস্যাটি দুটি ভাগে বিভক্ত করুন:

  • n(সর্বোচ্চ-মিনিট) মাধ্যমে 0 ব্যাপ্তিতে একটি এলোমেলো সংখ্যা তৈরি করুন ।
  • এই সংখ্যাটিতে মিনিট যোগ করুন

প্রথম অংশটি স্পষ্টতই সবচেয়ে কঠিন। আসুন ধরে নেওয়া যাক র‌্যান্ডের () এর রিটার্ন মান পুরোপুরি অভিন্ন। মডুলো ব্যবহার করা প্রথম (RAND_MAX + 1) % (max-min+1)সংখ্যাগুলিতে পক্ষপাত যুক্ত করবে । সুতরাং আমরা যদি যাদুতে পরিবর্তন RAND_MAXকরতে RAND_MAX - (RAND_MAX + 1) % (max-min+1)পারি তবে আর কোনও পক্ষপাত নেই।

দেখা যাচ্ছে যে আমরা যদি আমাদের অ্যালগরিদমের চলমান সময়ে সিউডো-ননডেটেরিনিজমকে অনুমতি দিতে রাজি হই তবে আমরা এই স্বজ্ঞাততাটি ব্যবহার করতে পারি। যখনই র‌্যান্ড () খুব বড় একটি সংখ্যা ফেরত দেয় আমরা পর্যাপ্ত পরিমাণে একটি নম্বর না পাওয়া পর্যন্ত আমরা অন্য একটি এলোমেলো সংখ্যা জিজ্ঞাসা করি।

চলমান সময়টি এখন জ্যামিতিকভাবে বিতরণ করা হয়েছে , প্রত্যাশিত মান সহ 1/pযেখানে pপ্রথম চেষ্টাতে খুব কম সংখ্যক সংখ্যা পাওয়ার সম্ভাবনা রয়েছে। যেহেতু RAND_MAX - (RAND_MAX + 1) % (max-min+1)সর্বদা এর চেয়ে কম (RAND_MAX + 1) / 2, আমরা জানি p > 1/2, সুতরাং পুনরাবৃত্তির প্রত্যাশিত সংখ্যা যে কোনও পরিসরের জন্য সর্বদা দুজনের চেয়ে কম হবে। এই কৌশলটি দিয়ে একটি স্ট্যান্ডার্ড সিপিইউতে কয়েক সেকেন্ডেরও কম সময়ে কয়েক মিলিয়ন এলোমেলো সংখ্যা উত্পন্ন করা উচিত should

সম্পাদনা করুন:

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


সম্পূর্ণতার জন্য: এটি প্রত্যাখ্যান নমুনা
ইটারিওন

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

13

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

এখানে তাদের উদাহরণ যেখানে তারা ছয়-পক্ষীয় ডাই রোল করার জন্য একটি সাধারণ ফাংশন করে:

#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/variate_generator.hpp>

boost::mt19937 gen;

int roll_die() {
    boost::uniform_int<> dist(1, 6);
    boost::variate_generator<boost::mt19937&, boost::uniform_int<> > die(gen, dist);
    return die();
}

ওহ, এবং এই জেনারেটরের আরও কিছু ধোঁয়াশা কেবলমাত্র যদি আপনি নিশ্চিত না হন যে আপনি এটি একেবারে নিকৃষ্টতর হিসাবে ব্যবহার করতে পারেন rand():

মার্সেন টুইস্টার হ'ল ম্যাকোটো মাতসুমোটো এবং তকুজি নিশিমুরা উদ্ভাবিত একটি "এলোমেলো সংখ্যা" জেনারেটর; তাদের ওয়েবসাইটে অ্যালগরিদমের অসংখ্য বাস্তবায়ন অন্তর্ভুক্ত রয়েছে।

মূলত, মার্সেন টুইস্টার একটি খুব বড় লিনিয়ার-প্রতিক্রিয়া শিফট রেজিস্টার। অ্যালগরিদম একটি 19,937 বিট বীজের উপর পরিচালিত হয়, 32-বিট স্বাক্ষরযুক্ত পূর্ণসংখ্যার 624-উপাদান অ্যারেতে সঞ্চিত হয়। মান 2 ^ 19937-1 একটি মার্সেন প্রাইম; বীজকে হেরফের করার কৌশলটি একটি পুরানো "মোচড়ানোর" অ্যালগরিদমের উপর ভিত্তি করে - তাই নামটি "মার্সেন টুইস্টার"।

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


1
মার্সেন টুইস্টার হ'ল একটি ভাল জেনারেটর, তবে অন্তর্নিহিত জেনারেটর নির্বিশেষে তিনি যে সমস্যাটি অবশেষের সাথে মোকাবেলা করছেন।
জেরি কফিন

আমি বুস্টকে কেবল এলোমেলো জেনারেটরের জন্য ব্যবহার করতে চাই না, কারণ (যেহেতু আমার প্রকল্পটি একটি গ্রন্থাগার) এর অর্থ প্রকল্পের সাথে অন্য নির্ভরতা প্রবর্তন করা। ভবিষ্যতে আমি সম্ভবত এটি যেভাবেই ব্যবহার করতে বাধ্য হব, তাই আমি এই জেনারেটরে স্যুইচ করতে পারি।
মাতাজ জাবস্কি

1
@ জেরি কফিন কোন সমস্যা? আমি এটি অফার করলাম কারণ এটি তার সমস্ত প্রয়োজনীয়তা সন্তুষ্ট করেছে: এটি দ্রুত, এটি অভিন্ন ( boost::uniform_intবিতরণ ব্যবহার করে ), আপনি সর্বনিম্ন সর্বাধিক সীমাগুলি আপনার পছন্দমতো কিছুতে রূপান্তর করতে পারেন এবং এটি বীজযোগ্য।
অ্যাফেক্স

@ এমজাবস্কি সম্ভবত আমি তা থামাতে দেব না, যখন আমি আমার প্রকল্পগুলি আমার অধ্যাপকদের কাছে জমা দেওয়ার জন্য পাঠাতে হয়েছিলাম, তখন আমি কেবল প্রাসঙ্গিক বুস্ট শিরোলেখ ফাইলগুলিকে অন্তর্ভুক্ত করেছি; আপনার কোড সহ পুরো 40 এমবি বুস্ট লাইব্রেরিটি প্যাকেজ করার দরকার নেই। অবশ্যই আপনার ক্ষেত্রে এটি কপিরাইটের মতো অন্যান্য কারণে সম্ভবত সম্ভব হবে না ...
Aphex

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

11
int RandU(int nMin, int nMax)
{
    return nMin + (int)((double)rand() / (RAND_MAX+1) * (nMax-nMin+1));
}

এটি (nMax-nMin + 1) পূর্ণসংখ্যার 32768 পূর্ণসংখ্যার ম্যাপিং। (এনম্যাক্স-এনমিন + 1) ছোট (আপনার প্রয়োজন মতো) ম্যাপিংটি বেশ ভাল হবে। তবে নোট করুন যে (এনম্যাক্স-এনমিন + 1) বড় হলে ম্যাপিংটি কাজ করবে না (উদাহরণস্বরূপ - আপনি সমান সম্ভাবনার সাথে 32768 মানগুলিকে ম্যাপ করতে পারবেন না) equal যদি এই ধরণের রেঞ্জগুলির প্রয়োজন হয় - আপনার 15-বিট র‌্যান্ড () এর পরিবর্তে 32-বিট বা 64-বিট র্যান্ডম উত্স ব্যবহার করা উচিত, বা সীমার বাইরে থাকা র্যান্ড () ফলাফলগুলি উপেক্ষা করা উচিত।


এর অ জনপ্রিয়তা সত্ত্বেও, আমি আমার অ-বৈজ্ঞানিক প্রকল্পগুলির জন্য এটিও ব্যবহার করি। সহজেই বুঝতে পারবেন (আপনার গাণিতিক ডিগ্রির প্রয়োজন নেই) এবং পর্যাপ্ত পরিশ্রম করুন (এটি ব্যবহার করে কোনও কোডই প্রোফাইল করতে হয়নি)। :) বড় পরিসরের ক্ষেত্রে, আমি অনুমান করি যে আমরা দুটি র‌্যান্ড () মান একসাথে স্ট্রিং করতে পারব এবং 30-বিট মান ধরে কাজ করতে পারি (ধরে নিয়েছি RAND_MAX = 0x7fff, অর্থাৎ 15 এলোমেলো বিট)
ইফোটিনিস

পরিবর্তন RAND_MAXকরার জন্য (double) RAND_MAXওভারফ্লো সতর্কবার্তা পূর্ণসংখ্যা এড়ানো।
অ্যালেক্স

4

এখানে একটি নিরপেক্ষ সংস্করণ যা এতে নম্বর উত্পন্ন করে [low, high]:

int r;
do {
  r = rand();
} while (r < ((unsigned int)(RAND_MAX) + 1) % (high + 1 - low));
return r % (high + 1 - low) + low;

যদি আপনার পরিসরটি যথাযথভাবে ছোট হয় তবে doলুপের তুলনায় ডানদিকে ক্যাশে দেওয়ার কোনও কারণ নেই ।


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

@ জেরি: দয়া করে নতুন সংস্করণটি দেখুন।
যেরেমিয়া উইলকক

সঠিকভাবে কাজ করা সম্পর্কে আমি কিছুটা অনিশ্চিত। এটি হতে পারে তবে সঠিকতা কমপক্ষে আমার কাছে সুস্পষ্ট বলে মনে হচ্ছে না।
জেরি কফিন 21

@ জেরি: এখানে আমার যুক্তি রয়েছে: ধরুন পরিধিটি [0, h)সরলতার জন্য। কল rand()করার RAND_MAX + 1সম্ভাব্য রিটার্ন মান রয়েছে; গ্রহণ rand() % hভেঙে (RAND_MAX + 1) / hপ্রত্যেকটি তাদের h, আউটপুট মান ছাড়া (RAND_MAX + 1) / h + 1তাদের মান কম হয় ম্যাপ করা হয় (RAND_MAX + 1) % h(মাধ্যমে গত আংশিক চক্রের কারণ hআউটপুট)। তাই আমরা (RAND_MAX + 1) % hনিরপেক্ষ বিতরণ পেতে সম্ভাব্য ফলাফলগুলি সরিয়ে ফেলি।
যেরেমিয়া উইলকক

3

আমি বুস্ট.র্যান্ডম লাইব্রেরিটি সুপারিশ করি , এটি অত্যন্ত বিস্তৃত এবং যথাযথভাবে নথিবদ্ধ, আপনি কী বিতরণ চান তা স্পষ্ট করে নির্দিষ্ট করতে দেয় এবং অ-ক্রিপ্টোগ্রাফিক পরিস্থিতিতে বাস্তবে একটি সাধারণ সি লাইব্রেরি র্যান্ড বাস্তবায়নকে ছাড়িয়ে যেতে পারে ।


1

ধরুন ন্যূনতম এবং সর্বাধিক ইনট মানগুলি, [এবং] অর্থ এই মানটি অন্তর্ভুক্ত করে (এবং) এর অর্থ সি ++ র্যান্ড () ব্যবহার করে সঠিক মান পেতে উপরের ব্যবহার করে এই মানটি অন্তর্ভুক্ত করা হয় না

রেফারেন্স: () [] সংজ্ঞায়িত করার জন্য, দেখুন:

https://en.wikipedia.org/wiki/Interval_(mathematics)

র্যান্ড এবং শ্রেন্ড ফাংশন বা RAND_MAX সংজ্ঞায়িত করার জন্য, দেখুন:

http://en.cppreference.com/w/cpp/numeric/random/rand

[মিনিট, সর্বাধিক]

int randNum = rand() % (max - min + 1) + min

(সর্বনিম্ন, সর্বাধিক]

int randNum = rand() % (max - min) + min + 1

[মিনিট, সর্বাধিক)

int randNum = rand() % (max - min) + min

(সর্বনিম্ন, সর্বোচ্চ)

int randNum = rand() % (max - min - 1) + min + 1

0

এই থ্রেডে প্রত্যাখ্যানের নমুনা ইতিমধ্যে আলোচনা করা হয়েছিল, তবে আমি rand() % 2^somethingইতিমধ্যে উপরে উল্লিখিত হিসাবে কোনও পক্ষপাতদর্শন প্রবর্তন না করে যে ভিত্তিতে একটি অপ্টিমাইজেশন প্রস্তাব করতে চেয়েছিলেন ।

অ্যালগরিদম সত্যিই সহজ:

  • অন্তর দৈর্ঘ্যের চেয়ে 2 এর ক্ষুদ্রতম শক্তি গণনা করুন
  • "নতুন" ব্যবধানে একটি নম্বর এলোমেলো করুন
  • সংখ্যাটি যদি মূল বিরতির দৈর্ঘ্যের চেয়ে কম হয় তবে তা ফিরিয়ে দিন
    • অন্যথায় প্রত্যাখ্যান

এখানে আমার নমুনা কোড:

int randInInterval(int min, int max) {
    int intervalLen = max - min + 1;
    //now calculate the smallest power of 2 that is >= than `intervalLen`
    int ceilingPowerOf2 = pow(2, ceil(log2(intervalLen)));

    int randomNumber = rand() % ceilingPowerOf2; //this is "as uniform as rand()"

    if (randomNumber < intervalLen)
        return min + randomNumber;      //ok!
    return randInInterval(min, max);    //reject sample and try again
} 

এটি বিশেষত ছোট ব্যবধানগুলির জন্য ভালভাবে কাজ করে, কারণ 2 এর শক্তি আসল বিরতি দৈর্ঘ্যের "কাছাকাছি" হবে, এবং তাই মিসের সংখ্যা আরও কম হবে।

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


0

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

ধরে নিন যে আপনি পূর্ণসংখ্যার এলোমেলো সংখ্যার [সর্বনিম্ন, সর্বাধিক] অঞ্চল চান। আমরা [0, সর্বোচ্চ-মিনিট] থেকে শুরু করি

বেস নিন b = সর্বোচ্চ-মিনিট + 1

বেস বিতে র‌্যান্ড () থেকে প্রাপ্ত একটি নম্বর উপস্থাপন থেকে শুরু করুন।

এইভাবে আপনি মেঝে পেয়েছেন (লগ (বি, RAND_MAX)) কারণ বেস বিতে প্রতিটি সংখ্যা, সম্ভবত শেষটি ব্যতীত, [0, সর্বোচ্চ-মিনিট] পরিসরে একটি এলোমেলো সংখ্যা উপস্থাপন করে।

অবশ্যই চূড়ান্ত শিফট [মিনিট, সর্বাধিক] প্রতিটি এলোমেলো সংখ্যা r + মিনিটের জন্য সহজ।

int n = NUM_DIGIT-1;
while(n >= 0)
{
    r[n] = res % b;
    res -= r[n];
    res /= b;
    n--;
}

NUM_DIGIT যদি বেস বিতে অঙ্কের সংখ্যা হয় তবে আপনি এটি বের করতে পারেন এবং তা that

NUM_DIGIT = floor(log(b,RAND_MAX))

তারপরে উপরেরটি হ'ল <RAND_MAX সরবরাহকারী একটি RAND_MAX এর মধ্যে 0 থেকে বি -1 এ NUM_DIGIT এলোমেলো সংখ্যা বের করার সহজ বাস্তবায়ন হিসাবে।


-1

এর সূত্রটি খুব সহজ, তাই এই অভিব্যক্তিটি চেষ্টা করে দেখুন,

 int num = (int) rand() % (max - min) + min;  
 //Where rand() returns a random number between 0.0 and 1.0

2
পুরো সমস্যাটি সি / সি ++ এর র্যান্ড ব্যবহার করছিল যা রানটাইম দ্বারা নির্দিষ্ট রেঞ্জের পূর্ণসংখ্যাকে প্রদান করে। এই থ্রেডে প্রদর্শিত হিসাবে, [0, RAND_MAX] থেকে [MIN, MAX] এ এলোমেলোভাবে পূর্ণসংখ্যার ম্যাপিং পুরোপুরি সোজা নয়, যদি আপনি তাদের পরিসংখ্যানগত বৈশিষ্ট্য বা কার্য সম্পাদন করতে না চান। আপনার যদি [0, 1] পরিসীমা দ্বিগুণ হয় তবে ম্যাপিংটি সহজ।
মাতাজ জাবস্কি

2
আপনার উত্তরটি ভুল, আপনার পরিবর্তে মডুলাসটি ব্যবহার করা উচিত:int num = (int) rand() % (max - min) + min;
জাইমে ইভান সার্ভেন্টস

-2

যদি আমার ভুল না হয় তবে নিম্নলিখিত মত প্রকাশের পক্ষপাতহীন হওয়া উচিত:

std::floor( ( max - min + 1.0 ) * rand() ) + min;

আমি এখানে ধরে নিচ্ছি যে র‌্যান্ড () আপনাকে ০.০ এবং ১.০ এর মধ্যে পরিসরে একটি এলোমেলো মান দেয় 1.0 এবং এই সর্বাধিক এবং ন্যূনতম শর্তটি কমপক্ষে <ম্যাক্স সর্বোচ্চ gers


std::floorফিরে আসে double, এবং আমাদের এখানে একটি পূর্ণসংখ্যার মান প্রয়োজন। আমি কেবল intব্যবহারের পরিবর্তে কাস্ট করব std::floor
ম্যাসিফিল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.