Apakah ada metode untuk menghitung faktorial di Jawa?


105

Saya belum menemukannya. Apakah saya melewatkan sesuatu? Saya tahu metode faktorial adalah program contoh umum untuk pemula. Tapi bukankah akan berguna untuk memiliki implementasi standar untuk yang ini untuk digunakan kembali? Saya bisa menggunakan metode seperti itu dengan tipe standar (Misalnya int, long ...) dan dengan BigInteger / BigDecimal, juga.

Jawaban:


26

Menurut saya tidak akan berguna memiliki fungsi perpustakaan untuk faktorial. Ada banyak penelitian tentang implementasi faktorial yang efisien. Berikut ini beberapa penerapan.


188
Mengapa tidak berguna memiliki fungsi perpustakaan untuk faktorial?
midnite

17
Tidak banyak orang yang benar-benar membutuhkan faktorial dalam kode sebenarnya. Jika ya, Anda mungkin mengerjakan beberapa matematika atau statistik tingkat lanjut, dalam hal ini kemungkinan besar Anda sudah menggunakan perpustakaan matematika dengan penerapan faktorial khusus.
mikera

3
Fungsi gamma sangat berguna, itulah sebabnya ia disertakan dalam pustaka standar C ++.
Columbo

2
Kedengarannya bagi saya bahwa @KarlthePagan berarti tidak berguna memiliki fungsi perpustakaan standar untuk faktorial - apakah itu benar?
dantiston

jadi mereka akan meminta Anda saat wawancara untuk melihat apakah Anda dapat melakukannya sendiri * kasus saya
moldovean

59

Apache Commons Math memiliki beberapa metode faktorial di kelas MathUtils .


1
Ya. Barang bagus. Ada implementasi faktorial untuk bilangan float dan non-flat (MathUtils.factorial (int) dan MathUtils.factorialDouble (int)) dan juga logaritma natural yang berguna dari n! (MathUtils.factorialLog (int))
Tomasz Błachowicz

3
itu ada di ArithmeticUtils saat ini.
MarianP

6
ArithmeticUtils.factorial tampaknya sudah tidak digunakan lagi sekarang, atm gunakan CombinatoricsUtils.factorial
Victor Häggqvist

Tolong jangan gunakan tautan! Mereka cenderung menghilang (seperti yang SEMUA miliki).
SMBiggs

1
@ScottBiggs Kedua tautan di jawaban berfungsi dengan baik.
Bill the Lizard

40
public class UsefulMethods {
    public static long factorial(int number) {
        long result = 1;

        for (int factor = 2; factor <= number; factor++) {
            result *= factor;
        }

        return result;
    }
}

Versi Angka Besar oleh HoldOffHunger :

public static BigInteger factorial(BigInteger number) {
    BigInteger result = BigInteger.valueOf(1);

    for (long factor = 2; factor <= number.longValue(); factor++) {
        result = result.multiply(BigInteger.valueOf(factor));
    }

    return result;
}

Juga Anda mengasumsikan bahwa Anda menginginkan faktorial dari sebuah bilangan bulat
Andrew

Solusi ini harus menggunakan kelas BigInteger.
Oleg Abrazhaev

2
Versi Angka Besar: faktorial BigInteger publik statis (BigInteger n) {faktorial BigInteger = BigInteger.valueOf (1); untuk (int i = 1; i <= n.intValue (); i ++) {factorial = factorial.multiply (BigInteger.valueOf (i)); } kembali faktorial; }
HoldOffHunger

23

Dalam praktiknya, faktorial telanjang telanjang jarang diperlukan. Paling sering Anda membutuhkan salah satu dari yang berikut:

1) bagi satu faktorial dengan lainnya, atau

2) jawaban floating-point yang diperkirakan.

Dalam kedua kasus tersebut, Anda akan lebih baik dengan solusi kustom sederhana.

Dalam kasus (1), katakan, jika x = 90! / 85 !, maka Anda akan menghitung hasilnya sama seperti x = 86 * 87 * 88 * 89 * 90, tanpa perlu menahan 90! dalam kenangan :)

Dalam kasus (2), google untuk "perkiraan Stirling".


3
Counterexample: Menghitung jumlah permutasi dengan N elemen membutuhkan faktorial telanjang, dan diperlukan jika Anda ingin mengalokasikan struktur untuk menahan permutasi.
Mark Jeronimus

Poin bagus! Pertanyaan pertama saya adalah jika 90! / 85! disederhanakan karena penyebut yang sama dari 5, tetapi sebenarnya, itu adalah penyebut yang sama dari 85 !. 90! / 85! = 90 * 89 * 88 * 87 * 86 * 85! / 85 !. Anda bisa melihatnya lebih jelas dalam kesetaraan itu.
HoldOffHunger


6

Meskipun faktorial merupakan latihan yang bagus untuk programmer pemula, mereka tidak terlalu berguna dalam banyak kasus, dan semua orang tahu bagaimana menulis fungsi faktorial, jadi mereka biasanya tidak ada di perpustakaan rata-rata.


6
Saya setuju dengan Anda, ada fungsi matematika yang lebih penting. Tapi menurut saya cara ini harus standar agar orang bisa menggunakannya kembali. Tidak perlu menerapkannya berkali-kali oleh banyak orang. Untuk tujuan pendidikan mungkin mereka bisa. Tetapi untuk pekerjaan sehari-hari itu sudah usang. Ini pendapat saya. Pokoknya, terima kasih sudah menjawab. Saya akan melakukannya sendiri - lain kali.

Apa keuntungan dari standardisasi yang Anda usulkan? Menambahkan metode ke pustaka standar bukan tanpa biaya. Seperti yang ditunjukkan orang lain, tidak ada satu pun solusi terbaik . Yang mana yang Anda usulkan untuk dikembangkan ke dalam bahasa? Memiliki metode di pustaka standar tidak akan menghemat waktu Anda untuk memahami masalah Anda, dan setelah Anda selesai melakukannya, Anda mungkin juga memilih implementasi yang paling sesuai untuk pekerjaan itu.
Matt G

2
"... dan semua orang tahu cara menulis fungsi faktorial" chaosinmotion.com/blog/?p=622
James P.

4
Tidak setuju. Faktorial diperlukan untuk Kombinatorik , yang dibutuhkan di banyak bidang desain perangkat lunak. Argumen tidak menyertakan faktorial dalam pustaka matematika bawaan adalah argumen yang sama dengan tidak memiliki pustaka matematika bawaan.
LateralFractal

Sungguh logika yang luar biasa. Benar-benar luar biasa. Sayangnya desainer kelas java.lang.Math mengabaikannya ketika mereka memasukkan metode abs () ke lib itu.
Igor Soudakevitch

6

Saya yakin ini akan menjadi cara tercepat, dengan tabel pencarian:

private static final long[] FACTORIAL_TABLE = initFactorialTable();
private static long[] initFactorialTable() {
    final long[] factorialTable = new long[21];
    factorialTable[0] = 1;
    for (int i=1; i<factorialTable.length; i++)
        factorialTable[i] = factorialTable[i-1] * i;
    return factorialTable;
}
/**
 * Actually, even for {@code long}, it works only until 20 inclusively.
 */
public static long factorial(final int n) {
    if ((n < 0) || (n > 20))
        throw new OutOfRangeException("n", 0, 20);
    return FACTORIAL_TABLE[n];
}

Untuk tipe asli long(8 byte), itu hanya dapat menampung hingga20!

20! = 2432902008176640000(10) = 0x 21C3 677C 82B4 0000

Tentunya 21!akan menyebabkan overflow.

Oleh karena itu, untuk tipe native long, hanya jumlah maksimal 20!yang diperbolehkan, bermakna, dan benar.


1
Ide yang cukup bagus. Mengingat, 20 faktorial pertama mungkin cukup, saya akan menambahkan konstanta statis (tidak perlu menghitungnya setiap kali peluncuran aplikasi) ke kelas Matematika dengan data tersebut disediakan. Fakta bahwa tidak banyak orang membutuhkan faktorial dalam kode mereka adalah alasan yang buruk untuk tidak mendukungnya di kelas Matematika.
TG

