JavaRush /Java блогы /Random-KK /Java бағдарламалаудағы факториалды

Java бағдарламалаудағы факториалды

Топта жарияланған
Бүгін біз факториалдар туралы айтатын боламыз. Бұл бағдарламашы білуі керек және сонымен бірге онымен жұмыс істей алатын ең негізгі функциялардың бірі. Ендеше, бастайық. n факториалы - 1-ден n-ге дейінгі барлық натурал сандардың көбейтіндісінің (көбейтіндісінің) мәні, ол 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-да қандай болатынын қарастырайық және факториалды есептеудің бірнеше жолын түсінейік.

Кәдімгі шешім

public static int getFactorial(int f) {
  int result = 1;
  for (int i = 1; i <= f; i++) {
     result = result * i;
  }
  return result;
}
Ештеңе күрделі емес: біз алынған санды циклдің өлшемі ретінде пайдаланамыз, онда біз f-ға жеткенше барлық алдыңғы сандарға көбейтеміз. Және негізінен:

System.out.println(getFactorial(6) - getFactorial(4));
Біз тексеріп, қажетті нәтиже аламыз: 696.

Рекурсивті шешім

Рекурсия әдісті өзіне шақыру арқылы логиканы жасайды. Бұл әдіс рекурсивті деп аталады. Әдетте ол екі бөліктен тұрады:
  1. әдістің шығу шарты, оған жеткенде әдіс өзін шақыруды тоқтатып, мәндерді жоғары жіберуді бастау керек. Әйтпесе, біз әдісті өзіне шақыру арқылы шексіз циклды аламыз және нәтижесінде StackOverflowError .

  2. белгілі бір жағдайда қажет кейбір өңдеу (логика) + өзін шақыру, бірақ басқа кіріс мәні бар.

Бүгінгі рекурсияға арналған тамаша мысал факториалды табу болып табылады:
public static int getFactorial(int f) {
  if (f <= 1) {
     return 1;
  }
  else {
     return f * getFactorial(f - 1);
  }
}
1-ге жеткенде рекурсиядан шығу шартын қоямыз. Егер аргумент 1 болмаса, онда ағымдағы мәнді осы әдіске келесі шақырудың нәтижесіне көбейтеміз (мұнда ағымдағы мәнді -1 жібереміз).

Stream көмегімен шешім

Ағынның функционалдығын білмейтіндер немесе жадын жаңартқысы келетіндер үшін мұны оқу пайдалы болады .
public static int getFactorial(int f) {
  if (f <= 1) {
     return 1;
  }
  else {
     return IntStream.rangeClosed(2, f).reduce((x, y) -> x * y).getAsInt();
  }
}
Мұнда біз int мәндерінен ағынмен жұмыс істеу кезінде қосымша мүмкіндіктерді қамтамасыз ететін арнайы IntStream класын қолданамыз. Мұндай ағынды жасау үшін біз оның 2-ден f қоса алғанда 1 қадамымен мәндерді жасайтын rangeClosed статикалық әдісін қолданамыз. Әрі қарай, біз азайту әдісін пайдаланып барлық мәндерді біріктіреміз, атап айтқанда, біз онда қалай болатынын көрсетеміз. біз оларды біріктіргіміз келеді. Соңында, getAsInt терминал әдісін қолданып алынған мәнді аламыз.

BigInteger пайдалану

Java тілінде BigInteger класы сандарды, әсіресе BIG сандарды өңдеу үшін жиі пайдаланылады . Өйткені, егер біз int қолданатын болсақ, онда деректерді жоғалтпай қабылдай алатын максималды факториал 31, ұзақ уақыт үшін - 39. Бірақ 100 факториалы қажет болса ше? Алдыңғы шешімдерді қарастырайық, бірақ BigInteger көмегімен. Java программалаудағы факториалды – 2

Кәдімгі шешім

public static BigInteger getFactorial(int f) {
  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-пен жұмыс істеудің кейбір әдістері қосылған.

Stream көмегімен шешім

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. Ағында қазір бізде mapToObj әдісі бар, оның көмегімен int мәндерін BigInteger түріне түрлендіреміз, оларды кейіннен көбейту арқылы бірге көбейтеміз (жақсы, біз Қосымша қаптамадан нысанды алу үшін get қостық ) . Егер біз осы үш әдістің кез келгенін 100 аргументпен орындасақ, бізде толып кету болмайды және біз аламыз:

93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION