এলোমেলো ফ্লোট নম্বর প্রজন্ম


271

আমি কীভাবে সি ++ এ এলোমেলো ফ্লোটগুলি উত্পন্ন করব?

আমি ভেবেছিলাম যে আমি পূর্ণসংখ্যাটি র‌্যান্ড নিতে এবং এটি কোনও কিছুর দ্বারা ভাগ করতে পারি, এটি কি পর্যাপ্ত পর্যাপ্ত হবে?


2
এটি নির্ভর করে আপনি কীসের জন্য নম্বর চান এবং কীভাবে এলোমেলো। সাধারণত র‌্যান্ড () এলোমেলোভাবে 15 বিট দেবে, তবে ফ্লোটে 23 বিট নির্ভুলতা থাকে, সুতরাং এটি কিছু মান মিস করবে।
পিট কির্খাম

1
আমি উপলব্ধ সমস্ত বড় বিকল্পগুলিকে অন্তর্ভুক্ত করার জন্য আমার উত্তর আপডেট করেছি randomএবং সি ++ 11 এ যুক্ত শিরোনামের দিকে মনোনিবেশ করার জন্য আমার পছন্দটি স্ট্যান্ডার্ড ডকুমেন্ট এন 3924: সি ++ 14 এ নিরুৎসাহিত র‌্যান্ড () দ্বারা উত্সাহিত । আমি rand()আমার উত্তরে বেশিরভাগ historicalতিহাসিক বিবেচনার জন্য অন্তর্ভুক্ত করি তবে উত্তরাধিকারের প্রয়োগটি উপলব্ধি করেও উপস্থিত রয়েছে।
শফিক ইয়াঘমোর

আমার উত্তরে অন্তর্ভুক্ত রয়েছে কীভাবে প্রতিবার <random>শিরোনামের সাথে একই নম্বর পাওয়া এড়ানো যায়
Andreas DM

উত্তর:


381

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


এটি অন্তর্ভুক্ত সহ 0.0 থেকে 1.0 পর্যন্ত একটি সংখ্যা উত্পন্ন করবে।

float r = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);

এই কিছু নির্বিচারে করার 0.0 থেকে একটি নম্বরে উত্পন্ন করবে float, X:

float r2 = static_cast <float> (rand()) / (static_cast <float> (RAND_MAX/X));

এই কিছু নির্বিচারে থেকে একটি নম্বরে উত্পন্ন করবে LOকিছু অবাধ করার HI:

float r3 = LO + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(HI-LO)));

মনে রাখবেন যে আপনার rand()সত্যিকারের এলোমেলো সংখ্যার প্রয়োজন হলে ফাংশনটি প্রায়শই পর্যাপ্ত হবে না।


কল করার আগে rand()আপনাকে অবশ্যই প্রথমে কল করে র্যান্ডম নম্বর জেনারেটরটি "বীজ" করতে হবে srand()। এটি আপনার প্রোগ্রামের চলাকালীন একবারে করা উচিত - আপনি যখন একবার কল করবেন তখনই নয় rand()। এটি প্রায়শই এভাবে করা হয়:

srand (static_cast <unsigned> (time(0)));

কল করতে randবা srandআপনাকে অবশ্যই করতে হবে #include <cstdlib>

কল করার জন্য time, আপনাকে অবশ্যই #include <ctime>


22
প্রথমে বীজ দিতে ভুলবেন না!
ক্লাইম

14
উভয় সীমা অন্তর্ভুক্ত হয় তা লক্ষ করা ভাল।
ডিএমকেকে --- প্রাক্তন মডারেটর বিড়ালছানা

14
এই উত্তরটি বিভ্রান্তিকর। এটি গত সপ্তাহে গাইটিং নেটিভ 2013 এ আচ্ছাদিত ছিল; র্যান্ড () ক্ষতিকারক হিসাবে বিবেচিত, চ্যানেল 9.msdn.com/Events/GoingNative/2013/… খুব বিশদ ব্যাখ্যার জন্য।
অ্যাডে মিলার

14
আমি বুঝতে পারি না কেন এত লোক কেন এই উত্তরটিকে আপগ্রেটেড করেছিল। এটি গাণিতিকভাবে ভুল। RAND_MAX একটি খুব ছোট সংখ্যা (সাধারণত 2 ^ 16)। এর অর্থ ফ্লোটিং পয়েন্টের 23 বিট থেকে আপনি কেবল 15 টি এলোমেলো করে তোলে। অন্যরা সম্ভবত শূন্য হবে। আপনি প্রকৃতপক্ষে অভিন্ন বিতরণে এলোমেলো সংখ্যা পাবেন তবে কম নির্ভুলতার। উদাহরণস্বরূপ আপনার এলোমেলো জেনারেটর 0.00001 এবং 0.00002 জেনারেট করতে পারে তবে 0.000017 জেনারেট করতে পারে না। সুতরাং আপনার অভিন্ন বিতরণ রয়েছে তবে স্বল্প নির্ভুলতার (প্রকৃত ভাসমান পয়েন্টের তুলনায় 256 গুণ কম নির্ভুলতা)।
ড্যানিয়েলএইচএসএইচ

10
@ ড্যানিয়েলএইচএসএইচ: ওপি বিশেষত জিজ্ঞাসা করেছিল যে এলোমেলোভাবে ভাসমান জেনারেট করতে কী কী মেকানিক্স ব্যবহার করা যেতে পারে rand()। এই প্রশ্নটি এবং আমার উত্তরটি বিশেষত বেসিকগুলি শেখার উপর নিবদ্ধ ছিল এবং উচ্চতর ডিগ্রিটি সম্পর্কে নির্ভুল ছিল না। দৌড়াতে শিখতে পারার আগে আপনাকে হাঁটা শিখতে হবে।
জন ডিবলিং

137

সি ++ 11 আপনাকে প্রচুর নতুন বিকল্প দেয় random। এই বিষয়টির মূল প্রবন্ধটি N3551, সি ++ 11 এ র্যান্ডম নম্বর জেনারেশন হবে

কেন ব্যবহার rand()করা সমস্যাযুক্ত হতে পারে তা দেখতে , GoingNative 2013 ইভেন্টের সময় দেওয়া স্টিফান টি। লাভভেজের র্যান্ড () বিবেচিত ক্ষতিকারক উপস্থাপনা উপাদানটি দেখুন । স্লাইডগুলি মন্তব্যে রয়েছে তবে এখানে একটি সরাসরি লিঙ্ক

আমি লিখিতভাবে কোডটি boostব্যবহারের পাশাপাশি randলেগ্যাসি কোডটি এখনও এর সমর্থন প্রয়োজন হতে পারে ব্যবহার করে ।

নীচের উদাহরণে cppreference সাইট থেকে চুয়ান এবং ব্যবহার করা হয় এসটিডি :: mersenne_twister_engine ইঞ্জিন এবং এসটিডি :: uniform_real_distribution যা সংখ্যার উত্পন্ন [0,10)ব্যবধান, অন্যান্য ইঞ্জিন ও ডিস্ট্রিবিউশন আউট মন্তব্য সঙ্গে ( এটা লাইভ দেখতে পাবেন ):

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>

int main()
{
    std::random_device rd;

    //
    // Engines 
    //
    std::mt19937 e2(rd());
    //std::knuth_b e2(rd());
    //std::default_random_engine e2(rd()) ;

    //
    // Distribtuions
    //
    std::uniform_real_distribution<> dist(0, 10);
    //std::normal_distribution<> dist(2, 2);
    //std::student_t_distribution<> dist(5);
    //std::poisson_distribution<> dist(2);
    //std::extreme_value_distribution<> dist(0,2);

    std::map<int, int> hist;
    for (int n = 0; n < 10000; ++n) {
        ++hist[std::floor(dist(e2))];
    }

    for (auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }
}

আউটপুট নিম্নলিখিত মত হবে:

0 ****
1 ****
2 ****
3 ****
4 *****
5 ****
6 *****
7 ****
8 *****
9 ****

আপনি কোন ডিস্ট্রিবিউশনটি বেছে নেবেন তার উপর নির্ভর করে আউটপুট পরিবর্তিত হবে, সুতরাং আমরা যদি স্ট্যান্ড :: নরমাল_ডিজিবিউটেশন2 উভয়ের জন্য যেমন গড় এবং এসটিডিডিভের সাথে মান নির্ধারণ করি তবেdist(2, 2) পরিবর্তে আউটপুটটি এর অনুরূপ হবে ( এটি সরাসরি দেখুন ):

-6 
-5 
-4 
-3 
-2 **
-1 ****
 0 *******
 1 *********
 2 *********
 3 *******
 4 ****
 5 **
 6 
 7 
 8 
 9 

নীচে উপস্থাপিত কিছু কোডের পরিবর্তিত সংস্করণ রয়েছে N3551( এটি সরাসরি দেখুন ):

#include <algorithm>
#include <array>
#include <iostream>
#include <random>

std::default_random_engine & global_urng( )
{
    static std::default_random_engine u{};
    return u ;
}

void randomize( )
{
    static std::random_device rd{};
    global_urng().seed( rd() );
}

int main( )
{
  // Manufacture a deck of cards:
  using card = int;
  std::array<card,52> deck{};
  std::iota(deck.begin(), deck.end(), 0);

  randomize( ) ;  

  std::shuffle(deck.begin(), deck.end(), global_urng());
  // Display each card in the shuffled deck:
  auto suit = []( card c ) { return "SHDC"[c / 13]; };
  auto rank = []( card c ) { return "AKQJT98765432"[c % 13]; };

  for( card c : deck )
      std::cout << ' ' << rank(c) << suit(c);

   std::cout << std::endl;
}

ফলাফলগুলি এর মতো দেখাবে:

5H 5S AS 9S 4D 6H TH 6D KH 2S QS 9H 8H 3D KC TD 7H 2D KS 3C TC 7D 4C QH QC QD QD জেডি এইচ জেসি এসি কেডি 9D 5C 2H 4H 9C 8C JH 5D 4S 7C AD 3S 8S TS 2C 8D 3H 6C JS 7 এস 6 এস

প্রচার করা

অবশ্যই বুস্ট.র্যান্ডম হ'ল সর্বদা একটি বিকল্প, এখানে আমি বুস্ট :: এলোমেলো :: ইউনিফর্ম_আরাল_স্তরন ব্যবহার করছি :

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_real_distribution.hpp>

int main()
{
    boost::random::mt19937 gen;
    boost::random::uniform_real_distribution<> dist(0, 10);

    std::map<int, int> hist;
    for (int n = 0; n < 10000; ++n) {
        ++hist[std::floor(dist(gen))];
    }

    for (auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }
}

RAND ()

আপনার যদি অবশ্যই ব্যবহার করা হয় rand()তবে আমরা কীভাবে ভাসমান-পয়েন্টের এলোমেলো সংখ্যা তৈরি করতে পারি তার গাইডগুলির জন্য সি এফকিউতে যেতে পারি? , যা অন্তর অন্তর একটি উত্পন্ন করার জন্য এটির অনুরূপ উদাহরণ দেয় [0,1):

#include <stdlib.h>

double randZeroToOne()
{
    return rand() / (RAND_MAX + 1.);
}

এবং এর থেকে পরিসীমাটিতে একটি এলোমেলো সংখ্যা তৈরি করতে [M,N):

double randMToN(double M, double N)
{
    return M + (rand() / ( RAND_MAX / (N-M) ) ) ;  
}

1
আপনি আপনার randMToNপ্লিজ ঠিক করতে পারেন ? হয় এটি নোট [M,N]করুন বা উপরেরটি + 1.থেকে পিছনে যুক্ত করুন randZeroToOne। -> এটিকে এভাবে কল করার কথা randMToN(0.0, 1.0);
ভাবুন

1
এদিকে শূন্য দ্বারা বিভাজন সম্পর্কে সতর্কতা অবলম্বন করুন (N-M)। এই ত্রুটিটি মোকাবেলা করার একটি দুর্দান্ত উপায় এখানে পাওয়া যায়: stackoverflow.com/questions/33058848/…
ডাঃ বেকো

61

বুস্ট.র্যান্ডমএকবার দেখুন । আপনি এরকম কিছু করতে পারেন:

float gen_random_float(float min, float max)
{
    boost::mt19937 rng;
    boost::uniform_real<float> u(min, max);
    boost::variate_generator<boost::mt19937&, boost::uniform_real<float> > gen(rng, u);
    return gen();
}

চারপাশে খেলুন, আপনি প্রতিবার নতুন তৈরির পরিবর্তে প্রায় একই এমটি 19937 অবজেক্টটি উত্তরণ করতে পারেন তবে আশা করি আপনি ধারণাটি পেয়ে আসবেন।


1
ইউনিফর্ম_রিয়াল একটি অর্ধ-খোলা ব্যবধান [মিনিট, সর্বাধিক) ব্যবহার করে যার অর্থ আপনি আপনার সর্বনিম্ন মান পাবেন তবে কখনও কখনও সর্বোচ্চ মানের কাছে পৌঁছাতে পারবেন না। এটি বিবেচনা করার মতো বিষয়, যদিও আপনি যদি কিছু উপায়ে গোল করেন তবে আপনি এই সমস্যাটি কাটিয়ে উঠতে পারেন।
তেহওয়ান

