PDA

View Full Version : سوال: سئوال در مورد خروجی صفر در محاسبه فاکتوریل



iman_n21
سه شنبه 05 اسفند 1393, 23:18 عصر
برنامه زیر برای محاسبه فاکتوریل نوشته شده
از جایی به بعد به ازای اعداد ورودی سرریز رخ میده ولی برای ورودی مثل 50 و بالاتر خروجی صفر میشه
بفرمایید که علت چیه ؟
سپاس




int number, i = 1, factorial = 1;
cout<< "Enter a positive integer: ";
cin >> number;

while ( i <= number) {
factorial = factorial * i;
++i;
}

cout<<factorial;

[[[[[[[[[[...]]]]]]]]]]
چهارشنبه 06 اسفند 1393, 08:45 صبح
اگر پردازشگرت 32 بیتی هست، حداکثر به 4294967295 بایت از حافظه می تونی دسترسی داشته باشی. حداکثر عددی که از محاسبه بالا در 32 بیتی به دست میاری 479,001,600 هست:
1 2 6 24 120 720 5,040 40,320 362,880 3,628,800 39,916,800 479,001,600 ؟ (عدد آخر از ضرب عدد قبلی اش در 12 به دست اومده)

عدد بعدی 6,227,020,800 هست که واسه پردازشگرهای 32 بیتی بزرگه. اما در 64 بیتی ها حداکثر تا 18,446,744,073,709,551,615 راه داره. حداکثر عددی که از محاسبه بالا در 64 بیتی به دست میاری 2,432,902,008,176,640,000 هست (این عدد از ضرب عدد قبلی اش در 20 به دست اومده). عدد بعدی 51,090,942,171,709,440,000 هست که خیلی بزرگتره.

البته اینها برای ذخیره اعداد صحیح مثبت در حافظه هست. اگر عدد منفی بخوای، 4294967295 تقسیم بر 2 میشه. 2147483648- (واسه منفی) 2147483647+ (واسه مثبت).


