‏نمایش پست‌ها با برچسب شبیه سازی. نمایش همه پست‌ها
‏نمایش پست‌ها با برچسب شبیه سازی. نمایش همه پست‌ها

۱۳۸۹ آذر ۲۸, یکشنبه

نوشتن و خواندن داده ها به صورت باینری در ++C

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


فایل باینری چیست؟
یک فایل باینری، فایلی هست که در آن داده ها به صورت بایت ها ذخیره می شن. بنابراین واحد اولیه داده ها معمولن به صورت پیش فرض به اندازه ی هشت بیت (یک کاراکتر character) هست. در واقع همه ی انواع داده ها در رایانه به صورت دودویی (باینری) هستند. زمانی که ما می خواهیم یک متن ساده را بر روی حافظه ذخیره کنیم، اتفاقی که می افتد این هست که داده ها می بایست ابتدا به متن ساده تبدیل شوند و سپس ذخیره شوند. حال آن که بخشی از این داده ها که تبدی می شوند واقعن لازم نیست اند؛ مثلن یک عدد صحیح (integer) بین دو تا چهار بایت هست که معمولن (بسته به بزرگی عدد) برای ذخیره آن یک بایت (هم اندازه ی یک کاراکتر) کافی هست. به علاوه در حین تبدیل ممکن است دقت را از دست بدهیم؛ مثلن در مورد عددهای اعشاری (double) این اتفاق می افتد چون معمولن تعداد اعشاری که در متن ساده نوشته می شوند کمتر از دقت واقعی متغییر هستند. وحال اگر بخواهیم این متن ساده را زمانی دیگر به عنوان ورودی برنامه استفاده کنیم بخشی از دقت را از دست داده ایم.

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


خواندن و نوشتن به صورت باینری
خواندن و نوشتن در باینری تفاوت هایی با متن های ساده دارد. برای مثال وقتی یک فایل باینری باز می شود، برای خواندن، مکان شروع و طول جمله ای که باید خوانده شود را می بایست خودِ برنامه نویس تعریف کند (در واقع برنامه نویس بایستی بداند که داخل فایل چه داده ای با چه شکل و ترتیبی نوشته شده است. به صورت پیش فرض واحد خوانش و نگارش یک کاراکتر هست). مشکل سازگاری یک فایل باینری از یک ماشین به ماشین دیگر هم ممکن است از همین جا باشد. چنانکه مثلن تعریف ابتدا و انتهای یک فایل ممکن است در دو ماشین متفاوت باشد و در نتیجه مکان نما در جای اشتباهی قرار گرفته باشد و در نتیجه فایل باینری در ماشین جدید قابل خواندن نباشد. در فایل باینری مفهمومی مثل پایان خط (end line) و فاصله (space) وجود ندارد.

نوشتن در فایل باینری هم به همین شکل هست؛ در یک فایل باینری اشاره گر شروع می کند به نوشتن پیوسته داده ها بدون در نظر گرفتن هیچ فاصله ی پیش فرضی. به این ترتیب تصحیح باینری ها هم به سادگی باز کردن و نوشتن در یک متن ساده نیست.

به طور کلی در خواندن و نوشتن در C++ می شود از سه کلاس زیر استفاده کرد:

ifstream (input file stream) تنها برای خواندن از یک فایل     
ofstream (outout file stream)تنها برای نوشتن در یک فایل  
fstream (file stream) برای نوشتن و خواندن (هردو) در یک فایل              

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


برای نوشتن کاراکترها به صورت باینری تنها نام و اندازه ی کاراکتر لازم هست. برای مثال دستور زیر یک کاراکتربا نام Name و اندازه ی ده را به صورت باینری ذخیره می کند:

char Name[10];
ofstream OutFile ("data.bin", ios::out | ios::binary);
OutFile.write (Name, 10);
OutFile.close();

اما اگر داده ها چیزی جز کاراکتر باشند نیاز هست علاوه بر اندازه ی متغیر، اشاره گر را هم به کاراکتر تبدیل کرد مثلن

double Variable;
ofstream OutFile ("data.bin", ios::out | ios::binary);
OutFile.write ((char*)& Variable, sizeof (double));
OutFile.close();


و برای خواندن
double Variable;
ifstream InFile ("data.bin", ios::in | ios::binary);
InFile.read ((char*)&Variable, sizeof (double));
InFile.close();


در شکل و برنامه های بالا به چند چیز دقت کنید:
  1. نوع کلاس برای نوشتن و خواندن متفاوت است.
  2. نام فایل بعد از نام کلاس همان اسمی هست که همه جا در طول برنامه شناخته می شود. اما این نام می تواند متفاوت از نام فایلی باشد که ذخیره می شود.
  3. اولین عبارت در داخل پرانتر نام فایلی هست که داده ها در آن ذخیره خواهند شد یا از آن خوانده خواهند شد.
  4. بعد از اسم فایل مشخصه ورودی-خروجی بودن آمده است. ورودی-خروجی بودن یک فایل بسته به نوع کلاسی هست که استفاده شده. مثلن برای خواندن از ios::in استفاده شده است.
  5. علامت جدا کننده.
  6. نوع فایل (باینری) تعریف شده است.
در مورد نوع فایل و مشخصاتی که فایل می تواند داشته باشد دو جدول در انتهای این متن آمده که می تواند مفید باشد.

برای آزمایش می توانید برنامه ی ساده ای را که نوشته ام دانلود کنید، بخوانید و اجرا کنید. در این برنامه متغییر x در خروجی باینری نوشته می شود و سپس از همان فایل خوانده شده و در متغییر y نوشته می شود. به این ترتیب مقدار نهایی y می بایست برابر با مقدار x باشد. به کلاس هایی که در برنامه به کار رفته اند دقت کنید.

 روی عکس ها کلیک کنید و آنها را در اندازه ی بزرگ ببینید.


پ.ن: اگر سوال یا پیشنهادی در این باره بود خوشجال می شوم بشنوم و اگر توانستم جواب بدهم.

۱۳۸۸ اردیبهشت ۳, پنجشنبه

مورچه ها و جمع آوری غذا

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


«با گذشت زمان استوانه ها در گروه های چندتایی جمع آوری می شوند [...] بنابراین برخلاف آنچه تصور می شود رفتار اعجاب آمیز مورچه ها ممکن است نتیجه ی منطق بسیار ساده ای باشد.»


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

الگوریتمی که نوشته ام به همان سادگی بود که برای ربات ها پیاده شد:

1- نقطه های ساکن (ذرات غذا) در یک صفحه به طور تصادفی پراکنده شده اند.

2- نقطه های متحرک (مورچه ها) در چهارگوشه ی صفحه پراکنده می شوند.

3- مورچه ها به طور تصادفی در صفحه حرکت می کنند

4- اگر یک مورچه به یک ذره ی غذا برخورد کند آن را بر میدارد

5- اگر مورچه ای که به یک ذره ی غذا می رسد ذره ی غذایی به همراه داشته باشد، آن را در کنار ذره ی ساکن می گذارد.


برنامه را در متلب نوشتم و اجرا کردم. در اینجا می توانید فیلم یک شبیه سازی با صدهزار گام زمانی را ببینید. در این شبیه سازی ده مورچه و دویست ذره ی غذا در یک مربع ده در ده شبیه سازی شده اند.


* در هر گام زمانی مورچه ها به مقداری تصادفی و در جهتی تصادفی تغییر جهت می دهند. حداکثر فاصله حرکت آنها قابل تعریف است.