PDA

View Full Version : آموزش: نکات آستفاده از تابع رندوم



maktoom
دوشنبه 26 دی 1390, 15:57 عصر
سلام
حتما دوستان واردی قبلا توضیحات جامع و کاملی دادن. اما این چیزایی که در مجموع در مورد تابع رندوم می دونم:
تابع رندوم یه تابعیه که اگه خیلی ساده فراخونی بشه و اونو مساوی با یه متغیر قرار بدیم مقدار صحیحی بین 0 تا 9 رو بصورت رندوم داخل اون متغیر میریزه.
شما می تونید کار دادن ورودی رندوم برای جاهاییکه خروجی خاصی مورد نظرتون نیست به این شکل تولید کنید مثل مد یا بیشترین یا تعداد یا از این دست.
اما این روش ساده و ابتدایی نقص بزرگی داره:
1)اول اینکه اعداد رندوم تولید شده در هربار یکسان خواهند بود.راه حل:
برای تابع رندوم چیزی وجود داره به نامseed که اون تعیین می کنه اعداد رندوم چطور تولید بشه. در هربار راه انداختن برنامه باید این رو تنظیم کرد. میشه از کاربر بصورت دستی گرفتش. اما این هم زیاد جالب نیست. بهتره قبل از استفاده از تابع رندوم بوسیله ساعت سیستم Seed رو تنظیم کنیم.
2)دومین نکته اینه که ما شاید بخوایم اعداد تولید شده بصورت رندوم در یک بازه خاصی تولید بشن نه بین 0 تا 9. این دیگه یه سوال ریاضیاتیه تا یه مسئله برنامه نویسی. ما یه تابع داریم که اعدادی بین 0 تا 9 تولید می کنه. چکار کنیم تا بین کف و سقف ما باشن؟
اگر x یک عدد تصادفی بین 0 تا 9 باشه و a کف مقادیر دلخواه و b سقف مقادیر دلخواه باشنبا این فرمول اعداد تولیدی در بازه دلخواه ما قرار می گیرن:
Random=x%(b-a+1)+a;

کدی که تمام این موارد رو رعایت کرده و باشه و بشه توی برنامه ها اونو بکار برد به این شکله:
int *nums;//araye pooya
long int a,b,size,i,j;
//------------------------------------------------------------

printf(" tedad adad ra vared konid: "); //tedade adadi ke mikhahim tolid shavad
scanf("%d",&size);
nums=(int *)malloc(size * sizeof(long int));//ijade araye pooya
if(!nums)
{
printf("faza mojood nist!\n");
getch();
exit(1);
}
printf("kafe maghadir:");//baraye entekhabi kardane kaf va saghfe maghadire random ke dakhele araye pooya mirizim
scanf("%d",&a);
printf("saghfe maghadir:");
scanf("%d",&b);
srand(time(0));
for ( i = 0; i < size; i++ )//ijade adade random be tedade voroodiye khaste shode
{
int rand100 = rand()%(b-a+1)+a;
*(nums+i)=rand100;
}

بازم خوشحال میشم اگه دوستان بیان مواردی رو که می دونن به این تاپیک اضافه کنن. چیزایه خیلی ساده ای که شما می دونید، ممکنه در وقت بسیاری صرفه جویی کنه. این مواردی رو که گفتم در طی یک سال برطبق نیازهایی که باهاش روبرو شدم بدست آوردم. امیدوارم نکات ارزشمندی اینجا جمع بشه.

Cancer
دوشنبه 26 دی 1390, 17:35 عصر
سلام سلام سلام.
می دونی خود تابع رندم با چه فرمولی اعداد رندم تولید می کنه؟
چطوری خودمون یه تابع رندم بنویسیم؟

تشکر.

shahmohammadi
دوشنبه 26 دی 1390, 19:12 عصر
سلام.
تاپیک خوبی رو باز کردین.
تابع رند یه دنباله ای داره که اعداد خیلی زیادی توش هست. وقتی تابع می آد برای اولین بار فراخوانی می شه اولین عدد از این دنباله رو بر می گردونه، و در دفعه بعد عدد بعدی رو بر می گردونه و همی طور در دفعات بعدی فراخوانی تابع ادامه می ده. ولی این کار باعث می شه که هر بار که برنامه رو اجرا می کنیم عدد های تصادفی مشابهی تولید شند. برای اینکه این اتفاق نیفته تابع رند این امکان رو به ما داده که بیایم بگیم از کدوم عدد به بعد رو برگردونه که برای این کار از تابع srand که در بالا اشاره شد استفاده می شه. این تابع می آد عددی مثلا n رو می گیره و از اون به بعد تابع رند از nامین عدد شروع می کنه. حالا اگه در ابتدای برنامه زمان سیستم رو به تابع srand بدیم هر بار که برنامه باز می شه اعداد تصادفی متفاوبی تولید می شند.