20
এটি এখন সি ++ 11 এর অংশ।
টমাস অ্যান্ড্রেল

ব্যবহারিক অ্যাপ্লিকেশনগুলিতে ওল্ড কোনও নির্দিষ্ট ভাসমান পয়েন্টের মানকে আঘাত করার প্রতিক্রিয়া এত কম যে শেষ পয়েন্টটি অন্তর্ভুক্ত করা হয়েছে বা বাদ দেওয়া হয়েছে তা বিবেচ্য নয়। আপনার যা দরকার তা যদি maxকিন্তু একটি সবিস্তার ব্যবহার করতে পারেন min, আপনি বিরতি সহজে বিপরীত করতে পারেন: return min + max - gen();
মার্ক রান্সম

26

আধুনিকতে c++আপনি <random>যে শিরোনামটি নিয়ে এসেছিলেন তা ব্যবহার করতে পারেন c++11
এলোমেলোভাবে পেতে floatআপনি ব্যবহার করতে পারেন std::uniform_real_distribution<>

আপনি সংখ্যার জেনারেট করতে একটি ফাংশন ব্যবহার করতে পারেন এবং যদি সংখ্যা একই হতে চাই না সব সময় হতে ইঞ্জিন ও বন্টন সেট static
উদাহরণ:

float get_random()
{
    static std::default_random_engine e;
    static std::uniform_real_distribution<> dis(0, 1); // rage 0 - 1
    return dis(e);
}

এটি floatএকটি পাত্রে যেমন রাখার জন্য আদর্শ std::vector:

int main()
{
    std::vector<float> nums;
    for (int i{}; i != 5; ++i) // Generate 5 random floats
        nums.emplace_back(get_random());

    for (const auto& i : nums) std::cout << i << " ";
}

উদাহরণ আউটপুট:

0.0518757 0.969106 0.0985112 0.0895674 0.895542

std::uniform_real_distribution<> dis(0, 1); // rage 0 - 1প্রযুক্তিগতভাবে ভুল, 1.0 কখনই উত্পন্ন হবে না, en.cppreferences.com/w/cpp/numeric/random/… দেখুন To create a distribution over the closed interval [a,b], std::nextafter(b, std::numeric_limits<RealType>::max()) may be used as the second parameter.
ট্রয়সিফ

1
এটি গ্রহণযোগ্য উত্তর হওয়া উচিত, এটি ২০২০ সালে প্রকাশিত হয়
অ্যালেক্স

25

কোডটিকে দুটি floatমান সহ কল ​​করুন, কোডটি কোনও পরিসরে কাজ করে।

float rand_FloatRange(float a, float b)
{
    return ((b - a) * ((float)rand() / RAND_MAX)) + a;
}

এটি উল্লেখ করার মতো হতে পারে যে এটি C99 বা সি ++ 11 এ fmaf()(বা fma()সি ++ তে ফ্লোট ওভারলোড) এর সম্ভাব্য ব্যবহারের কেস , যা আরও নির্ভুলতা রক্ষা করতে পারে। হিসাবে হিসাবে fmaf((float)rand() / RAND_MAX, b - a, a),।
টিম Čas

22

আপনি যদি সি ++ ব্যবহার করেন এবং সি নয়, তবে মনে রাখবেন যে প্রযুক্তিগত প্রতিবেদন 1 (টিআর 1) এবং সি ++ 0x খসড়াতে তারা শিরোনাম ফাইলটিতে একটি এলোমেলো সংখ্যা জেনারেটরের জন্য সুবিধা যুক্ত করেছে, আমি বিশ্বাস করি এটি বুস্টের মতোই। এলোমেলো গ্রন্থাগার এবং স্পষ্টভাবে সি লাইব্রেরির ফাংশনের চেয়ে আরও নমনীয় এবং "আধুনিক", র্যান্ড।

এই সিনট্যাক্স অফার জেনারেটরের (যেমন পছন্দ করে নিন ক্ষমতা mersenne প্রতারক একটি বন্টন (স্বাভাবিক, বের্নুলি দ্বিপদ ইত্যাদি) mt19937) এবং তারপর চয়ন।

সিনট্যাক্সটি নিম্নরূপ ( এই সাইট থেকে নির্লজ্জভাবে ধার করা ):

  #include <iostream>
  #include <random>

  ...

  std::tr1::mt19937 eng;  // a core engine class 
  std::tr1::normal_distribution<float> dist;     

  for (int i = 0; i < 10; ++i)        
      std::cout << dist(eng) << std::endl;

2
এটি এখন সি ++ 11 এ রয়েছে, এছাড়াও কমপক্ষে এবং সর্বাধিক মানগুলির সাহায্যে ডিস্টের শুরু করা যেতে পারে।
Étienne

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

6

কিছু সিস্টেমে (বর্তমানে ভিসি স্প্রিংসের সাথে উইন্ডোজ মনে রাখবেন) RAND_MAXহাস্যকরভাবে ছোট, i। ঙ। মাত্র 15 বিট। RAND_MAXআপনার দ্বারা বিভাজন করার সময় 23 টি সম্ভাব্য বিটের পরিবর্তে কেবল 15 বিটের একটি ম্যান্টিসা তৈরি করা হচ্ছে। এটি আপনার সমস্যা হতে পারে বা নাও হতে পারে তবে আপনি সেই ক্ষেত্রে কিছু মান মিস করছেন।

ওহ, কেবলমাত্র লক্ষ্য করেছেন যে এই সমস্যার জন্য ইতিমধ্যে একটি মন্তব্য রয়েছে। যাইহোক, এখানে কিছু কোড রয়েছে যা এটি আপনার জন্য সমাধান করতে পারে:

float r = (float)((rand() << 15 + rand()) & ((1 << 24) - 1)) / (1 << 24);

স্বীকৃত, তবে কাজ করতে পারে :-)


ফ্লোট আর = (ফ্লোট) ((র্যান্ড () << 9) | র্যান্ড ()) / আরএ এমএএমএএমএক্স সম্পর্কে কী? (অনির্ধারিতও)
ট্র্যাপ করুন

আরগ, দুঃখিত, RAND_MAX দ্বারা বিভাজন আপনাকে কোথাও নিয়ে যাবে না ... এই কৌশলটির পুরো বিন্দুটি ছিল RAND_MAX এর চেয়ে বড় কিছু ছিল ... এটি আমার জন্যও ঠিক করা হয়েছিল।
জোয়

2
তত্ত্ব ব্যতীত এলোমেলো সংখ্যা রচনা সম্পর্কে সতর্কতা অবলম্বন করুন ... র‌্যাণ্ডে (পরপর কল) সম্পূর্ণ স্বাধীন হতে পারে না। ইঙ্গিত: এটির যদি লিনিয়ার কংগ্রেসনাল জেনারেটর থাকে তবে একটানা কলগুলিতে কম বিটটি দেখুন: এটি 0 এবং 1 এর মধ্যে বিকল্প হয়
আরবার্টেইগ

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

(এনবি: এমএসভিসিতে র‌্যান্ড দ্বারা স্বল্প বিট ফিরে আসা আরএনজি রাষ্ট্রের সর্বনিম্ন বিট নয় 100 100 র্যান্ডের জন্য) কলগুলির জন্য আমি নিম্নলিখিতগুলি পাই: 110010000011111110101001001001010101010101010101010101011111100100000000010100011011000000100101100011. জাভা একটি 48-বিট এলসিজি ব্যবহার করে এবং কেবল 32C বিসিজি ব্যবহার করে এটি একইভাবে করতে)
জোয়

4

drand48(3)POSIX মানক উপায়। GLibC একটি প্রেরক সংস্করণ সরবরাহ করে drand48_r(3),।

এসভিআইডি 3 এ ফাংশনটি অপ্রচলিত ঘোষণা করা হয়েছিল তবে কোনও পর্যাপ্ত বিকল্প সরবরাহ করা হয়নি তাই আইইইই স্ট্যান্ড 1003.1-2013 এখনও এতে অন্তর্ভুক্ত রয়েছে এবং শীঘ্রই যে কোনও সময় এটি চলেছে এমন কোনও নোট নেই।

উইন্ডোজে, স্ট্যান্ডার্ড উপায় হ'ল ক্রিপটেনরানডম ()


2

আমি এখনও পর্যন্ত কোনও উত্তর দ্বারা সন্তুষ্ট ছিলাম না তাই আমি একটি নতুন এলোমেলো ফ্লোট ফাংশন লিখেছি। এটি ভাসমান ডেটা ধরণের সম্পর্কে কিছুটা ধারনা তৈরি করে। এটি এখনও কমপক্ষে 15 এলোমেলো বিট সহ একটি র‌্যান্ড () ফাংশন প্রয়োজন।

