CodeGym /وبلاگ جاوا /Random-FA /برنامه جاوا برای فاکتوریل
John Squirrels
مرحله
San Francisco

برنامه جاوا برای فاکتوریل

در گروه منتشر شد
امروز قصد داریم در مورد فاکتوریل ها و رایج ترین راه های یافتن فاکتوریل صحبت کنیم. این یکی از اساسی ترین عملکردهایی است که یک برنامه نویس باید هم بداند و هم بتواند با آن کار کند. خوب، بیایید شروع کنیم. فاکتوریل عدد n که با n نشان داده می شود، مقدار حاصل ضرب (ضرب) تمام اعداد طبیعی از 1 تا n است. در اینجا به نظر می رسد (بیایید دانش خود را در مورد ریاضی تجدید کنیم):
1 = 1 2! = 1 * 2 = 2 3! = 1 * 2 * 3 = 6 4! = 1 * 2 * 3 * 4 = 24 5! = 1 * 2 * 3 * 4 * 5 = 120
و یک قانون کوچک دیگر برای 0 وجود دارد:
0 = 1
اگر بخواهیم تفاوت 6 را محاسبه کنیم! و 4!:
6!-4! = 1⋅2⋅3⋅4⋅5⋅6 - 1⋅2⋅3⋅4 = 720 - 24 = 696
بیایید ببینیم که وقتی در برنامه نویسی اجرا شود چه شکلی خواهد بود. ما چند راه را برای نحوه انجام محاسبات فاکتوریل در جاوا بررسی خواهیم کرد.

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

در اینجا یک برنامه فاکتوریل ساده با استفاده از حلقه وجود دارد:
class FactorialExample{
 public static void main(String args[]){
  int i,fact=1;
  int number=7;// our number to do the necessary calculations in class Factorial
  for(i=1;i<=number;i++){
      fact=fact*i;
  }
  System.out.println("Factorial of "+number+" is: "+fact);
 }
}
خروجی ما در کنسول این خواهد بود:
فاکتوریل 7 برابر با 5040 است
و یک مثال دیگر برای مرتب کردن مسائل:
public static int getFactorial(int f) {
  int result = 1;
  for (int i = 1; i <= f; i++) {
     result = result * i; // finding factorial of number using loops
  }
  return result;
}
در اینجا هیچ چیز سختی نیست: از عدد پاس شده به عنوان اندازه حلقه خود استفاده می کنیم، که در آن در تمام اعداد قبلی ضرب می کنیم تا به f برسیم. و در اصل:
System.out.println(getFactorial(6) - getFactorial(4));
با تست کد می بینیم که به نتیجه دلخواه می رسیم: 696.

راه حل بازگشتی

بازگشت زمانی اتفاق می افتد که یک متد خودش را فراخوانی کند. به چنین روشی روش بازگشتی می گویند. به عنوان یک قاعده، از دو بخش تشکیل شده است:
  1. یک شرط پایانی - وقتی شرط پایانی برآورده شد، متد باید خود را فراخوانی نکند و شروع به ارسال مقادیر به بالا کند. از این گذشته، اگر شرط پایانی وجود نداشته باشد، یک حلقه بی نهایت خواهیم داشت که متد به طور مکرر خود را فراخوانی می کند تا زمانی که یک StackOverflowError دریافت کنیم .
  2. هر منطقی که موقعیت نیاز دارد به اضافه یک تماس بازگشتی، اما با مقدار ورودی متفاوت.
یافتن فاکتوریل در جاوا مثال کاملی از زمان استفاده از بازگشت است:
public static int getFactorial(int f) { // finding factorial of number using recursive solution
  if (f <= 1) {
     return 1;
  }
  else {
     return f * getFactorial(f - 1);
  }
}
شرط پایان بازگشتی ما زمانی خواهد بود که به 1 برسیم. اگر پارامتر 1 نباشد، مقدار فعلی را در نتیجه فراخوانی بازگشتی بعدی به متد (که مقدار فعلی منهای 1 را به آن منتقل می کنیم) ضرب می کنیم.

راه حل با یک جریان

هرکسی که با عملکرد جریان جاوا آشنا نیست، یا هرکسی که می‌خواهد حافظه خود را تازه کند، از مطالعه اینجا سود می‌برد .
public static int getFactorial(int f) { // finding factorial of number using Stream
  if (f <= 1) {
     return 1;
  }
  else {
     return IntStream.rangeClosed(2, f).reduce((x, y) -> x * y).getAsInt();
  }
}
در اینجا ما از کلاس ویژه IntStream استفاده می کنیم که در هنگام کار با جریانی از مقادیر int به ما قابلیت های اضافی می دهد. برای ایجاد چنین جریانی، از متد static rangeClosed آن استفاده می‌کنیم، که مقادیر 2 تا f را با افزایش 1 تولید می‌کند. سپس از روش کاهش برای ترکیب همه مقادیر استفاده می‌کنیم. به طور خاص، ما به آن نشان می دهیم که چگونه می خواهیم مقادیر را ترکیب کنیم. در نهایت با استفاده از متد terminal getAsInt مقدار حاصل را بدست می آوریم .

با استفاده از BigInteger

در جاوا، کلاس BigInteger اغلب برای مدیریت اعداد، به خصوص اعداد BIG استفاده می شود. در واقع، اگر از int استفاده کنیم ، حداکثر فاکتوریل که می‌توانیم بدون از دست دادن داده‌ها مدیریت کنیم 31 است. برای نوع داده طولانی ، حداکثر فاکتوریل 39 است. اما اگر به فاکتوریل 100 نیاز داشته باشیم، چه؟ بیایید راه حل های قبلی را با BigInteger تطبیق دهیم.برنامه جاوا برای فاکتوریل - 2

راه حل معمولی

public static BigInteger getFactorial(int f) { // finding factorial of number using BigInteger
  BigInteger result = BigInteger.ONE;
  for (int i = 1; i <= f; i++)
     result = result.multiply(BigInteger.valueOf(i));
  return result;
}
الگوریتم اساساً یکسان است، اما در اینجا از قابلیت‌های BigInteger استفاده می‌کنیم: BigInteger.ONE مقدار شروع 1 است و multiply() برای ضرب مقدار فاکتوریل قبلی و عدد فعلی استفاده می‌شود.

راه حل بازگشتی

public static BigInteger getFactorial(int f) {
  if (f <= 1) {
     return BigInteger.valueOf(1);
  }
  else {
     return BigInteger.valueOf(f).multiply(getFactorial(f - 1));
  }
}
منطق کلی راه حل تغییر نمی کند، به جز اینکه روش هایی برای کار با BigInteger اضافه می شود.

راه حل با یک جریان

public static BigInteger getFactorial(int f) {
  if (f < 2) {
     return BigInteger.valueOf(1);
  }
  else {
     return IntStream.rangeClosed(2, f).mapToObj(BigInteger::valueOf).reduce(BigInteger::multiply).get();
  }
}
همه چیز در اصل یکسان است، اما با BigInteger. کلاس Stream متد mapToObj را به ما می‌دهد که از آن برای تبدیل مقادیر int به BigInteger استفاده می‌کنیم تا سپس با استفاده از متد multiply آن‌ها را با خودشان ضرب کنیم (و get() اضافه شد تا یک شی از بسته‌بندی Optional دریافت کنیم. اگر هر یک از این سه روش را با آرگومان 100 اجرا کنیم، از سرریز پشته جلوگیری می کنیم و نتیجه صحیح را می گیریم:
93326215443944152681699238856266700490715968264381621468592963895217599999322991560894146397685929322991560894146397685926 118521091686400000000000000000000000
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION