PDA

View Full Version : سوال: صفر کردن آرایه 381 مگابایتی ؟



Nabege
پنج شنبه 07 شهریور 1392, 09:22 صبح
با سلام دوستان
من یک متغیری به این شکل ساختم و می خواهم تمام آن را برابر صفر کنم راه حل چیست ؟؟؟
__int8 table[61][50][50][50][50]={0};
که طی کارهای زیاد با آن مجبور به صفر کردنش جهت استفاده ی دوباره از آن شدم.
البته من از روش زیر برای صفر کردن استفاده کردم :
for (__int8 a1=0;a1!=61;a1++)
for (__int8 a2=0;a2!=50;a2++)
for (__int8 a3=0;a3!=50;a3++)
for (__int8 a4=0;a4!=50;a4++)
for (__int8 a5=0;a5!=50;a5++)
table[a1][a2][a3][a4][a5]=0;
ولی مشکلی که این روش دارد این است زمان زیادی صرف میکند.
لطفا سریعترین روش را برای صفر کردن این آرایه بگویید.

mehdi.mousavi
پنج شنبه 07 شهریور 1392, 10:43 صبح
سلام.
باید از memset استفاده کنید. برای آشنایی با چگونگی انجام این کار، به این URL (http://stackoverflow.com/questions/2516096/fastest-way-to-zero-out-a-2d-array-in-c) رجوع کنید.

موفق باشید.

Nabege
پنج شنبه 07 شهریور 1392, 11:18 صبح
بابا من از این استفاده کردم هیچ فرقی با روش اول نکرد همون مقدار و بیشتر هم طول کشید! راه بهتری نیست ؟؟؟

mehdi.mousavi
پنج شنبه 07 شهریور 1392, 12:08 عصر
بابا من از این استفاده کردم هیچ فرقی با روش اول نکرد همون مقدار و بیشتر هم طول کشید! راه بهتری نیست ؟؟؟

میشه کدی که نوشته اید رو اینجا قرار بدید تا ببینم چطوری از memset استفاده کرده اید؟

UfnCod3r
پنج شنبه 07 شهریور 1392, 12:50 عصر
برای ارایه های بزرگ بهتره از memset استفاده کنی . کند تر هم نیست خیلی هم سریع تره

memset(table, 0, sizeof(table));

Nabege
سه شنبه 12 شهریور 1392, 07:38 صبح
وقتی به روش شما از memset استفاده کردم یعنی :
memset(table, 0, sizeof(table));
21 ثانیه طول کشید ولی وقتی به این شکل نوشتم :
memset(table, 0, 381250000);
11 ثانیه طول کشید در صورتی که وقتی به روش دستی متغیرهای آرایه رو 0 کردم هم 11 ثانیه طول کشید.
حالا میشه بگید کجاش سریعتره ؟؟ البته اگه راهی واقعا سریعتر دارید هم بگید.

بهروز عباسی
سه شنبه 12 شهریور 1392, 10:26 صبح
وقتی به روش شما از memset استفاده کردم یعنی :
memset(table, 0, sizeof(table));
21 ثانیه طول کشید ولی وقتی به این شکل نوشتم :
memset(table, 0, 381250000);
11 ثانیه طول کشید در صورتی که وقتی به روش دستی متغیرهای آرایه رو 0 کردم هم 11 ثانیه طول کشید.
حالا میشه بگید کجاش سریعتره ؟؟ البته اگه راهی واقعا سریعتر دارید هم بگید.

اگه میشه مشخصات سیستمی که باهاش تست کردی رو بنویس ؛CPU و... . !

UfnCod3r
سه شنبه 12 شهریور 1392, 11:16 صبح
من نمی دونم شما چطور حساب کردی که این ارقام درامد . فکر کنم متغیر هات ا ستاتیک و کلا خود کامپایلر تشخیص داده و موقع ا جرا اونا رو با صفر مقداد داده
شما عادی که کپی می کنی در واقع از MOV استفاده می کنه
memset خودش بهینه شده هست . Data-aligment رو درست می کنه از چیزایی مثل SSE , کش و ... هم استفاده می کنه.
در ضمن با Release تست کن نه دیباگ

omidshaman
سه شنبه 12 شهریور 1392, 11:20 صبح
با چی مگه تایم میگیری؟!!!!!!!!!!
من رو یک ارایه کوچیکتر امتحان کردم با for شد 0.17 با memset شد 0.008 !! یعنی حدودا 20 برابر سریع تر !!(__int8 table[100][50][50];)
بعد یک همچین ارایه ای رو اصلا ویندوز اجازه نمیده رو Stack بگیری !!! باید با new حافظه بگیری !
خیلی عجیبه برنامت کرش نمیکنه!!

mehdi.mousavi
سه شنبه 12 شهریور 1392, 12:59 عصر
بعد یک همچین ارایه ای رو اصلا ویندوز اجازه نمیده رو Stack بگیری !!! باید با new حافظه بگیری !

سلام.
در Visual Studio، می تونید با استفاده از Linker > System > Stack Size مقدار مورد نیاز stack رو تعیین کنید (یا سوئیچ /Stack).
این مقدار بصورت پیش فرض 1MB هستش...

@Nabege: من مثال شما رو دقیقا با memset آزمایش کردم و به اندازه فشردن و رها کردن کلید F10 زمان برد (کسری از ثانیه).
آیا ممکنه کدتون رو بصورت کامل Share کنید تا ببینم به چه دلیل 11 ثانیه زمان میبره؟ (البته اگر از Visual Studio استفاده می کنید،
چون من دسترسی به Compiler دیگه ای ندارم).

موفق باشید.

Nabege
چهارشنبه 13 شهریور 1392, 09:26 صبح
کدم دقیقا همینه :
__int8 table[61][50][50][50][50]={0};
;cout<<"start"<<endl
memset(table, 0, 381250000);
cout<<"finish"<<endl;
system("pause");

که وقتی امتحانش می کنم بعد از این که "start" در میاد 11 ثانیه طول می کشه تا "finish" در بیاد.

darknes666
چهارشنبه 13 شهریور 1392, 15:21 عصر
کدم دقیقا همینه :
__int8 table[61][50][50][50][50]={0};
;cout<<"start"<<endl
memset(table, 0, 381250000);
cout<<"finish"<<endl;
system("pause");

که وقتی امتحانش می کنم بعد از این که "start" در میاد 11 ثانیه طول می کشه تا "finish" در بیاد.

مدل CPUت چیه؟:متفکر:

Nabege
پنج شنبه 14 شهریور 1392, 08:27 صبح
Intel(R) Pentium(R) 4 CPU 2.40GHz

omidshaman
پنج شنبه 14 شهریور 1392, 09:50 صبح
این کدو امتحان کن متوجه تفاوتشون میشی!

#include <iostream>
#include <windows.h>
using namespace std;
double PCFreq = 0.0;
__int64 CounterStart = 0;
void StartCounter()
{
LARGE_INTEGER li;
if(!QueryPerformanceFrequency(&li))
cout << "QueryPerformanceFrequency failed!\n";

PCFreq = double(li.QuadPart)/1000.0;

QueryPerformanceCounter(&li);
CounterStart = li.QuadPart;
}
double GetCounter()
{
LARGE_INTEGER li;
QueryPerformanceCounter(&li);
return double(li.QuadPart-CounterStart)/PCFreq;
}
int main()
{
__int8 table[100][50][50];


StartCounter();
memset(table, 0, sizeof(table));
cout << GetCounter() <<" with memset"<< endl;

StartCounter();
for (__int8 a1=0;a1!=100;a1++)
for (__int8 a2=0;a2!=50;a2++)
for (__int8 a3=0;a3!=50;a3++)
table[a1][a2][a3]=0;
cout <<GetCounter() <<" with for"<<endl;

Sleep(7000);


}

نتیجه :

0.0186605 with memset
0.194069 with for

Nabege
پنج شنبه 14 شهریور 1392, 10:53 صبح
یه نکته خیلی مهم : وقتی که تعداد متغیر های آرایه خیلی زیاد می شن مثلا : table[1000000][50][50]
زمان استفاده از تابع ممست به زمان استفاده از for نزدیک می شه و ممکنه هم بیشتر بشه.
تنها بدی memset همینه ولی نمی دونم علتش چیه ؟؟؟

Nabege
پنج شنبه 14 شهریور 1392, 10:59 صبح
یه نکته ی دیگه تازه بهش متوجه شدم : همین اتفاق هم وقتی می افته که تعداد اندیس های آرایه خیلی کم بشن مثلا : table[10][10]

Nabege
پنج شنبه 14 شهریور 1392, 11:19 صبح
بابا انگار تابع های کار با حافظه کلا بهینه نیستن کد زیر که مربوط به memcpy هست رو امتحان کنید که منظورم رو بفهمید :
#include <iostream>
#include <windows.h>
__int8 table[1100][1100];
__int8 table2[1100][1100]={5,7,3,12,7,9,6,3,0,0,0,0};

using namespace std;
double PCFreq = 0.0;
__int64 CounterStart = 0;
void StartCounter()
{
LARGE_INTEGER li;
if(!QueryPerformanceFrequency(&li))
cout << "QueryPerformanceFrequency failed!\n";

PCFreq = double(li.QuadPart)/1000.0;

QueryPerformanceCounter(&li);
CounterStart = li.QuadPart;
}
double GetCounter()
{
LARGE_INTEGER li;
QueryPerformanceCounter(&li);
return double(li.QuadPart-CounterStart)/PCFreq;
}
int main()
{



StartCounter();
memcpy(table, table2, sizeof(table));
cout << GetCounter() <<" with memcpy"<< endl;

StartCounter();
for (int a2=0;a2!=1100;a2++)
for (int a3=0;a3!=1100;a3++)
table[a2][a3]=table2[a2][a3];
cout <<GetCounter() <<" with for"<<endl;

Sleep(7000);


}

omidshaman
پنج شنبه 14 شهریور 1392, 12:56 عصر
خب اون چیه نوشتی مقدار اولیه اشتباه دادی به table 2!
از کتاب خونه های c بهینه تر نداریم اصلا !
مقدار کم هم دیگه معلومه نتیجه مثل هم میشه این قدر تعداد کمه که به چشم نمیاد .
بعدشم همچین ارایه ای رو روی stack کسی نمیگیره بگرد دنبال الگوریتم بهتر مگه می خوای سریال تو ارایت ذخیره کنی 380 مگابایت !!؟

#include <iostream>
#include <windows.h>
__int8 table[1100][1100];
__int8 table2[1100][1100];

using namespace std;
double PCFreq = 0.0;
__int64 CounterStart = 0;
void StartCounter()
{
LARGE_INTEGER li;
if(!QueryPerformanceFrequency(&li))
cout << "QueryPerformanceFrequency failed!\n";

PCFreq = double(li.QuadPart)/1000.0;

QueryPerformanceCounter(&li);
CounterStart = li.QuadPart;
}
double GetCounter()
{
LARGE_INTEGER li;
QueryPerformanceCounter(&li);
return double(li.QuadPart-CounterStart)/PCFreq;
}
int main()
{
for(int i=0;i<1100;i++)
for(int j=0;j<1100;j++)
table2[i][j]=(i+j)%200;
StartCounter();
memcpy(table, table2, sizeof(table2));
cout << GetCounter() <<" with memcpy"<< endl;

StartCounter();
for (int a2=0;a2!=1100;a2++)
for (int a3=0;a3!=1100;a3++)
table[a2][a3]=table2[a2][a3];
cout <<GetCounter() <<" with for"<<endl;

Sleep(7000);
}

یک نکته هم درباره memset هست :

Use memset() to initialize a block of memory to a specified value. Because this function can use only a type char as the initialization value, it is not useful for working with blocks of data types other than type char, except when you want to initialize to 0. In other words, it wouldn't be efficient to use memset() to initialize an array of type int to the value 99, but you could initialize all array elements to the value 0.
سایت : http://www.java-samples.com/showtutorial.php?tutorialid=591

Nabege
جمعه 15 شهریور 1392, 12:08 عصر
آره یه چیز مثل سریال
بعدشم چطور مقدار اولیه اشتباه دادم کامپایلر هم نه ورنینگ داد نه ارور !؟؟ لطفا توضیح بدین
ولی کلا کسی روش بهتری نداره چون من یه نرم افزاری دارم 500 مگابایت از حافظه رو می گیره بعد با یه کلیل رو [clear] همشو تو یه لحظه پاک می کنه چطور ؟؟؟؟

1485159
جمعه 15 شهریور 1392, 13:11 عصر
ولی کلا کسی روش بهتری نداره چون من یه نرم افزاری دارم 500 مگابایت از حافظه رو می گیره بعد با یه کلیل رو [clear] همشو تو یه لحظه پاک می کنه چطور ؟؟؟؟
من روش دارم براش ولی از اون روش ایرانی هاس دیگه! :بامزه:
کافیه تو تا از این متغیر ها داشته باشی:
v1 صفر باشه و v2 همونی که ازش استفاده میکنی. حالا هر وقت خواستی که v2 رو صفر کنی از v1 استفاده کن و تو یه thread دیگه v2 رو صفرش کن و برعکس. :لبخند:

Nabege
جمعه 15 شهریور 1392, 17:28 عصر
حالا اگه حافظه ی کافی برای ساختن دو تا از اینا نداشته باشم چییییی ؟؟؟

1485159
جمعه 15 شهریور 1392, 18:53 عصر
اون قسمتی از برنامه که قراره بعد از صفر کردن متغیر ازش استفاده کنه کد خودته؟ یعنی خودت نوشتی؟ کدش رو داری؟
اگه آره:
خب وقتی که استفاده میکنی صفرش کن. یعنی لازم نیست که اول صفرش کنی و بعد استفاده کنی. مثلا وقتی میخوای از یکی از عناصر آرایه استفادی کنی صفرش کن و بعد هر کاری میخوای روش انجام بده.

fjm11100
جمعه 15 شهریور 1392, 23:54 عصر
از پوینتر استفاده کردی؟ با یک تکه کد اسمبلی؟

Nabege
شنبه 16 شهریور 1392, 12:04 عصر
خب وقتی که استفاده میکنی صفرش کن. یعنی لازم نیست که اول صفرش کنی و بعد استفاده کنی. مثلا وقتی میخوای از یکی از عناصر آرایه استفادی کنی صفرش کن و بعد هر کاری میخوای روش انجام بده.
من هم به این فکر افتادم ولی برنامم اونجوریاهم نیست که می گید باید حتما قبل از هر کاری صفرش کنم .


از پوینتر استفاده کردی؟ با یک تکه کد اسمبلی؟
از پوینتر استفاده نمی کنم . ولی میشه یه مثال از تکه کد اسمبلی برای این کار بگید.

fjm11100
شنبه 16 شهریور 1392, 16:12 عصر
تا جایی که میدونم یک آرایه چند بعدی توی حافظه خونه های پشت هم را اشغال میکنه. حالا اگر آدرس آرایه ات را توسط پوینترش به یک حلقه اسمبلی با تعداد شمارش x*y*z که x،y و z ابعاد آرایه است بدی و با mov مقدار صفر را در هر خانه حافظه بزاری فکر کنم بسرعت بالاتری برسی چون دیگه برای هر حلقه تودرتو یک شرط جدا وجود نداره و کلا یک حلقه داری با یک شرط، ضمن اینکه مستقیما داری با آدرس کار می کنی و مسلما کار با آدرس سریعتره

_macro_
شنبه 23 شهریور 1392, 22:14 عصر
تا جایی که میدونم یک آرایه چند بعدی توی حافظه خونه های پشت هم را اشغال میکنه. حالا اگر آدرس آرایه ات را توسط پوینترش به یک حلقه اسمبلی با تعداد شمارش x*y*z که x،y و z ابعاد آرایه است بدی و با mov مقدار صفر را در هر خانه حافظه بزاری فکر کنم بسرعت بالاتری برسی چون دیگه برای هر حلقه تودرتو یک شرط جدا وجود نداره و کلا یک حلقه داری با یک شرط، ضمن اینکه مستقیما داری با آدرس کار می کنی و مسلما کار با آدرس سریعتره
البته در تاييد گفته هاي شما اگه از xor استفاده بشه فكر كنم بهتر بشه... چون چند جا ديدم از xor استفاده ميشه.

fjm11100
یک شنبه 24 شهریور 1392, 10:15 صبح
البته در تاييد گفته هاي شما اگه از xor استفاده بشه فكر كنم بهتر بشه... چون چند جا ديدم از xor استفاده ميشه.
تست نکردم. آره میشه با خودش xor کرد