package probability;

import java.io.*;
import java.util.*;
import java.math.BigInteger;

/**
*Demonstrates factorial, large numbers, permutations and combinations, probability
* @author BotRejectsInc
*/
public class Main
{

/** Creates a new instance of Main */
public Main()
{
}

public static void main(String[] args)
{
int numberBalls = 20;
int[] myBag = new int[numberBalls];

initialiseBag(myBag);

//How many balls to chose?
System.out.println("I have a bag of 20 balls numbered from 1 to 20");
System.out.println("How many balls do you wish to select from the bag?");
int input = getInput();

//Array to hold selected balls;
int[] ballsSelected = new int[input];

//Select balls
drawFromBag(myBag, ballsSelected);

//Display balls selected
if(input == 1)
{
System.out.println("The following ball has been selected: ");
}
else
{
System.out.println("The following " + input + " balls have been selected: ");
}
displayArray(ballsSelected);

//Calculate factorial
//This is input!
long shriek = factorial(input);
System.out.println(input + "! = " + shriek);

//Calculate number of permutations
//This is 20! / (20 - input)!
long permutations = factorialDivision(20,  20-input);
System.out.println("The number of permutations of " + input + " balls is: 20! / " + (20-input) + "! = " + permutations);

//Calculate number of combinations
//This is 20! / (20-input)!input!
long combinations = factorial(20) / (factorial(20-input) * factorial(input));
System.out.print("The number of combinations of "+ input + " balls is: 20! / " + (20-input) + "!" + input + "! = ");
System.out.print(combinations + "\n\n");

//Calculate probabilities
double probThisOrder = 1.0/permutations;
System.out.println("The probability of drawing these balls from the bag in this order = " + probThisOrder);
double probAnyOrder = 1.0/combinations;
System.out.println("The probability of drawing these balls from the bag in any order = " + probAnyOrder + "\n");

//Calculate a large factorial
BigInteger bigFactorial = bigFactorial(69);
System.out.println("Let's use BigInteger to find a large factorial!");
System.out.println("The largest my pocket calculator will do is 69!");
System.out.println("69! = " + bigFactorial.toString() + "\n");
}

private static void initialiseBag(int bag[])
{
int bagSize = bag.length;

for(int i = 0; i < bagSize; i++)
{
//Number balls from 1 to bagSize
bag[i] = i + 1;
}
}

private static void drawFromBag(int bag[], int selected[])
{
int numberSelected = selected.length;
int nextBall;
int bagSize = bag.length;
Random rnd = new Random(System.currentTimeMillis());

for(int i = 0; i < numberSelected; i++)
{
//Select balls without replacing them in bag
nextBall = rnd.nextInt(bagSize-1);
System.out.println("random = " + nextBall + " ball = " + bag[nextBall]);
while(bag[nextBall] == 0)
{
nextBall = rnd.nextInt(bagSize);
System.out.println("random = " + nextBall + " ball = " + bag[nextBall]);
}
selected[i] = bag[nextBall];
//Set ball in bag to zero to show it has been drawn
bag[nextBall] = 0;
}
}

private static void displayArray(int[] arr)
{
int number = arr.length;
for(int i = 0; i < number; i++)
{
System.out.print(arr[i]);
if(i < (number-1))
{
System.out.print(", ");
}
}
System.out.println("\n");
}

private static int getInput()
{
int numberToSelect;
String number = "0";
Scanner sc = new Scanner(System.in);

do
{
System.out.println("Please enter a number between 1 and 20");
while (!sc.hasNextInt())
{
sc.next();
}
numberToSelect = sc.nextInt();
} while (numberToSelect < 1 || numberToSelect > 20);

sc.close();

return numberToSelect;
}

private static long factorial(int n)
{
//Can calculate any factorial from -20! to +20!
long result = 1;
int m = n;
boolean negative = false;

if(n == 0)
{
return result;
}
if(n < 0)
{
m = Math.abs(n);
negative = true;
}

for(int j = m; j > 0; j--)
{
result = result * j;
//System.out.println(result);
}

if(negative)
{
result = result * -1;
}

return result;
}

private static long factorialDivision(int n, int m)
{
//Divides the factorial of the larger argument
// from the factorial of the smaller argument (a truncated factorial)
long result = 1;
int d = n - m;
int large = n;
int small = m;
boolean negative = false;

if(n == 0)
{
return result;
}
if(d < 0)
{
d = m - n;
large = m;
small = n;
}

for(int j = large; j > small; j--)
{
result = result * j;
//System.out.println(result);
}

return result;
}

private static BigInteger bigFactorial(int n)
{
//Returns the factorial of a number >= 0
BigInteger bigIntOne = new BigInteger("" + n);
BigInteger bigIntResult = new BigInteger("1");

for(int j = n; j > 0; j--)
{
BigInteger bigIntTwo = new BigInteger("" + j);
bigIntResult = bigIntResult.multiply(bigIntTwo);
}

return bigIntResult;
}

}
Factorials, permutations, combinations, probabilities and big integers

This Java code snippet is a play with factorials and big numbers. The largest factorial that can be stored by a 32-bit integer
(int) is 12!, for a long (64-bit) it is 20! before the number overflows its holder and becomes erroneous. If we wish to go any
higher then we can use Java's BigInteger (or we could use double and forget about the decimal places). This program
demonstrates the computation of large factorials using permutations, combinations and probabilities.