محاسبه فهرست مقسوم‌علیه‌های یک عدد در متلب(جلسه پنجاه)

محاسبه فهرست مقسوم علیه های یک عدد در متلب
محاسبه فهرست مقسوم علیه های یک عدد در متلب

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

در جلسه‌ی گذشته راجع به نحوه نوشتن برنامه با قابلیت استفاده مجدد از آن با استفاده از تابع function صحبت کردیم. در این جلسه می‌خواهیم قسمت آخر تمرین را هم حل کرده و بخش سوم را به پایان برسانیم.

چگونگی محاسبه فهرست مقسوم‌علیه‌های یک عدد در متلب

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

در اینجا نیز از ۲ تا   را مانند قبل بررسی می‌کنیم و باید توجه داشته باشید که خودش (یعنی آن عدد مورد نظر که می‌خواهیم تعداد مقسوم‌علیه‌های آن را به دست آوریم) و عدد ۱ صددرصد مقسوم علیه‌های آن عدد هستند. یعنی برای مثال عدد ۱۲ بر ۱۲ و ۱ بخش‌پذیر است یا عدد ۵ بر ۵ و ۱ بخش‌پذیر است.

پس به این نکته توجه داشته باشید.

در اینجا یک function را تعریف می‌کنیم.

ایجاد کردن SCRIPT جدید
ایجاد کردن SCRIPT جدید
نوشتن نام برای تابع
نوشتن نام برای تابع

یک script جدید باز می‌کنیم و اسم function را divisor list یا Getdivisor قرار می‌دهیم.

نوشتن نام تابع با نام Getdivisor
نوشتن نام تابع با نام Getdivisor
کلیک کردن بر روی Getdivisor
کلیک کردن بر روی Getdivisor

divisor یعنی مقسوم‌علیه.

باز کردن تابع Getdivisor
باز کردن تابع Getdivisor

در اینجا 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) که جواب زیر را دریافت می‌کنیم.

نوشتن Getdivisor(30) و نمایش نتیجه
نوشتن Getdivisor(30) و نمایش نتیجه

مثلا شما می‌خواهید این‌ها را به صورت کوچک به بزرگ مرتب کنید. قبلا گفتیم که چگونه این کار را انجام می‌دادیم و بسیار کار ساده‌ای است.

با یک تابع sort کار انجام می‌شود که در خط ۸ آن را نوشتیم.

نوشتن یک تابع sort
نوشتن یک تابع sort

الان اگر تعریف کنید، مشاهده می‌کنید که به سادگی sort شده است و از ۱ تا بزرگترین عدد نوشته شده است.

نمایش نتایج دستور SORT
نمایش نتایج دستور SORT

حال اگر ۳۶ را وارد کنید، جواب به صورت زیر خواهد بود.

نمایش نتیجه برای  (GETDIVITION(36
نمایش نتیجه برای (GETDIVITION(36

در اینجا یک مشکل وجود دارد. دو تا ۶ پشت سر هم تکرار شدند. چگونه این مشکل را برطرف کنیم؟ دو راه وجود دارد. راه اول این است که اگر i=n/i دیگر آن را اضافه نکنیم. راه بعدی این است که از تابع unique استفاده کنیم. unique خودش sort هم می‌کند.

در خط ۸ به جای sort کردن باید بنویسید DL = unique(DL)

Unique می‌گوید که تمام اعضای من باید unique باشد یعنی اینکه منحصربفرد باشد. یعنی دو تا ۶ در کنار هم نداشته باشیم. پس در اینجا اگر عدد ۳۶ را مجدد وارد کنیم، مشاهده می‌کنید که یک ۶ برای ما نشان داده است و دو تا ۶ نداریم. یعنی المان‌های تکراری را حذف کرده است.

منحصربفرد کردن اعداد با دستور UNIQUE
منحصربفرد کردن اعداد با دستور UNIQUE

اما این کار، کار خوبی در برنامه‌نویسی ما نیست و باید اصولی‌تر بنویسیم.

تابع unique هم سرعت برنامه را به دلیل چک کردن پایین می‌آورد و در اعداد بزرگ هم سرعت را بسیار پایین می‌آورد و مشکلات دیگری را در پی دارد.

برای اینکه این کار را به صورت اصولی انجام دهید،‌ باید یک flag تعریف کنید.

در اینجا یک function دیگر می‌نویسیم.

باز کردن SCRIPT جدید برای نوشتن تابع
باز کردن SCRIPT جدید برای نوشتن تابع
تغییر نام تابع به Getdivisor2
تغییر نام تابع به Getdivisor2

نام 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هایی که می‌خواهیم هستند.

flag هایی که true و false شده اند
flag هایی که true و false شده اند

یک راه دیگر این است که از تابع find که قبلا معرفی کردیم، استفاده کنیم. یعنی DL = find(flag) یعنی flagها را پیدا کند.

پیدا کردن flag ها
پیدا کردن flag ها

حال در command window می‌نویسیم Getdivisor2(30)

تایپ کردن دستورGetdivisor2(30)
تایپ کردن دستورGetdivisor2(30)

مشاهده می‌کنید که به سادگی اعداد را داده است. فقط در خط سوم که f را گذاشتید، باید flag کنید و مشاهده می‌کنید که مربع کنار تصویر سبز شد.

با نوشتن f باید flag شود و مربع سبز شده
با نوشتن f باید flag شود و مربع سبز شده

اکنون مشاهده می‌کنید که در Getdivisor قبلی رنگ مربع قرمز است.

قرمز شدن مربع Getdivisor قبلی
قرمز شدن مربع Getdivisor قبلی

که به دلیل وجود DL در خط ۵ است.

DL دلیل وجود مربع قرمز
DL دلیل وجود مربع قرمز

می‌گوید این برای اعداد خیلی بزرگ دردسرساز می‌شود و Getsdivisor2 کدنویسی بسیار بهتری است و سرعت آن هم بسیار بالاتر است و لیست هرچقدر بزرگتر باشد، این برنامه می‌تواند به راحتی جواب را به دست آورد.

پس توجه کنید که fای که قبلا در خط سوم این برنامه نوشته بودیم اشتباه بود و باید به جای آن flag می‌نوشتیم.

و این‌که Getdivisor2 الان خیلی از برنامه قبلی بهتر است و شما همیشه باید برنامه‌هایتان را به بهترین نحو بنویسید.

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

تا فصل بعد شما را به خدای مهربان می‌سپارم.