View Full Version : سوال: نحوه کامپایل توابع بازگشتی
ravaei
دوشنبه 03 فروردین 1394, 03:54 صبح
درود ...
می خواستم ببینم کامپایلر چطوری خطوط توابع بازگشتی رو کامپایل میکنه برای مثال کد زیر رو در نظر بگیرید :
double fact(int get_num)
{
double temp;
if( get_num == 0 || get_num <0 ) return 0;
else if (get_num == 1) { return 1;}
else temp = get_num * fact(get_num-1);
return temp;
}
در این کد آیا اول جواب فاکتوریل را حساب می کنه بعد میریزه تو temp ؟ یا هرسری حساب میکنه میریزه تو temp بعد دو باره get_num رو فراخونی می کنه؟
یه مساله دیگه چرا تا بینهایت تکرار نمیشه و هی 0 return نمیکنه؟ تازه اگه یک بار هم 0 return بکنه temp برابر 0 میشه ...
اگه بشه یه توضیح بدید ...
از نظر من این کد با در نظر گرفتن get_num = 5 این طوری عمل میکنه ...
5*(4*(3*(2*(1*(0*(0*(0*(0* ... ))))))))
عیدتون هم مبارک
a.abbasi49
دوشنبه 03 فروردین 1394, 14:59 عصر
یه مساله دیگه چرا تا بینهایت تکرار نمیشه و هی 0 return نمیکنه؟
چون شما اعداد کوچکتر یا مساوی 1 رو ، شرط های پایان تابع قرار دادی.
ب ازای 0 یا اعدا کوچکتر از 0 ، مقدار بازگشتی 0 و به ازای عدد 1 ، مقدار بازگشتی 1 است.
chikar
سه شنبه 04 فروردین 1394, 15:14 عصر
ببینید مثلا عدد 3 رو بخواهیم حساب کنیم به این صورت محاسبه می شه
temp = get_num * fact(temp = get_num * fact((get_num == 1) { return 1;})return temp;)return temp;
همونطور که می دونید پرانتز تقدم رو بالا می بره. و return از تابع خارج می کنه، دستورات بالا کامل نیست در اصل باید کل تابع رو درون هر پرانتز نوشت تا بهتر متوجه بشید،زمانی که مقدار آخرین پرانتز یعنی یک محاسبه می شه با return از تابع خارج می شه یک رو بر می گردونه ، دفعه بعد یک در getnum ضرب می شه و با return temp از این تابع درونی هم خارج می شه و مقدار temp جدید در get num قبلی ضرب می شه و همین منوال به عقب برمی گرده تا در آخر مقدار اصلی temp بدست بیاد و با return از کل تابع خارج بشه
نقل قول: یه مساله دیگه چرا تا بینهایت تکرار نمیشه و هی 0 return نمیکنه؟ تازه اگه یک بار هم 0 return بکنه temp برابر 0 میشه ...
ج: زمانی که برابر 1 می شه، دیگه تابع خودش رو فراخوانی نمی کنه، و مقدار یک رو بر می گردونه، مقداری که بر می گرده در getnum قبلی ضرب می شه، جواب دوباره در قبلی ضرب می شه .... در آخر هم مقدار نهایی در temp ریخته می شه و با دستور return از تابع خارج می شه
این رو تست کنید
double fact(int get_num)
{
double temp;
if( get_num == 0 || get_num <0 )
{std::cout << " get_num == 0 \n" ; return 0;}
else if (get_num == 1)
{std::cout << " get_num == 1 \n"; return 1;}
else
{
temp = get_num * fact(get_num-1);
std::cout << " temp is " << temp << "\n";
return temp;}
}
benyaminmazhari
سه شنبه 04 فروردین 1394, 16:54 عصر
این سوال اول یه مشکل محاسباتی داره : آخه 0! برابر 1 است ولی این کد rteturn 0 دارد که اشتباه است.
بعدم توابع بازگشتی دقیقا اینجوری کار میکنن که هر بار با مقدار گفته شده باز خوانی میشه و مقدار دهی میشه مثل :
temp = 5 * fact 4
temp = 5 * 4 * fact 3
temp = 5 * 4 * 3 *fact 2
temp = 5 *4 * 3 * 2 * fact 1
چون گفتی اگه 1 بود return 1 حالا بجای fact 1 مقدار 1 رو قرار میده و حالا temp برابر میشه با :
temp =5 * 4 * 3 * 2 * 1
که مقدارش دقیقا برابر با تعریف ریاضی 5! است.
chikar
سه شنبه 04 فروردین 1394, 17:27 عصر
این سوال اول یه مشکل محاسباتی داره : آخه 0! برابر 1 است ولی این کد rteturn 0 دارد که اشتباه است.
بعدم توابع بازگشتی دقیقا اینجوری کار میکنن که هر بار با مقدار گفته شده باز خوانی میشه و مقدار دهی میشه مثل :
temp = 5 * fact 4
temp = 5 * 4 * fact 3
temp = 5 * 4 * 3 *fact 2
temp = 5 *4 * 3 * 2 * fact 1
چون گفتی اگه 1 بود return 1 حالا بجای fact 1 مقدار 1 رو قرار میده و حالا temp برابر میشه با :
temp =5 * 4 * 3 * 2 * 1
که مقدارش دقیقا برابر با تعریف ریاضی 5! است.
صفر رو برای زمانی گذاشته که اگر کاربر صفر و یا منفی وارد کرد، تابع با دستور return 0 خارج بشه
بله فقط هر بار فاکتوریل حساب می شه در getnum ضرب می شه درون temp قرار می گیره و با return temp از تابع درونی بیرون میاد و مقدار بر میگرده برای ضرب در get num قبلیش!
benyaminmazhari
سه شنبه 04 فروردین 1394, 17:41 عصر
صفر رو برای زمانی گذاشته که اگر کاربر صفر و یا منفی وارد کرد، تابع با دستور return 0 خارج بشه
بله فقط هر بار فاکتوریل حساب می شه در getnum ضرب می شه درون temp قرار می گیره و با return temp از تابع درونی بیرون میاد و مقدار بر میگرده برای ضرب در get num قبلیش!
آخه این تابع برای مقدار 0 ، مقدار 0 رو بر میگردونه که اشتباهه. باید 1 رو برگردونه واسه اعداد منفی می تونی این کار رو بکنی ;)
reza_noei
سه شنبه 04 فروردین 1394, 17:42 عصر
سلام
این تابع یک اشکال داره. فاکتوریل 0 میشه 1
chikar
سه شنبه 04 فروردین 1394, 18:08 عصر
سلام
این تابع یک اشکال داره. فاکتوریل 0 میشه 1
آخه این تابع برای مقدار 0 ، مقدار 0 رو بر میگردونه که اشتباهه. باید 1 رو برگردونه واسه اعداد منفی می تونی این کار رو بکنی ;)
متوجه این مساله نبودم، با یه تغییر کوچیک، درست شد
double fact(int get_num)
{
double temp;
if( get_num <0 ) return 0;
else if (get_num <= 1) { return 1;}
else temp = get_num * fact(get_num-1);
return temp;
}
reza_noei
سه شنبه 04 فروردین 1394, 18:57 عصر
متوجه این مساله نبودم، با یه تغییر کوچیک، درست شد
double fact(int get_num)
{
double temp;
if( get_num <0 ) return 0;
else if (get_num <= 1) { return 1;}
else temp = get_num * fact(get_num-1);
return temp;
}
فاکتوریل اعداد منفی تعریف نشدست ولی یکجا دیدم که عدد منفی رو میگیره (-1) رو بتوان n میرسونه بعد در حاصل فاکتوریل عدد
حاصله ضرب میکنه. یعنی -100 میشود (-1) بتوان 100 * فاکتوریل 100
ولی همون تعریف نشده بزارید بهتره چون تابع گاما که برای محاسبه فاکتوریل استفاده میشه برای اعداد صحیح مثبت جواب میده و برای اعداد منفی
تعریف تشده است. با یک مثال ساده هم میشه علت تعریف نشده بودن فاکتوریل اعداد منفی را اثبات کرد همانطور که میدانید فاکتوریل 5 رو می توانیم بنویسیم !6 تقسیم بر 6 پس فاکتوریل -1 رو هم میتونیم بنویسیم !0 تقسیم بر 0 که برابره با 1/0 که تعریف نشدست پس
دیگر اعداد منفی هم براساس این قانون تعریف نشده هستند.
vBulletin® v4.2.5, Copyright ©2000-1404, Jelsoft Enterprises Ltd.