//Returns a random number in the range [0.0f, 1.0f).  Every
//bit of the mantissa is randomized.
float rnd(void){
  //Generate a random number in the range [0.5f, 1.0f).
  unsigned int ret = 0x3F000000 | (0x7FFFFF & ((rand() << 8) ^ rand()));
  unsigned short coinFlips;

  //If the coin is tails, return the number, otherwise
  //divide the random number by two by decrementing the
  //exponent and keep going. The exponent starts at 63.
  //Each loop represents 15 random bits, a.k.a. 'coin flips'.
  #define RND_INNER_LOOP() \
    if( coinFlips & 1 ) break; \
    coinFlips >>= 1; \
    ret -= 0x800000
  for(;;){
    coinFlips = rand();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    //At this point, the exponent is 60, 45, 30, 15, or 0.
    //If the exponent is 0, then the number equals 0.0f.
    if( ! (ret & 0x3F800000) ) return 0.0f;
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
  }
  return *((float *)(&ret));
}

7
আকর্ষণীয় পদ্ধতির, আমি
উঁচুতে

2

আমার মতে উপরের উত্তরগুলি কিছু 'এলোমেলো' ভাসা দেয় তবে এগুলির কোনওটিই সত্যিকার অর্থে একটি এলোমেলো ফ্লোট নয় (যেমন তারা ভাসমান উপস্থাপনার একটি অংশ মিস করে)। আমি আমার বাস্তবায়নে ছুটে যাবার আগে প্রথমে ভাসমানগুলির জন্য এএনএসআই / আইইইই স্ট্যান্ডার্ড ফর্ম্যাটটি দেখে নেওয়া যাক:

| চিহ্ন (1-বিট) | e (8-বিট) | f (23-বিট) |

এই শব্দের দ্বারা উপস্থাপিত সংখ্যাটি হ'ল (-1 * চিহ্ন) * 2 ^ ই * 1.f

নোট করুন যে 'ই' নম্বরটি পক্ষপাতদুষ্ট (127 এর পক্ষপাত সহ) এইভাবে -127 থেকে 126 অবধি রয়েছে The সর্বাধিক সরল (এবং প্রকৃতপক্ষে এলোমেলো) ফাংশনটি কেবল একটি ফ্লোটে র্যান্ডম ইন্টের ডেটা লিখতে হয়, এইভাবে

int tmp = rand();
float f = (float)*((float*)&tmp);

মনে রাখবেন আপনি float f = (float)rand();এটি করলে এটি পূর্ণসংখ্যাকে একটি ফ্লোটে রূপান্তরিত করে (এভাবে 10 হয়ে যাবে 10.0)।

সুতরাং এখন আপনি যদি সর্বাধিক মান সীমাবদ্ধ করতে চান তবে আপনি এমন কিছু করতে পারেন (নিশ্চিত না যে এটি কাজ করে কিনা)

int tmp = rand();
float f = *((float*)&tmp);
tmp = (unsigned int)f       // note float to int conversion!
tmp %= max_number;
f -= tmp;

তবে আপনি যদি ফ্লোটের কাঠামোটি দেখেন তবে দেখতে পাবেন যে একটি ফ্লোটের সর্বাধিক মান (আনুমানিক) 2 ^ 127 যা কোনও ইনট (2 ^ 32) এর সর্বাধিক মান হিসাবে বেশ বড়, এইভাবে একটি উল্লেখযোগ্য অংশকে অস্বীকার করে ruling যে সংখ্যাগুলি একটি ফ্লোট দ্বারা প্রতিনিধিত্ব করা যেতে পারে এটি আমার চূড়ান্ত বাস্তবায়ন:

/**
 * Function generates a random float using the upper_bound float to determine 
 * the upper bound for the exponent and for the fractional part.
 * @param min_exp sets the minimum number (closest to 0) to 1 * e^min_exp (min -127)
 * @param max_exp sets the maximum number to 2 * e^max_exp (max 126)
 * @param sign_flag if sign_flag = 0 the random number is always positive, if 
 *              sign_flag = 1 then the sign bit is random as well
 * @return a random float
 */
