CodeGym /จาวาบล็อก /สุ่ม /โปรแกรม Java สำหรับแฟคทอเรียล
John Squirrels
ระดับ
San Francisco

โปรแกรม Java สำหรับแฟคทอเรียล

เผยแพร่ในกลุ่ม
วันนี้เราจะพูดถึงแฟกทอเรียลและวิธีทั่วไปในการหาแฟกทอเรียล นี่เป็นหนึ่งในฟังก์ชันพื้นฐานที่สุดที่โปรแกรมเมอร์จำเป็นต้องรู้และสามารถทำงานด้วยได้ มาเริ่มกันเลยดีกว่า แฟกทอเรียลของจำนวน 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
มาดูกันว่าสิ่งนี้จะมีลักษณะอย่างไรเมื่อนำไปใช้ในการเขียนโปรแกรม เราจะสำรวจวิธีการคำนวณแฟกทอเรียลใน Java สองสามวิธี

คำตอบสามัญในโปรแกรมแฟคทอเรียล

นี่คือโปรแกรมแฟคทอเรียลอย่างง่ายโดยใช้ลูป:

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. ไม่ว่าสถานการณ์จะต้องการตรรกะแบบใดบวกกับการโทรแบบเรียกซ้ำ แต่มีค่าอินพุตที่แตกต่างกัน
การค้นหาแฟกทอเรียลใน Java เป็นตัวอย่างที่สมบูรณ์แบบว่าเมื่อใดควรใช้การเรียกซ้ำ:

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)

วิธีแก้ปัญหาด้วยสตรีม

ใครก็ตามที่ไม่คุ้นเคยกับฟังก์ชัน การ สตรีมของ Java หรือใครก็ตามที่ต้องการรีเฟรชหน่วยความจำ จะได้รับประโยชน์จากการอ่านที่นี่

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 ขั้นต่อไป เราใช้วิธีลดเพื่อรวมค่าทั้งหมด โดยเฉพาะอย่างยิ่ง เราแสดงให้เห็นว่าเราต้องการรวมค่าต่างๆ เข้าด้วยกันอย่างไร สุดท้าย เราได้รับค่าผลลัพธ์โดยใช้เมธอดgetAsInt ของ เทอร์มินัล

การใช้ BigInteger

ใน Java คลาส BigIntegerมักจะใช้เพื่อจัดการกับตัวเลข โดยเฉพาะตัวเลขขนาดใหญ่ อันที่จริง ถ้าเราใช้intแฟกทอเรียลสูงสุดที่เราสามารถจัดการได้โดยไม่สูญเสียข้อมูลคือ 31 สำหรับ ประเภทข้อมูล แบบยาวแฟกทอเรียลสูงสุดคือ 39 แต่ถ้าเราต้องการแฟกทอเรียลของ 100 ล่ะ ลองปรับโซลูชันก่อนหน้านี้เป็น BigIntegerโปรแกรม Java สำหรับแฟคทอเรียล - 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 และคูณ ()ใช้เพื่อคูณค่าแฟกทอเรียลก่อนหน้ากับจำนวนปัจจุบัน

วิธีแก้ปัญหาแบบเรียกซ้ำ


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 เพื่อคูณพวกมันด้วยตัวเองโดยใช้เมธอดการคูณ (และ เพิ่ม get()เพื่อรับวัตถุจาก wrapper ทางเลือก ) หากเราเรียกใช้หนึ่งในสามวิธีนี้ด้วยอาร์กิวเมนต์ 100 เราจะหลีกเลี่ยงสแต็กโอเวอร์โฟลว์และได้ผลลัพธ์ที่ถูกต้อง:
9332621544394415268169923885626670049071596826438162146859296389521759999322991560894146397615651828625369792082722375825 1185210916864000000000000000000000000
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION