PDA

View Full Version : ایجاد اعداد تصادفی به تعداد زیاد



Ms.lemon
سه شنبه 20 تیر 1391, 12:24 عصر
سلام دوستان، من می خوام برای پروژه ام تعداد زیادی (2000 تا یا شاید هم بیشتر) عدد تصادفی بین +1 و 1- ایجاد کنم و کد زیر را برای ایجاد این اعداد نوشتم:

for (int i = 0; i < 2000; ++i)
{
//setup the weights with an initial random value
int sign = 0;
Random rnd = new Random();
if (rnd.Next(0, 2) == 1)
sign = 1;
else sign = -1;
double w = rnd.NextDouble() * sign;
listBox1.Items.Add(w);
}



اما مشکل کار اینجاست، که اعداد تصادفی تکراری و پشت سر هم ایجاد می شوند (وجود اعداد تکراری مشکلی نداره، اما مثلاً در خروجی 100 تا پشت سرهم 0.27 دارم)... چون با الگوریتم های ژنتیک کار می کنم، این اعداد تکراری تنوع جمعیتو کم می کنه و توی همگرایی جواب مشکل ایجاد می کنم. ممنون میشم بهم بگید ایراد کار کجاست؟

mze666
سه شنبه 20 تیر 1391, 15:19 عصر
اگر Random rnd = new Random(); رو بیرون از حلقه بذارید درست میشه.

the king
سه شنبه 20 تیر 1391, 15:34 عصر
Random rnd = new Random();
listBox1.BeginUpdate();
for (int i = 0; i < 2000; ++i)
{
double w = rnd.NextDouble() * 2 - 1;
listBox1.Items.Add(w);
}
listBox1.EndUpdate();

mehdi.mousavi
سه شنبه 20 تیر 1391, 18:34 عصر
Random rnd = new Random();
listBox1.BeginUpdate();
for (int i = 0; i < 2000; ++i)
{
double w = rnd.NextDouble() * 2 - 1;
listBox1.Items.Add(w);
}
listBox1.EndUpdate();


سلام.
اولین مساله ای که در کد فوق توجهم رو جلب کرد، استفاده از BeginUpdate/EndUpdate بود. :) احسنت. این کار باعث میشه تا ListBox تا انتهای کار Refresh نشه و ... اما نکته دومی نیز در این کد وجود داره و اون عدم استفاده از AddRange هستش. من برای اینکه ببینم چقدر Performance اش تغییر میکنه، کد شما رو با کد زیر، برای 500،000 آیتم تست کردم:


List<string> numbers = new List<string>();
for (int i = 0; i < 500000; ++i)
{
double w = rnd.NextDouble() * 2 - 1;
numbers.Add(w.ToString());
}

listBox1.Items.AddRange(numbers.ToArray());



استفاده از AddRange (به شکل فوق) باعث میشه تا تقریبا 4 ثانیه کد فوق سریعتر اجرا بشه... البته به List<string> در کد فوق توجه کنید... اگر List<object> میگرفتم، یا List<double> و ... بدلیل Boxing/Unboxing زیادی که رخ میداد، عمل Performance هر دو الگوریتم یکسان میشد (و دیگه 4 ثانیه سریعتر نبود). بنابراین، لیستی از string ها تعریف کردم تا عمل Boxing/Unboxing به کمترین میزان خودش برسه... بنابراین بعنوان یک قانون کلی، وقتی چندین Item رو میخواهید به ListBox اضافه کنید، حتما از AddRange استفاده کنید.

در نهایت، برای خوانایی کد فوق، میشه اونو بدین شکل بازنویسی کرد (با استفاده از LINQ):

var q = Enumerable.Range(0, 500000).Select(i => (rnd.NextDouble() * 2 - 1).ToString());
listBox1.Items.AddRange(q.ToArray());

که بازهم 4 ثانیه سرعتش بهتر از الگوریتم اول هستش.

موفق باشید.

syntiberium
سه شنبه 20 تیر 1391, 19:44 عصر
موقعی که قرار نیست به اون لیست بعد از اتمام عملیات آیتمی اضافه بشه و تعداد آیتم ها از قبل مشخصه اگر از آرایه بجایه لیست استفاده کنید و بعدا آرایه را AddRange کنید بهتره چون کلا سرعت آرایه از لیست چند برابر بیشتر هست و دلیل اینکه کد سومی 4 ثانیه زود تر از کد دومی انجام می شه احتمالا همینه که اون جا از لیست استفاده نشده .

mehdi.mousavi
چهارشنبه 21 تیر 1391, 11:49 صبح
موقعی که قرار نیست به اون لیست بعد از اتمام عملیات آیتمی اضافه بشه و تعداد آیتم ها از قبل مشخصه اگر از آرایه بجایه لیست استفاده کنید و بعدا آرایه را AddRange کنید بهتره چون کلا سرعت آرایه از لیست چند برابر بیشتر هست و دلیل اینکه کد سومی 4 ثانیه زود تر از کد دومی انجام می شه احتمالا همینه که اون جا از لیست استفاده نشده .

سلام.
به نکته خوبی اشاره کردید، اما با آزمایشی که انجام دادم، متوجه شدم که Allocate کردن String Array بطول 500000، باعث تفاوت چشمگیری در سرعت نشد (فقط در حد چند میلی ثانیه، سریعتر بود). ضمن اینکه لیست Constructor ای داره که Capacity می گیره، بنابراین اونو Set کردم و بارها Performance اش رو اندازه گیری کردم و در بهترین حالت، 10-20 میلی ثانیه استفاده از String Array نسبت به List of String سریعتر بود (در 500،000 آیتم). اما خوب، وقتی چشمم به پیاده سازی LINQ ای که نوشته بودم افتاد، بلافاصله متوجه شدم که می تونم سرعت تولید اعداد تصادفی رو به طرز چشمگیری بالاتر هم ببرم. کافی بود تا AsParallel رو به Enumerable.Range اضافه کنم:

var q = Enumerable.Range(0, 500000).AsParallel().Select(i => (rnd.NextDouble() * 2 - 1).ToString());
listBox1.Items.AddRange(q.ToArray());

بدین ترتیب، 5 ثانیه دیگه (البته روی CPU من که 8 Core داره) به سرعت تولید اون اعداد افزوده شد. بنابراین با یه تغییر ساده، Performance اجرای کد، 9 ثانیه (بازم تکرار می کنم، در 500000 آیتم) بهبود پیدا کرد که عدد چشمگیری هستش.

موفق باشید.

Ms.lemon
چهارشنبه 21 تیر 1391, 23:47 عصر
بابت راهنمایی هاتون متشکرم، اما قرار دادن لیست توی کد فقط برای نمایش مقادیر تصادفی بود، من توی پروژه چندین کلاس دارم، یکی از اونها را به شکل کاملاً ساده شده براتون میذارم، باید توی ، Constructor متغیر m_drotation را مقداردهی اولیه کنم:

class Crotation
{
static public double dPi = 3.14159265358979;
static public double dTwoPi = dPi * 2;
public double m_dRotation;

public Crotation()
{
Random rnd = new Random();
m_dRotation = rnd.NextDouble() * dTwoPi;
}

}



حالا می خوام از این کلاس، 20 تا شی ایجاد کنم، مقدار متغیر m_drotation همگی با هم برابر میشه (مثل سری قبل):

for (int i = 0; i < 2000; ++i)
{
Crotation CR = new Crotation();

listBox1.Items.Add(CR.m_dRotation);
}


متغیر m_drotation را public تعریف کردم، فقط برای اینکه بتونم مقدارش را در لیست باکس ببینم.

the king
پنج شنبه 22 تیر 1391, 00:16 صبح
public class Crotation
{
public double m_dRotation;

private static Random rnd = new Random();

public Crotation()
{
m_dRotation = rnd.NextDouble() * 2 * Math.PI;
}
}