اگر میخوای با اعداد بزرگتر کار کنی، می تونی از کاراکترهای عددی استفاده کنی. سقف تعداد ارقام اعداد به نوع پردازشگر و حجم RAM کامپیوترت بستگی داره. در پردازشگر 32 بیتی حداکثر به 4 گیگابایت از حافظه می تونی دسترسی داشته باشی (اگر سیستم عامل این اجازه رو بده)، و در پردازشگر 64 بیتی حداکثر به 16,777,215 ترابایت! اما سیستم عامل ها محدودیت حافظه گذاشتن; مثلا در Windows 8 Professional با پردزاشگر 64 بیتی حداکثر به 512 گیگابایت از RAM می تونی دسترسی داشته باشی. صفحه وبسایت مایکروسافت (https://msdn.microsoft.com/en-us/library/windows/desktop/aa366778%28v=vs.85%29.aspx) رو ببین تا متوجه بشی. اینها رو میگم چون ممکنه بخوای با اعدادی با میلیون ها ارقام کار کنی.


توابعی بنویس که مثل عملگرهای + - * / % عمل کنن. مثل تابعی به نام add که وظیفه جمع دو رشته از کاراکترهای عددی رو داشته باشه. از add می تونی در تابعی به نام multiply استفاده کنی; به این صورت که برای ضربِ 4 در 3، دو بار تابع add رو صدا بزنی: 4+4 | نتیجه + 4. نتیجه جمع دو کاراکتر عددی رو در آرایه ای دیگر ذخیره کن. تابعی به نام reverse بنویس تا بتونه رشته ای از کاراکترها رو وارونه کنه: 8991 | 1998 چون ممکنه لازمت باشه.

از این روش برای ساخت ماشین حساب های بزرگ هم استفاده میشه. برای مثال وقتی می بینی ماشین حسابی عدد صحیحی 200 میلیون رقمی رو + عدد صحیحی 200 میلیون رقمی می کنه، ارقامی که می بینی، می تونن کاراکترهای عددی باشن. اگر به زبان C بخوایم بگیم، از نوع char نه int. محاسبه اعداد صحیح در این روش چالش برانگیزه، اما محاسبه اعداد اعشاری چالش برانگیزتره.


راجع به 16,777,215 ترابایت:
با توجه به مقدار حجم هر RAM (که شنیدم کمپانی SK Hynix اخیرا از یک 128 گیگابایتی پرده برداری کرده) و با توجه به فاصله هر یک از RAM ها از یکدیگر روی Motherboard (بگذار 1.2 سانتی متر حساب کنیم)،
اگر حجمی برابر با 16,777,215 ترابایت بخوایم، به 134,217,720 تا رَم 128 گیگابایتی احتیاج داریم، که جمع فاصله اونها از یکدیگر روی Motherboard به 1610.612628 کیلومتر ختم میشه!
یعنی به پهن ترین مادربردی که دنیا به خودش دیده احتیاج داریم. مسلما باید تریلیونر باشیم (دلاری). نمی دونم چنین سیستمی به چقدر برق احتیاج داره تا کار کنه. محدودیت هایی وجود داره.

iman_n21
چهارشنبه 06 اسفند 1393, 09:38 صبح
حرفهاتون کاملا درسته و بسیار استفاده کردیم
ولی سئوال اصلی من این بود، چرا صفر ؟!
آیا قرارداد ++C که اینجور مواقع صفر نشون بده ؟!

[[[[[[[[[[...]]]]]]]]]]
چهارشنبه 06 اسفند 1393, 11:56 صبح
حرفهاتون کاملا درسته و بسیار استفاده کردیم
ولی سئوال اصلی من این بود، چرا صفر ؟!
آیا قرارداد ++C که اینجور مواقع صفر نشون بده ؟!

در 32مین و 33مین دور حلقه، مقدار factorial میشه 2147483648-، که این عدد دور بعد ضرب در 34 میشه و عدد 0 به دست میاد! در دورهای بعد، 0 ضرب در 35...50 میشه که جوابشون صفره. اولین صفر در 34مین دور زاده میشه!
اینکه چطور 2147483648- بدست اومد، بهش میگن «رفتار تعریف نشده» یا «رفتار معین نشده». این نتایج تنها بین 2147483647 و 2147483648- به دست میان چون نوع متغیرت int هست.
اگر در الگوریتمت از نوع unsigned int استفاده کنی، عددی غیر منتظره بین 0 و 4294967295 به دست میاد.

اگر 4294967300 رو + 0 کنی، 4 به دست میاد (4294967296 - 4294967300).
اگر 4294967300 رو + 1 کنی، 5 به دست میاد (1 + (4294967296 - 4294967300) ).
اگر 4294967300 رو + 1000 کنی، 1004 به دست میاد. (1000 + (4294967296 - 4294967300) ).
اگر 4294967300 رو + 1000000000 کنی، 1000000004 به دست میاد.
اگر 4294967300 رو + 999999999 کنی، 1000000003 به دست میاد.
اگر 4294967300 رو + 10000000000 کنی، 1410065412 به دست میاد.
اگر 4294967300 رو * 3 کنی، 12 به دست میاد. ( (4294967296 - 4294967300) + (4294967296 - 4294967300) + (4294967296 - 4294967300) )
اگر 4294967300 رو + 4294967300 و + 4294967300 کنی، 12 به دست میاد. (محاسبه بالا)
اگر 4294967300 رو + 4294967300 و + 4294967300 و ضرب در 10 کنی، 120 به دست میاد. (نتیجه محاسبه بالا * 10)
حوصله ندارم بفهمم چرا 9999999999 + 9999999999 + 9999999999 ضرب در 117 میشه 294058889!

میخوام بگم که «منطقی» ولی «بیخودی» جمع و تفریق میشن.

iman_n21
چهارشنبه 06 اسفند 1393, 16:56 عصر
اونچه که به نظر من میرسه اینه که رقمهای با ارزش کمتر همواره صفر خواهد بود و با بزرگتر شدن عدد تعداد صفرها هم بیشتر میشه
از الگوریتم محاسبه فاکتوریل با استفاده از آرایه برای محاسبه اعداد بزرگ استفاده کردم