غیر از این روش روش های دیگه ای هم استفاده می شه مثلا قبلا چند کد اسمبلی دیده بودم که با گرفتن بافر صفحه کلید و اعمال تغییرات در اون یا گرفتن زمان سیستم و باز اعمال تغییرات در اون (توی قسمت اسمبلی بحث شده) یه عدد تصادفی تولید می کردند.
چند وقت پیش باز یه جا یه نفر توی سی پلاس پلاس با تعریف کلاس و بعد ساختن یه شی از اون کلاس و بعدش از بین بردن همون شی یه طوری (که اون موقع نفهمیدم چطوری بود و بعدا هم لینکشو گم کردم) عدد تصادفی تولید می کرد. (شاید یه اشاره گر به اون شی تعریف می کرده، و آدرس اون یا محتوایات اون حافظه رو به عوان عدد تصادفی بر میگردونده، بعدا هرچقدر گشتم نتونستم پیداش کنم)
کلا به هر طریقی می شه تابع تولید اعداد تصادفی نوشت، و یکی از روشهایی که برای بررسی کارایی تابع بررسی می شه این هست که اگر این تابع 10000بار (مثلا) تکرار شه، آیا در بازه ای که اعداد رو تولید کرده اعداد تراکم مساوی دارند یا نه (یعنی شانس انتخاب شدن هر عدد توی بازه برابر باشه). که این رو هم با رسم یه نمودار می شه فهمید.

maktoom
دوشنبه 26 دی 1390, 21:12 عصر
مثلا راهی که بنظر من میرسه اینه که تویه تابع بیاد تعداد کلمات تا اینجای برنامه رو بشمره(باید بریزه تویه فایل) بعد اونو با مکان فعلی ثبات pc جمع کنه محتوای مکان بعدی pc را برگردونه باقی ماندش بر ده رو حساب کنه. اینجوری بازم شما یه تابع رندوم داری که بین 0 تا 9 بهت میده و با این فرمول میشه کف و سقف هم بهش داد.
کلا اگه با دستورات اسمبلی قاطیش کنی خیلی راه جدید بوجود میاد. که لازم به Seed دادن هم نباشه.

باز کسی راه بهتری سراغ نداره؟

Cancer
سه شنبه 27 دی 1390, 10:36 صبح
آره اینا راههای خوبی هستند.:متفکر:
خود تابع رند ++C چطوری کار می کنه؟
من زیاد اهل آمار نیستم ولی یه یارویی میگفت که تو آمار فرمولی هستی که بشه باهاش عدد رندم تولید کرد (تازه میگفت طوری رندم تولید کرد که مثلاً اگه 10 اعداد رندم بین 0 تا 9 هر کدوم یک بار تولید کنه) تو اون بخش مربوط به کارت شارژ ایرانسل که بحث اصلیش رو عدد رندم می چرخید گفتن (فکر کنم).

shahmohammadi
سه شنبه 27 دی 1390, 10:47 صبح
خود تابع رند ++C چطوری کار می کنه؟بند اول حرفای من هم در مورد همین هست. توی کتاب دیتل دیتل ترجمه صاحت الزمانی خونده بودم.
این طور که من می دونم توی هر زبان برنامه نویسی یه تابع پایه ای هست که می تونه فقط اعداد تصادفی تولید کنه. بعدا هر فرمولی که بخاهیم استفاده کنیم (مثل مثالتون برای کارت شارژ ایرانسل) از همین تابع استفاده می کنه.

Salar Ashgi
سه شنبه 27 دی 1390, 22:11 عصر
موضوع تاپیک تکراری است ولی امیدوارم اهداف آن تکراری نباشد .

در مورد سوالی که پرسیدن : بله ، شما خودتون می تونید تابع تصادفی تولید کنید با استفاده ترکیب فرمولهای
آماری و نظریه اعداد و همچنین استفاده از توزیع های نرمال در علم آمار .

اما راجب چگونگی پیاده سازی تابع تولید اعداد تصادفی : http://www.johndcook.com/cpp_TR1_random.html

Salar Ashgi
سه شنبه 27 دی 1390, 22:17 عصر
بعنوان نکته راجب این بحث ، مثلا میتوان تولید اعداد تصادفی اعشاری بین صفر و یک را در نظر گرفت :



#include <iostream>
#include <conio>
#include <stdlib>
int main(){
srand(time(0));
double x = (double)(1+rand()%10)/10;// x<1 & x>0
cout<<x<<endl;
getch();
}

shahmohammadi
سه شنبه 27 دی 1390, 22:52 عصر
برای تولید اعداد اعشاری بین 0 و 1 تابع بالا مثال خوبی هست. اعدادی که تولید می کنه:0.1، 0.2، 0.3،...، 0.9، 1 هست. ملاحظه می شه که اعدادی مثل 0.11 تولید نمی شند. هر چقدر از عدد بزرگ تری به جای 10 استفاده کنیم تابع اعداد بیشتری رو توی این بازه تولید میکنه.
می تونیم به جای عدد 10، از عدد 32767 که بزرگترین عددی هست که در اینت ذخیره میشه و یا از ماکروی RAND_MAX که مقدارش همون 32767 هست استفاده کنیم.
double x = (double)(rand()%32767)/32767;
// ویا
double x = (double)(rand()%RAND_MAX)/RAND_MAX;

maktoom
چهارشنبه 28 دی 1390, 10:50 صبح
این روشی که شما گفتید بازهم همون تولید اعداد تصادفی با تابع خود زبان برنامه نویسیه که منجر به تولید اعدادی بین 0 تا 9 هست که با تقسیم به ده و برداشتن باقیمانده تولید عدد تصادفی شده.
اما من دیروز با استاد درس ریزپردازنده ها صحبت کردم. ایشون هم روش برداشتن رقم یکان از مقدار فعلی ثبات pc رو بهتر دونستن. اینطوری واقعا یه عدد رندوم داریم بین 0 تا 9 که با فرمول ریاضی میشه کف و سقف بهش داد.
اما... من بازهم با این فرمول مشکل دارم.
مشکل من اینه که با این فرمول داره یه جور maping میشه. یعنی خیلی از اعداد از دست میرن.
یعنی عدد بر فرض 2 ای که در تابع رندوم ما تولید شده تصویر میشه روی بازه بزرگی از اعداد بین اون سقف و کفی که بهش می دیم. اینجوری شانس انتخاب برای یکسری از اعداد صفره.
میشه در این مورد قدری بهتر کار کرد. بنحوی که واقعا اعداد رندوم تولید بشه و شانس اعداد برای انتخاب شدن مساوی باشه.
بنظر باید دنبال راهی بود که یک بازه کامل از اعداد رو به ما بده و از داخل اون بنحوی عددی رو بیرون بکشه.

shahmohammadi
چهارشنبه 28 دی 1390, 11:07 صبح
این روش های مستقلی که من گفتم برای کار های علمی و آماری مناسب نیستند، فقط در مواردی مثل ساختن یه بازی کوچک با اسمبلی مفید هست.
مثلا فرض کنید شما می خواهید به اعضای یک آرایه 200 تایی اعداد تصادفی بدید، اگه از تابعی که با اعمال تغییرات بر روی زمان سیستم این کار رو انجام می ده این کارو بکنید چون دستور انتصاب برای همه اعضا در کمتر از یک ثانیه انجام می شه و زمان سیستم در همشون برابره پس تمام اعضا یک عدد رو می گیرند، و مشاهده می شه که تابع خود سی بهتر از این روش هاست.

maktoom
پنج شنبه 29 دی 1390, 00:58 صبح
ضعف روشی که در اولین پست برای داشتن اعداد تصادفی با دادن سقف و کف به تعداد دلخواه زمانی روشن میشه که این درخواست از ورودی صادر بشه:
یک میلیون عدد در بازه 200 تا 400
اما شاید جوابش این بشه:
درسته که در یکبار تولید عدد رندوم به تعداد بالا در یک بازه دلخواه بخاطر تصویر شدن اعداد 0 تا 9 روی مقادیری خاص، امکان انتخاب برخی از اعداد در این دور، نزدیک به صفر خواهد بود
اما در دور بعد این امکان نزدیک به صفر روی تعداد دیگری از اعداد خواهد بود.
چون SEED هربار از سیستم بصورت متفاوت و شاید بتوان گفت رندوم تولید میشود.(بخاطر گرفتن از ساعت سیستم)
پس در یک دور درست است. اعداد رندوم آنطور که باید نیستند. اما در توالی ای از اجرای برنامه اعداد رندوم بدرستی مفهوم رندوم را خواهند داشت.

بازم کسی پیشنهادی یا نکته ای داره؟

baran1370
سه شنبه 12 آبان 1394, 20:32 عصر
سلام وقت بخیر
چگونه میتوانم داده باینری(صفر و یک) به صورت رندم تولید کنم؟با چه شبیه سازی بهتر است؟
ممنون

rahnema1
سه شنبه 12 آبان 1394, 21:52 عصر
سلام وقت بخیر
چگونه میتوانم داده باینری(صفر و یک) به صورت رندم تولید کنم؟با چه شبیه سازی بهتر است؟
ممنون

سلام
ببینید شما اگه اعداد صحیح تولید کنید همین اعداد یک نمایش باینری دارند
یعنی تولید عدد رندوم صحیح در واقع تولید داده رندوم باینری هست

Ananas
جمعه 22 آبان 1394, 01:00 صبح
سلام.
این 0 تا 9 رو از کجا آوردید؟! اشتباهه!
تابع rand یک عدد در بازه ی 0 تا RAND_MAX برمیگردونه. مقدارش هم اینطور تعریف شده:
/* Maximum value returned by "rand" function
*/
#define RAND_MAX 0x7FFFU

در فایل stdlib.h
و تابع std::_lrand هم در بازه ی 0 تا LRAND_MAX.

/* Maximum value returned by "_lrand" function (also used by random() macro)
*/
#define LRAND_MAX 0x7FFFFFFFU

Ananas
جمعه 22 آبان 1394, 01:12 صبح
برای ایجاد عدد در بازه ی خاص میتونیم ایننطور عمل کنیم:

float RandByRang(const float min_val, const float max_val)
{
float x_0to1 = (float)std::_lrand() / (float)LRAND_MAX;
return (max_val - min_val) * x_0to1 + min_val;
};