6

Karena faktorial tumbuh begitu cepat, stack overflow tidak menjadi masalah jika Anda menggunakan rekursi. Padahal, nilainya 20! adalah yang terbesar yang bisa diwakili dalam jangka panjang Jawa. Jadi metode berikut akan menghitung faktorial (n) atau melontarkan IllegalArgumentException jika n terlalu besar.

public long factorial(int n) {
    if (n > 20) throw new IllegalArgumentException(n + " is out of range");
    return (1 > n) ? 1 : n * factorial(n - 1);
}

Cara lain (lebih keren) untuk melakukan hal yang sama adalah dengan menggunakan pustaka aliran Java 8 seperti ini:

public long factorial(int n) {
    if (n > 20) throw new IllegalArgumentException(n + " is out of range");        
    return LongStream.rangeClosed(1, n).reduce(1, (a, b) -> a * b);
}

Baca lebih lanjut tentang Factorial menggunakan aliran Java 8



6

Jawaban singkatnya adalah: gunakan rekursi.

Anda dapat membuat satu metode dan memanggil metode itu langsung di dalam metode yang sama secara rekursif:

public class factorial {

    public static void main(String[] args) {
        System.out.println(calc(10));
    }

    public static long calc(long n) {
        if (n <= 1)
            return 1;
        else
            return n * calc(n - 1);
    }
}

5
fungsi rekursif bagus, tetapi jika seseorang akan mencoba menghitung kelelahan yang sangat besar, mereka akan berakhir dengan StackOverflowException;) + Saya tidak yakin, tetapi saya pikir rekursi lebih lambat daripada metode loop lama yang baik;)
TG

bagaimana Anda bisa tahu itu akan berakhir dengan pengecualian stackoverflow? @TG
gumuruh

2
Itu sederhana. masing-masing secara rekursif menempatkan tempat saat ini di stack sehingga program akan memiliki 'memori' tempat untuk kembali setelah pemanggilan metode selesai. Tumpukan ada batasnya. untuk mencobanya sendiri coba di kode di atas ubah System.out.println(calc(10));untuk System.out.println(calc(Long.MAX_VALUE));Anda harus mendapatkan stactrace cukup lama :)
TG

@TG Agar jelas, saya mencoba metode rekursif saya yang berfungsi BigInteger. Saya mencoba menghitung faktorial dari bilangan 8020yang memberi saya hasil 613578884952214809325384...yang memiliki 27831tempat desimal. Jadi bahkan ketika bekerja dengan angka yang sangat besar tidak Stackoverflowakan dibuang. Tentu saja Anda benar, tetapi saya ragu ada angka sebesar itu dengan penggunaan praktis :-)
Moritz Schmidt

3

Coba ini

public static BigInteger factorial(int value){
    if(value < 0){
        throw new IllegalArgumentException("Value must be positive");
    }

    BigInteger result = BigInteger.ONE;
    for (int i = 2; i <= value; i++) {
        result = result.multiply(BigInteger.valueOf(i));
    }

    return result;
}

3
Saya yakin ada bug di loop-for: seharusnya begitu i <= value. For-loop dapat sedikit dioptimalkan untuk (int i = 2; i <= value; i++).
Chris

2

Saya menemukan trik yang luar biasa untuk menemukan faktorial hanya dalam setengah perkalian sebenarnya.

Harap bersabar karena ini adalah posting yang sedikit panjang.

Untuk Bilangan Genap: Untuk membagi dua perkalian dengan bilangan genap, Anda akan mendapatkan n / 2 faktor. Faktor pertama adalah bilangan yang Anda ambil faktorialnya, kemudian faktor berikutnya adalah bilangan itu ditambah bilangan itu dikurangi dua. Angka berikutnya adalah angka sebelumnya ditambah angka terakhir dikurangi dua. Anda selesai ketika nomor terakhir yang Anda tambahkan adalah dua (yaitu 2) . Itu mungkin tidak masuk akal, jadi izinkan saya memberi Anda contoh.

