در این دوره آنلاین آموزش متلب به صورت رایگان با سری آموزشهای نرم افزار متلب در خدمت شما هستیم. در واقع آنچه که شما به طور کاملا عملی برای استفاده در انجام پروژه متلب نیاز دارید در این جلسات ارائه خواهد شد.
در جلسهی گذشته راجع به نحوه نوشتن برنامه با قابلیت استفاده مجدد از آن با استفاده از تابع function صحبت کردیم. در این جلسه میخواهیم قسمت آخر تمرین را هم حل کرده و بخش سوم را به پایان برسانیم.
چگونگی محاسبه فهرست مقسومعلیههای یک عدد در متلب
به سراغ برنامه متلب میرویم. در دو جلسه گذشته راجع به اعداد اول و ساختن function صحبت کردیم. حال فرض کنید که میخواهیم فهرست مقسومعلیههای یک عدد را به دست آوریم. مقسومعلیه یعنی اعدادی که بر یک عدد بخشپذیر هستند. میخواهیم وقتی یک عدد را به برنامه میدهیم، به ما یک فهرستی از مقسومعلیههای آن بدهد. باید چگونه آن را بنویسیم؟
در اینجا نیز از ۲ تا را مانند قبل بررسی میکنیم و باید توجه داشته باشید که خودش (یعنی آن عدد مورد نظر که میخواهیم تعداد مقسومعلیههای آن را به دست آوریم) و عدد ۱ صددرصد مقسوم علیههای آن عدد هستند. یعنی برای مثال عدد ۱۲ بر ۱۲ و ۱ بخشپذیر است یا عدد ۵ بر ۵ و ۱ بخشپذیر است.
پس به این نکته توجه داشته باشید.
در اینجا یک function را تعریف میکنیم.
یک script جدید باز میکنیم و اسم function را divisor list یا Getdivisor قرار میدهیم.
divisor یعنی مقسومعلیه.
در اینجا Getdivisor باز شده است. حال میخواهیم تابع را تعریف کنیم. گفتیم که یک function است و نام آن را DL میگذاریم و اینکه DL = Getdivisor(n)
مشاهده میکنید که تغییر کرده است و به صورت function درآمده است.
DL هم مخفف divisor list است.
گفتیم که DL همیشه ۱ و n را دارد که آن عدد بر این دو عدد بخشپذیر است.
بقیه برنامه مشابه برنامه قبلی است. بعد میگوییم که برای i=2:floor(sqrt(n)) اگر mod(n,i)=0 برقرار بود، DL=[DL i n/i]; را مینویسیم. که در مورد i n/i هم توضیح میدهیم که چرا آن را نوشتیم.
به نظر شما i و n/i را چرا نوشتیم؟ در جلسات گذشته توضیح داده بودیم. ولی برای اینکه در اینجا هم متوجه شوید، باز هم توضیح میدهیم. در مثالهای قبل گفتیم که اعدادی که ۳۰ بر آنها بخشپذیر است، کدام هستند. میگفتیم که باید ۲ تا را محاسبه کنیم. اول میگوییم که بر ۱ بخشپذیر است که همان i ما است. بعد ۲ را داشتیم و بعد ۳ که باز i ما هستند. بر همه اینها بخشپذیر بود. ولی خارج قسمت ۱ چند بود؟ ۳۰
۳۰ تقسیم بر ۱ که همان n/i میشود. خارج قسمت ۳۰ تقسیم بر ۲ هم ۱۵ بود. یعنی ۳۰ تقسیم بر ۲ که همان n/2 است.
بعد ۳۰ تقسیم بر ۳ که همان n/i است. همه اینها n/i هستند. پس اینها به همین دلیل در DL لیست قرار گرفتند. اگر کمی دقت کنید متوجه خواهید شد.
حال برنامه را run میکنیم.
به ما در خط ۲ یک ارور نشان میدهد که ارور صحیحی است.
ولی اصلا نیاز نداریم که آن را run کنیم.
در اینجا فقط آمدیم یک function تعریف کردیم. در command window مینویسیم Getdivisor(30) که جواب زیر را دریافت میکنیم.
مثلا شما میخواهید اینها را به صورت کوچک به بزرگ مرتب کنید. قبلا گفتیم که چگونه این کار را انجام میدادیم و بسیار کار سادهای است.
با یک تابع sort کار انجام میشود که در خط ۸ آن را نوشتیم.
الان اگر تعریف کنید، مشاهده میکنید که به سادگی sort شده است و از ۱ تا بزرگترین عدد نوشته شده است.
حال اگر ۳۶ را وارد کنید، جواب به صورت زیر خواهد بود.
در اینجا یک مشکل وجود دارد. دو تا ۶ پشت سر هم تکرار شدند. چگونه این مشکل را برطرف کنیم؟ دو راه وجود دارد. راه اول این است که اگر i=n/i دیگر آن را اضافه نکنیم. راه بعدی این است که از تابع unique استفاده کنیم. unique خودش sort هم میکند.
در خط ۸ به جای sort کردن باید بنویسید DL = unique(DL)
Unique میگوید که تمام اعضای من باید unique باشد یعنی اینکه منحصربفرد باشد. یعنی دو تا ۶ در کنار هم نداشته باشیم. پس در اینجا اگر عدد ۳۶ را مجدد وارد کنیم، مشاهده میکنید که یک ۶ برای ما نشان داده است و دو تا ۶ نداریم. یعنی المانهای تکراری را حذف کرده است.
اما این کار، کار خوبی در برنامهنویسی ما نیست و باید اصولیتر بنویسیم.
تابع unique هم سرعت برنامه را به دلیل چک کردن پایین میآورد و در اعداد بزرگ هم سرعت را بسیار پایین میآورد و مشکلات دیگری را در پی دارد.
برای اینکه این کار را به صورت اصولی انجام دهید، باید یک flag تعریف کنید.
در اینجا یک function دیگر مینویسیم.
نام function را هم Getdivisor2 قرار میدهیم.
آن را باز میکنیم. یک function DL در آن تعریف میکنیم که نام آن Getdivisor2 است و برای nها تعریف میشود.
ابتدا در نظر میگیریم که همه اینها false هستند یعنی همه صفر هستند. میگوییم که flag = false(1,n)
کار ما این بود که بخشپذیری را بررسی کنیم. ابتدا فرض کردیم که بر هیچ عددی بخشپذیر نیستند. یعنی کلا flag را false در نظر گرفتیم.
میگوییم f([1 n])=true یعنی اینکه مانند قبل که تعریف کردیم، به ۱ و خودش همیشه بخشپذیر است.
مانند قبل مینویسیم برای i=2 : floor(sqrt(n))اگر mod(n,i)==0 داریم flag([i n/i])=true
در مورد [i n/i] هم در ابتدای جلسه توضیح دادیم.
اگر خودتان هم کمی فکر کنید، تمام مفاهیم به خوبی واضح هستند و موضوع خاصی وجود ندارد.
این تابع دوم ما است.
در اینجا یک سری flag یا پرچم داریم که true یا false شدند و کافی است که در اینجا فقط اعضایی را پیدا کنیم که true هستند یعنی بخشپذیر هستند. در اصل برنامه را به گونهای نوشتیم که اعضایی را پیدا کند که بخشپذیر هستند.
دو راه وجود دارد. یکی اینکه بگوییم A = 1:n یعنی همه اعداد ۱ تا n را بررسی میکنیم.
بعد میگوید که لیست مقسوم علیهها برابر A(t) است یعنی اعضایی از A که f برای آنها true است. DL میشود آن اعضایی از A که f برای آنها true است. یعنی دقیقا همان trueهایی که میخواهیم هستند.
یک راه دیگر این است که از تابع find که قبلا معرفی کردیم، استفاده کنیم. یعنی DL = find(flag) یعنی flagها را پیدا کند.
حال در command window مینویسیم Getdivisor2(30)
مشاهده میکنید که به سادگی اعداد را داده است. فقط در خط سوم که f را گذاشتید، باید flag کنید و مشاهده میکنید که مربع کنار تصویر سبز شد.
اکنون مشاهده میکنید که در Getdivisor قبلی رنگ مربع قرمز است.
که به دلیل وجود DL در خط ۵ است.
میگوید این برای اعداد خیلی بزرگ دردسرساز میشود و Getsdivisor2 کدنویسی بسیار بهتری است و سرعت آن هم بسیار بالاتر است و لیست هرچقدر بزرگتر باشد، این برنامه میتواند به راحتی جواب را به دست آورد.
پس توجه کنید که fای که قبلا در خط سوم این برنامه نوشته بودیم اشتباه بود و باید به جای آن flag مینوشتیم.
و اینکه Getdivisor2 الان خیلی از برنامه قبلی بهتر است و شما همیشه باید برنامههایتان را به بهترین نحو بنویسید.
ما آن را به دو صورت نوشتیم که به خوبی این موضوع را متوجه شوید که یک برنامهنویس حرفهای همیشه طوری مینویسد که هیچ مشکلی در هیچ شرایطی به وجود نیاید.
تا فصل بعد شما را به خدای مهربان میسپارم.
ارسال پاسخ