float randf(int min_exp, int max_exp, char sign_flag) {
    assert(min_exp <= max_exp);

    int min_exp_mod = min_exp + 126;

    int sign_mod = sign_flag + 1;
    int frac_mod = (1 << 23);

    int s = rand() % sign_mod;  // note x % 1 = 0
    int e = (rand() % max_exp) + min_exp_mod;
    int f = rand() % frac_mod;

    int tmp = (s << 31) | (e << 23) | f;

    float r = (float)*((float*)(&tmp));

    /** uncomment if you want to see the structure of the float. */
//    printf("%x, %x, %x, %x, %f\n", (s << 31), (e << 23), f, tmp, r);

    return r;
}

এই ফাংশনটি ব্যবহার করে randf(0, 8, 0)0.0 এবং 255.0 এর মধ্যে একটি এলোমেলো সংখ্যা ফিরে আসবে


1
তোমার একটা ভুল আছে র্যান্ড ()% frac_mod কাজ করবে না যেহেতু MAX_RAND সাধারণত (1 << 23) এর চেয়ে কম থাকে।
ড্যানিয়েলএইচএসএইচ

আমাকে স্বীকার করতে হবে যে আমি MAX_RAND এর সঠিক আকারটি জানি না। এটি এখনও যত কম কম কাজ করবে না, এটি সম্ভবত একটি অকেজো বিবৃতি, তবে এটি এখনও কার্যকর হবে। 8% 10 = 8 সুতরাং ঠিক আছে, তবে যদি MAX_RAND সর্বদা ছোট হয় তবে (1 << 23) আপনি অবশ্যই এটি মুছে ফেলতে পারেন।
ব্যবহারকারী 2546926

2
না, আপনি কিছুটা ভুল র্যান্ডম্যাক্স সাধারণত 65,000 ডলার। এর অর্থ 23 টি বিট থেকে আপনি কেবল 15 এলোমেলো করে। অন্যরা সম্ভবত শূন্য হবে। আপনি অবশ্যই এলোমেলো সংখ্যা পাবেন তবে স্বল্প নির্ভুলতার জন্য of উদাহরণস্বরূপ আপনার এলোমেলো জেনারেটর 0.001 এবং 0.002 উত্পাদন করতে পারে তবে 0.0017 জেনারেট করতে পারে না। সুতরাং আপনার অভিন্ন বিতরণ আছে তবে নিম্ন নির্ভুলতার (ফ্লোটের চেয়ে 256 গুণ কম নির্ভুলতা)।
ড্যানিয়েলএইচএসএইচ

এই উত্তরে দুটি ভুল রয়েছে। কাফের পরিসীমা নির্ধারণ: int e = (rand() % (max_exp - min_exp)) + min_exp_mod;এবং ম্যান্টিসা: int f = (int)(frac_mod * (float)rand() / RAND_MAX);উপরে তাদের নিজ নিজ রেখা প্রতিস্থাপন। লক্ষ্য করুন অংশক ভুল প্রধান বলে: RAND_MAXছোট 1 << 23আপনি শুধুমাত্র নিম্ন উল্লেখযোগ্য বিট randomise এবং সবচেয়ে গুরুত্বপূর্ণ বিট জন্য সব সময় 0 সেঃ পেতে চাই!
বায়িলারস্টুডিওগুলি

2

আপনি যদি জানেন যে আপনার ভাসমান পয়েন্ট ফর্ম্যাটটি আইইইই 754 (ইন্টেল এবং এআরএম সহ প্রায় সমস্ত আধুনিক সিপিইউ) তবে আপনি বিট-ওয়াইজ পদ্ধতি ব্যবহার করে একটি এলোমেলো পূর্ণসংখ্যার থেকে একটি এলোমেলো ভাসমান পয়েন্ট নম্বর তৈরি করতে পারেন। এটি কেবল তখনই বিবেচনা করা উচিত যখন আপনার সি ++ 11 এর অ্যাক্সেস নেই randomবা Boost.Randomযা উভয়ই অনেক বেশি ভাল।

float rand_float()
{
    // returns a random value in the range [0.0-1.0)

    // start with a bit pattern equating to 1.0
    uint32_t pattern = 0x3f800000;

    // get 23 bits of random integer
    uint32_t random23 = 0x7fffff & (rand() << 8 ^ rand());

    // replace the mantissa, resulting in a number [1.0-2.0)
    pattern |= random23;

    // convert from int to float without undefined behavior
    assert(sizeof(float) == sizeof(uint32_t));
    char buffer[sizeof(float)];
    memcpy(buffer, &pattern, sizeof(float));
    float f;
    memcpy(&f, buffer, sizeof(float));

    return f - 1.0;
}