8! = 8 * (8 + 6 = 14) * (14 + 4 = 18) * (18 + 2 = 20)

8! = 8 * 14 * 18 * 20 which is **40320** 

Perhatikan bahwa saya mulai dengan 8, lalu angka pertama yang saya tambahkan adalah 6, lalu 4, lalu 2, setiap angka ditambah dua kurang dari angka yang ditambahkan sebelumnya. Cara ini sama dengan mengalikan bilangan terkecil dengan bilangan terbesar, hanya dengan perkalian yang lebih sedikit, seperti:

8! = 1 * 2 * 3 * 4 * 5 * 6 * 7 * 
8! = (1 * 8) * (2 * 7) * (3 * 6) * (4 * 5)
8! = 8 * 14 * 18 * 20

Sederhana bukan :)

Sekarang Untuk Angka Ganjil: Jika angkanya ganjil, penjumlahannya sama, seperti Anda kurangi dua setiap kali, tetapi Anda berhenti di tiga. Namun jumlah faktor berubah. Jika Anda membagi angka dengan dua, Anda akan mendapatkan beberapa angka yang diakhiri dengan 0,5. Alasannya adalah jika kita mengalikan kedua ujungnya, kita akan mendapatkan angka tengahnya. Pada dasarnya, ini semua dapat diselesaikan dengan menyelesaikan sejumlah faktor yang sama dengan angka dibagi dua, dibulatkan. Ini mungkin juga tidak masuk akal bagi pikiran tanpa latar belakang matematika, jadi izinkan saya memberikan contoh:

9! = 9 * (9 + 7 = 16) * (16 + 5 = 21) * (21 + 3 = 24) * (roundUp(9/2) = 5)

9! = 9 * 16 * 21 * 24 * 5 = **362880**

Catatan: Jika Anda tidak menyukai metode ini, Anda juga bisa mengambil faktorial dari bilangan genap sebelum ganjil (dalam hal ini delapan) dan mengalikannya dengan bilangan ganjil (yaitu 9! = 8! * 9).

Sekarang mari kita terapkan di Java:

public static int getFactorial(int num)
{
    int factorial=1;
    int diffrennceFromActualNum=0;
    int previousSum=num;

    if(num==0) //Returning  1 as factorial if number is 0 
        return 1;
    if(num%2==0)//  Checking if Number is odd or even
    { 
        while(num-diffrennceFromActualNum>=2)
        {
            if(!isFirst)
            {
                previousSum=previousSum+(num-diffrennceFromActualNum);  
            }
            isFirst=false;
            factorial*=previousSum;
            diffrennceFromActualNum+=2;
        }
    }
    else // In Odd Case (Number * getFactorial(Number-1))
    {
        factorial=num*getFactorial(num-1);
    }
    return factorial;
}

isFirstadalah variabel boolean yang dideklarasikan sebagai statis; ini digunakan untuk kasus pertama di mana kami tidak ingin mengubah jumlah sebelumnya.

Cobalah dengan angka genap dan ganjil.


2

Anda dapat menggunakan rekursi.

public static int factorial(int n){    
      if (n == 0)    
        return 1;    
      else    
        return(n * factorial(n-1));    
     }

dan kemudian setelah Anda membuat metode (fungsi) di atas:

System.out.println(factorial(number of your choice));  
    //direct example
    System.out.println(factorial(3));

1

Satu-satunya penggunaan bisnis untuk faktorial yang dapat saya pikirkan adalah rumus Erlang B dan Erlang C, dan tidak semua orang bekerja di pusat panggilan atau untuk perusahaan telepon. Kegunaan fitur untuk bisnis tampaknya sering kali menentukan apa yang muncul dalam suatu bahasa - lihat semua penanganan data, XML, dan fungsi web dalam bahasa utama.

Sangat mudah untuk menyimpan cuplikan faktorial atau fungsi pustaka untuk sesuatu seperti ini.


1

Metode yang sangat sederhana untuk menghitung faktorial:

private double FACT(double n) {
    double num = n;
    double total = 1;
    if(num != 0 | num != 1){
        total = num;
    }else if(num == 1 | num == 0){
        total = 1;
    }
    double num2;
    while(num > 1){
        num2 = num - 1;
        total = total * num2;
        num = num - 1;
    }
    return total;
}

Saya telah menggunakan double karena mereka dapat menampung jumlah besar, tetapi Anda dapat menggunakan tipe lain seperti int, long, float, dll.

PS Ini mungkin bukan solusi terbaik tetapi saya baru mengenal pengkodean dan butuh waktu lama bagi saya untuk menemukan kode sederhana yang dapat menghitung faktorial jadi saya harus menulis metode sendiri tetapi saya meletakkan ini di sini sehingga membantu orang lain seperti saya .


1

Anda juga dapat menggunakan versi rekursi.

static int myFactorial(int i) {
    if(i == 1)
        return;
    else
        System.out.prinln(i * (myFactorial(--i)));
}

Rekursi biasanya kurang efisien karena harus mendorong dan mengeluarkan rekursi, jadi iterasinya lebih cepat. Di sisi lain, versi rekursif menggunakan lebih sedikit atau tidak ada variabel lokal yang menguntungkan.


1

Faktorial meningkatkan fungsi diskrit. Jadi saya pikir menggunakan BigInteger lebih baik daripada menggunakan int. Saya telah menerapkan kode berikut untuk perhitungan faktorial bilangan bulat non-negatif. Saya telah menggunakan rekursi sebagai pengganti penggunaan loop.

public  BigInteger factorial(BigInteger x){     
    if(x.compareTo(new BigInteger("1"))==0||x.compareTo(new BigInteger("0"))==0)
        return new BigInteger("1");
    else return x.multiply(factorial(x.subtract(new BigInteger("1")))); 
}

Di sini kisaran bilangan bulat besar adalah

-2^Integer.MAX_VALUE (exclusive) to +2^Integer.MAX_VALUE,
where Integer.MAX_VALUE=2^31.

Namun kisaran metode faktorial yang diberikan di atas dapat diperpanjang hingga dua kali dengan menggunakan BigInteger unsigned.


1

Kami memiliki satu baris untuk menghitungnya:

Long factorialNumber = LongStream.rangeClosed(2, N).reduce(1, Math::multiplyExact);

1

Metode yang cukup sederhana

    for ( int i = 1; i < n ; i++ )
    {
            answer = answer * i;
    }

1
    /**
import java liberary class

*/
import java.util.Scanner;

/* class to find factorial of a number
*/

public class factorial
{
public static void main(String[] args)
{

// scanner method for read keayboard values

    Scanner factor= new Scanner(System.in);

    int n;
    double total = 1;
    double sum= 1;

    System.out.println("\nPlease enter an integer: ");
    n = factor.nextInt();

// evaluvate the integer is greater than zero and calculate factorial

if(n==0)

{
    System.out.println(" Factorial of 0 is 1");
}
else if (n>0)
{
    System.out.println("\nThe factorial of " + n + " is " );

    System.out.print(n);

    for(int i=1;i<n;i++)
    {
        do // do while loop for display each integer in the factorial
              {
                System.out.print("*"+(n-i) );
              }

        while ( n == 1);

      total = total * i;

    }

// calculate factorial
sum= total * n;


// display sum of factorial

    System.out.println("\n\nThe "+ n +" Factorial is : "+" "+ sum);
}

// display invalid entry, if enter a value less than zero

else

{
    System.out.println("\nInvalid entry!!");

}System.exit(0);
}
}

0
public static int fact(int i){
    if(i==0)
       return 0;
    if(i>1){
       i = i * fact(--i);
    }

   return i;
}

1
Saya pikir OP menanyakan apakah ada fungsi di API, bukan bagaimana menulisnya. Juga, 0! = 1 - Anda mungkin ingin memperbarui kode Anda untuk memasukkan kasus itu.
SL Barth - Kembalikan Monica

akan selalu menghasilkan 0
Tom Brito

0

Kita perlu menerapkannya secara berulang. Jika kita mengimplementasikan secara rekursif, itu akan menyebabkan StackOverflow jika input menjadi sangat besar (yaitu 2 milyar). Dan kita perlu menggunakan nomor ukuran tak terikat seperti BigInteger untuk menghindari luapan aritmatik saat bilangan faktorial menjadi lebih besar dari jumlah maksimum jenis tertentu (yaitu 2 miliar untuk int). Anda dapat menggunakan int untuk maksimum 14 faktorial dan panjang untuk maksimum 20 faktorial sebelum luapan.

public BigInteger getFactorialIteratively(BigInteger input) {
    if (input.compareTo(BigInteger.ZERO) <= 0) {
        throw new IllegalArgumentException("zero or negatives are not allowed");
    }

    BigInteger result = BigInteger.ONE;
    for (BigInteger i = BigInteger.ONE; i.compareTo(input) <= 0; i = i.add(BigInteger.ONE)) {
        result = result.multiply(i);
    }
    return result;
}

Jika Anda tidak dapat menggunakan BigInteger, tambahkan pemeriksaan kesalahan.

public long getFactorialIteratively(long input) {
    if (input <= 0) {
        throw new IllegalArgumentException("zero or negatives are not allowed");
    } else if (input == 1) {
        return 1;
    }

    long prev = 1;
    long result = 0;
    for (long i = 2; i <= input; i++) {
        result = prev * i;
        if (result / prev != i) { // check if result holds the definition of factorial
            // arithmatic overflow, error out
            throw new RuntimeException("value "+i+" is too big to calculate a factorial, prev:"+prev+", current:"+result);
        }
        prev = result;
    }
    return result;
}

0
public int factorial(int num) {
        if (num == 1) return 1;
        return num * factorial(num - 1);
}

Harus menggunakan long atau BigInteger;)
AxelH

0

while loop (untuk bilangan kecil)

public class factorial {

public static void main(String[] args) {
    int counter=1, sum=1;

    while (counter<=10) {
        sum=sum*counter;
        counter++;
   }

    System.out.println("Factorial of 10 is " +sum);
   }
}

0

Saya mendapat ini dari EDX, gunakan! itu disebut rekursi

   public static int factorial(int n) {
    if (n == 1) {
        return 1;
    } else {
        return n * factorial(n-1);
    }
}

0

dengan rekursi:

public static int factorial(int n)
{
    if(n == 1)
    {
        return 1;
    }               
    return n * factorial(n-1);
}

dengan while loop:

public static int factorial1(int n)
{
    int fact=1;
    while(n>=1)
    {
        fact=fact*n;
        n--;
    }
    return fact;
}

0

MENGGUNAKAN DYNAMIC PROGRAMMING EFISIEN

jika Anda ingin menggunakannya untuk menghitung lagi dan lagi (seperti cache)

Kode Java:

int fact[]=new int[n+1]; //n is the required number you want to find factorial for.
int factorial(int num)
 {
    if(num==0){
     fact[num]=1;
     return fact[num];
       }
     else
       fact[num]=(num)*factorial(num-1);

     return fact[num];
 }

0

menggunakan rekursi adalah metode paling sederhana. Jika kita ingin mencari faktorial dari N, kita harus mempertimbangkan dua kasus dimana N = 1 dan N> 1 karena dalam faktorial kita tetap mengalikan N, N-1, N-2 ,,,,, sampai 1. jika kita pergi ke N = 0 kita akan mendapatkan 0 untuk jawabannya. untuk menghentikan faktorial mencapai nol, metode rekursif berikut digunakan. Di dalam fungsi faktorial, sedangkan N> 1, nilai yang dikembalikan dikalikan dengan inisiasi lain dari fungsi faktorial. ini akan membuat kode secara rekursif memanggil faktorial () sampai mencapai N = 1. untuk kasus N = 1, ia mengembalikan N (= 1) itu sendiri dan semua hasil yang dibangun sebelumnya dari pengembalian yang dikalikan N s dikalikan dengan N = 1. Jadi memberikan hasil faktorial.

static int factorial(int N) {
    if(N > 1) { 
    return n * factorial(N - 1);
    }
    // Base Case N = 1
    else { 
    return N;
    }
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.