package p09_funkcje;

import java.math.BigInteger;
import java.util.Scanner;
import java.util.stream.LongStream;

public class Silnia {
	
	// silnia to jest iloczyn kolejnych liczb naturalnych od 1 do n włącznie
	// np. 5! = silnia(5) = 1*2*3*4*5 = 120
	// silnia(0) = 1, silnia(1) = 1...
	static int silnia(int n) {
		int iloczyn = 1;
		for(int i = 1; i <= n; i++) {
			iloczyn = iloczyn * i;
		}
		return iloczyn;
	}
	
	// wersja dająca wynik typu long - działa do silnia(20)
	static long silniaLong(int n) {
		long iloczyn = 1;
		for(int i = 2; i <= n; i++) {
			iloczyn *= i;
		}
		return iloczyn;
	}
	
	static BigInteger silniaBig(int n) {
		BigInteger iloczyn = BigInteger.ONE;
		for(int i = 1; i <= n; i++) {
			iloczyn = iloczyn.multiply(BigInteger.valueOf(i));
		}
		return iloczyn;
	}
	
	// wersja z rekurencją - czyli funkcja wywołuje samą siebie
	static long silniaRek(int n) {
		if(n <= 1) return 1;
		return n * silniaRek(n-1);
	}
	
	// wersje w stylu "funkcyjnym" wykorzystujące strumienie
	// tworzymy ciąg liczb od 1 do n włącznie i je wszystkie "przez siebie mnożymy"
	static long silniaFun(int n) {
		return LongStream.rangeClosed(1, n).reduce(1, (x,y) -> x*y);
	}
	
	static BigInteger silniaBigFun(int n) {
		return LongStream.rangeClosed(1, n)
				.mapToObj(BigInteger::valueOf)
				.reduce(BigInteger.ONE, BigInteger::multiply);
	}

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		System.out.println("Podawaj liczby, zakończ wpisując -1");
		while(true) {
			System.out.print("liczba: ");
			int n = scanner.nextInt();
			if(n < 0) break;
			System.out.println("wersja int : " + n + "! = " + silnia(n));
			System.out.println("wersja long: " + n + "! = " + silniaLong(n));
			System.out.println("wersja rek : " + n + "! = " + silniaRek(n));
			System.out.println("wersja fun : " + n + "! = " + silniaFun(n));
			System.out.println("wersja big: " + silniaBig(n));
			System.out.println("wersja bigfun: " + silniaBig(n));
			System.out.println();
		}
	}

}