এটি বিভাগ ব্যবহার করে একের চেয়ে ভাল বিতরণ দেবে।


8
আমি নিশ্চিত না আপনি কেন বলছেন এটি "আরও ভাল বিতরণ" দেবে। আসলে, এটি ঠিক যেমন একই বিতরণ দেবে return (float)random23 / (1 << 23)। (হ্যাঁ, আমি শুধু এই পরীক্ষিত , আপনার ফাংশন পরিবর্তন নিতে random32একটি প্যারামিটার হিসেবে এবং আপ শূন্য থেকে সব মান জন্য এটি চলমান (1 << 23)-1এবং হ্যাঁ, আপনার পদ্ধতি প্রকৃতপক্ষে ঠিক একই ফলাফল দ্বারা বিভাগ হিসেবে দিতে না। 1 << 23।)
Ilmari Karonen

1

সি ++ এর জন্য, এটি distভেরিয়েবল দ্বারা নির্দিষ্ট রেঞ্জের মধ্যে প্রকৃত ভাসমান সংখ্যা উত্পন্ন করতে পারে

#include <random>  //If it doesnt work then use   #include <tr1/random>
#include <iostream>

using namespace std;

typedef std::tr1::ranlux64_base_01 Myeng; 
typedef std::tr1::normal_distribution<double> Mydist;

int main() { 
       Myeng eng; 
       eng.seed((unsigned int) time(NULL)); //initializing generator to January 1, 1970);
       Mydist dist(1,10); 

       dist.reset(); // discard any cached values 
       for (int i = 0; i < 10; i++)
       {
           std::cout << "a random value == " << (int)dist(eng) << std::endl; 
       }

       return (0);
}

1
আপনি কি এই উত্তরটি থেকে কোডটি অনুলিপি করে কপি করেছেন? stackoverflow.com/a/1118739/1538531
ডেরেক

আসলে না। তারা কতটা দেখতে দেখতে আমি কিছুটা অবাক! তবে আমি ইঞ্জিন-জেনারেটর জানুয়ারী 1,1970 এ শুরু করেছি।
Marco167

যথেষ্ট ফর্সা। আমি লক্ষ্য করেছি যে আপনি জেনারেটরটিকে যুগের দিকে আরম্ভ করেছিলেন, তবে এই কোডটি একই রকমের করে নিন!
ডেরেক

আমি টিআর 1 উদাহরণ দিলে কিছুটা অদ্ভুত বলে মনে করি, আপনি কি সি -++ এর বিপরীতে কার ক্ষেত্রে টিআর 1 ব্যবহার করতে হবে তা ব্যাখ্যা করতে পারেন?
শফিক ইয়াঘমোর

0

র্যান্ড () 0 এবং RAND_MAX এর মধ্যে একটি পূর্বাবস্থায় ফিরে আসে। ০.০ থেকে ১.০ এর মধ্যে একটি এলোমেলো সংখ্যা পাওয়ার জন্য প্রথমে র্যান্ড () দ্বারা একটি ফ্লোটে প্রেরণ করুন, তারপরে RAND_MAX দিয়ে ভাগ করুন।


0
#include <cstdint>
#include <cstdlib>
#include <ctime>

using namespace std;

/* single precision float offers 24bit worth of linear distance from 1.0f to 0.0f */
float getval() {
    /* rand() has min 16bit, but we need a 24bit random number. */
    uint_least32_t r = (rand() & 0xffff) + ((rand() & 0x00ff) << 16);
    /* 5.9604645E-8 is (1f - 0.99999994f), 0.99999994f is the first value less than 1f. */
    return (double)r * 5.9604645E-8;
}

int main()
{
    srand(time(NULL));
...

আমি দুটি উত্তর পোস্ট করতে পারিনি, সুতরাং দ্বিতীয় সমাধানটি এখানে। লগ 2 এলোমেলো সংখ্যা, 0.0f এর দিকে বিশাল পক্ষপাত কিন্তু এটি সত্যই একটি এলোমেলো ফ্লোট 1.0f থেকে 0.0f।

#include <cstdint>
#include <cstdlib>
#include <ctime>

using namespace std;

float getval () {
    union UNION {
        uint32_t i;
        float f;
    } r;
    /* 3 because it's 0011, the first bit is the float's sign.
     * Clearing the second bit eliminates values > 1.0f.
     */
    r.i = (rand () & 0xffff) + ((rand () & 0x3fff) << 16);
    return r.f;
}

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