Performance Improvement For Using BigInteger While Calculating Square Root - java

I am trying to calculate the square root of all the integers below 100 with A precision of up to 10000 digits. I already tried it using Newton's method with Big Decimal, where it eats a lot of time.
So now am using Jarvis method for finding the square root using BigInteger.(I think this method involves less number of calculations and gets rid of the maintenance of decimal digits). Even then my code takes a lot of time.The following piece of code depicts the calculations.
public class SquareRootHackerRankJarvis {
static BigInteger limit;
static BigInteger a;
static BigInteger b;
private static BigInteger squareroot(int n, int digits, BigInteger ten,
BigInteger hundred, BigInteger five) {
limit = ten.pow(digits + 1);
a = BigInteger.valueOf(n * 5);
b = BigInteger.valueOf(5);
while (b.compareTo(limit) == -1) {
if (a.compareTo(b) != -1) {
a = a.subtract(b);
b = b.add(ten);
} else {
a = a.multiply(hundred);
b = (b.divide(ten)).multiply(hundred).add(five);
}
}
return b.divide(hundred);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt();
int P = scanner.nextInt();
int sum = 0;
int p = 1;
BigInteger ten = BigInteger.valueOf(10);
BigInteger hundred = BigInteger.valueOf(100);
BigInteger five = BigInteger.valueOf(5);
for (int i = 1; i <= N; i++) {
if (p * p == i) {
p++;
continue;
}
BigInteger x = squareroot(i, P, ten, hundred, five);
char[] digits = x.toString().toCharArray();
for (int j = 0; j <= P - 1; j++) {
sum += Character.getNumericValue(digits[j]);
}
}
System.out.println(sum);
scanner.close();
}}
Can anyone provided or suggestions about the proper usage of BigInteger for optimum performance?
Comments on improvement of the above algorithm are also welcomed.

BigInteger ten = BigInteger.valueOf(10);
BigInteger hundred = BigInteger.valueOf(100);
BigInteger five = BigInteger.valueOf(5);
Should be moved outside of the function squareroot so they are not created and initialized every time function is called. Make sure they are still accessible in this function.
BigInteger num;
BigInteger limit;
BigInteger a;
BigInteger b;
Should be created outside of the function and should be only initialized on every fucntion call.
Also following line
b = (b.divide(ten)).multiply(hundred).add(five);
can be optimized to
b = b.multiply(ten).add(five);

One observation beyond fast computation of numerous digits of roots of non-squares is that there are just 25 non-compound numbers from 2 to 100.
Next, in addition to introducing constants like Maciej suggested, reduce the "introduction of 0 before the trailing 5" to two operations:
static final BigInteger
ten = BigInteger.TEN,
oneHundred = BigInteger.valueOf(100),
five = BigInteger.valueOf( 5),
fourtyFive = BigInteger.valueOf( 45);
/** Computes <code>digits</code> decimal digits of <code>n</code>
* <em>ignoring</em> (decimal) scaling. */
private static BigInteger sqrtDigitsJarvis(int n, int digits) {
BigInteger
limit = ten.pow(digits + 1), // might be an instance data member
a = BigInteger.valueOf(n*5L), // la*100),
b = five; // BigInteger.valueOf(ib*10 - 45);
// flawed for limit < sqrt(5n)
while (b.compareTo(limit) < 0) {
if (0 <= a.compareTo(b)) { // each branch can be parallelised
a = a.subtract(b);
b = b.add(ten);
} else {
a = a.multiply(oneHundred);
b = b.multiply(ten).subtract(fourtyFive);
}
}
return b.divide(oneHundred);
}

Related

Calculate the number of trailing zeroes in a sequence

Consider the sequence where s(0) and s(1) are inputs, and s(n) = s(n-1) * s(n-2) for all n >= 2. I want to find the number of trailing zeros in s(n). We can assume the following:
n, s(0), and s(1) are given as inputs
n <= 40
s(0) <= 20
s(1) <= 20
Below is my code attempt. It is not running when n is greater than 30 (it runs for a very long time). Is there any other way to calculate the number of trailing zeroes?
public class Soroco {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BigInteger n = new BigInteger(br.readLine());
BigInteger s0 = new BigInteger(br.readLine());
BigInteger s1 = new BigInteger(br.readLine());
BigInteger num = s(n, s0, s1);
System.out.println(num);
System.out.println(countTrailingZeroes(num));
}
static BigInteger s(BigInteger n, BigInteger s0, BigInteger s1) {
if (n.equals(new BigInteger("0")))
return s0;
else if (n.equals(new BigInteger("1")))
return s1;
else {
BigInteger n1=n.subtract(new BigInteger("1"));
BigInteger n2=n.subtract(new BigInteger("2"));
BigInteger n3=s(n1, s0, s1).multiply(s(n2, s0, s1));
return n3;
}
}
static int countTrailingZeroes(BigInteger num) {
String str = String.valueOf(num);
int count = 0;
for (int i = 0; i < str.length(); i++)
if (str.charAt(i) == '0')
count++;
return count;
}
}
Instead of performing the entire multiplication, you only need to keep track of the factors of 2 and 5. If a number can be written as N = 2^a * 5^b * (factors other than 2 or 5), then the number of trailing zeros in N is min(a, b). (This is because a trailing zero is just a factor of 10, which requires one 2 and one 5.)
Note that multiplication adds together the exponents of the factors. So, if you can write:
s(n-2) = 2^a * 5^b * (factors other than 2 or 5)
s(n-1) = 2^c * 5^d * (factors other than 2 or 5)
Then we have:
s(n) = s(n-1) * s(n-2)
= 2^(a+c) * 5^(b+d) * (factors other than 2 or 5)
Therefore, we can treat this problem like two Fibonacci sequences. You start with the number of 2s and 5s in s(0) and s(1), and compute the number of 2s and 5s in s(2), s(3), ..., s(n) in the Fibonacci-sequence manner:
#2s in s(n) = (#2s in s(n-1)) + (#2s in s(n-2))
#5s in s(n) = (#5s in s(n-1)) + (#5s in s(n-2))
Finally, the number of trailing zeros is min(#2s in s(n), #5s in s(n)).
The above algorithm (if implemented with a loop, or memoized recursion) is O(n). Your attempt was exponential in n, which is why it takes a long time to run even for n = 30. I don't mean to bash your attempt, but it's good to understand these mistakes -- your code is slow for two main reasons:
First, multiplying very large integers with complete precision (as you're doing with BigInteger) is extremely slow, since the number of digits can double with each multiplication. If you only care about the number of trailing zeros, complete precision isn't necessary.
Second, ignoring the cost of multiplication, your recursive implementation of s is still exponential-time, but it doesn't have to be. Notice that you're computing the same values many times -- s(n-2) is computed separately for both s(n) and s(n-1), but the value of s(n-2) is clearly the same. The trick is to memoize the recursion by remembering previously-computed results, to avoid recomputation. Alternatively, you can compute Fibonacci-like sequences with a loop:
// Computes the n-th Fibonacci number in O(n) time
int[] fib = new int[n + 1];
fib[0] = 0;
fib[1] = 1;
for (int i = 2; i <= n; i++)
fib[i] = fib[i-1] + fib[i-2];
return fib[n];
This is a much simpler approach than memoized recursion, at least for this problem.
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
int s0 = Integer.parseInt(br.readLine());
int s1 = Integer.parseInt(br.readLine());
int num21 = findNumberOf2s(s0);
int num22 = findNumberOf2s(s1);
int num51 = findNumberOf5s(s0);
int num52 = findNumberOf5s(s1);
int arr2[] = new int[n + 1];
arr2[0] = num21;
arr2[1] = num22;
for (int i = 2; i <= n; i++)
arr2[i] = arr2[i - 1] + arr2[i - 2];
int arr5[] = new int[n + 1];
arr5[0] = num51;
arr5[1] = num52;
for (int i = 2; i <= n; i++)
arr5[i] = arr5[i - 1] + arr5[i - 2];
System.out.println(Math.min(arr2[n], arr5[n]));
}
static int findNumberOf2s(int num) {
int num2 = 0;
while (num % 2 == 0) {
num = num / 2;
num2++;
}
return num2;
}
static int findNumberOf5s(int num) {
int num5 = 0;
while (num % 5 == 0) {
num = num / 5;
num5++;
}
return num5;
}

Why is my sequence generating incorrectly?

The goal of the code is to generate a sequence that operates as follows:
The first number is given, 2. To find the next number in the sequence: multiply all numbers in the sequence together than add 1. The smallest prime divisor of that number is the next number in the sequence. The first three number are [2, 3, 7]. So 237 + 1 = 43. The smallest prime factor is 43. So 43 is the next number. However when my code reaches the 5th number in the sequence it generates 139, instead of 13. 237*43 + 1 = 1807. 1807/13 = 139. So 13 should be next.
Problem: When my code reaches the 5th number in the sequence it generates 139
Note: Using BigInteger because reaching the 8th, 9th,... do not work with Int
import java.math.BigInteger;
import java.util.Scanner;
import java.util.ArrayList;
public class LPMSeq {
public static BigInteger spd(BigInteger y) {
ArrayList<BigInteger> primes = new ArrayList<BigInteger>();
int retval = 0;
int Nth_prime = 25200;
BigInteger TWO = new BigInteger("2");
BigInteger bi = new BigInteger("1");
primes.add(TWO);
int i = 1;
//generates N prime numbers using isProbablePrime
while (i < Nth_prime) {
bi = bi.add(TWO);
if (bi.isProbablePrime(80)) {
i++;
primes.add(bi);
}
}
BigInteger zero = new BigInteger("0");
// finds smallest prime divisor
for (int n = 0; n < Nth_prime; n++) {
BigInteger modded = y.mod(primes.get(n));
if (modded.equals(zero)) {
retval = primes.get(n).intValue();
}
}
return BigInteger.valueOf(retval);
}
public static ArrayList<BigInteger> LpmSeq(int k) {
//ArrayList holding the sequence
ArrayList<BigInteger> Seq = new ArrayList<BigInteger>();
BigInteger two = new BigInteger ("2");
//Add two to sequence (first number in sequence)
Seq.add(two);
while (Seq.size() < k) {
BigInteger x = new BigInteger ("1");
for (int i = 0; i < Seq.size(); i++) {
x = x.multiply(Seq.get(i));
}
BigInteger y = x.add(BigInteger.ONE);
BigInteger spd = spd(y);
Seq.add(spd);
}
return Seq;
}
public static void main(String[] args) {
//Create Scanner
Scanner userinput = new Scanner(System.in);
// Variables
int k = 0;
//Prompt user and get input
System.out.println("How many elements would you like in the sequence? (Please enter an integer)");
k = userinput.nextInt();
System.out.println(LpmSeq(k));
}
}
Your loop that finds the smallest prime factor doesn't work if y isn't prime:
// finds smallest prime divisor
for (int n = 0; n < Nth_prime; n++) {
BigInteger modded = y.mod(primes.get(n));
if (modded.equals(zero)) {
retval = primes.get(n).intValue();
}
}
It finds the largest prime factor, because it doesn't stop when it finds the first prime factor. Because the factorization of 1807 is 13 x 139, it skips 13 and returns 139.
Place a break after you assign retval:
for (int n = 0; n < Nth_prime; n++) {
BigInteger modded = y.mod(primes.get(n));
if (modded.equals(zero)) {
retval = primes.get(n).intValue();
break;
}
}
Also, I find it curious that you're checking all primes through the 25,200th (and re-calculating all 25,200 of them each call). You only need to check primes through the square root of y.

Program for seems to freeze up despite functioning on earlier iterations

I am writing a program to calculate Feigenbaum's constant using the Logistics equation by finding superstable values and then using the ratio of these superstable values to calculate the constant.
I use BigDecimals for almost all of my values so that I can maintain the necessary level of precision during the calculation of the constant.
I am adapting my code from the C++ code on pages 30-35 of the following file: http://webcache.googleusercontent.com/search?q=cache:xabTioRiF0IJ:home.simula.no/~logg/pub/reports/chaos_hw1.ps.gz+&cd=21&hl=en&ct=clnk&gl=us
I doubt what the program does even matters to my question. I run the program, and it seems to be working. The output i get for the first 4 superstable values and the first 2 d's is what is expected, but then after displaying these 4 rows, the program seems to just halt. I don't get an exception, but even after waiting for 30 minutes no more calculations are outputted. I can't figure out what exactly is causing it, because the calculation time should be about the same for each row, yet it obviously is not. Here is my output:
Feigenbaum constant calculation (using superstable points):
j a d
-----------------------------------------------------
1 2.0 N/A
2 3.23606797749979 N/A
4 3.4985616993277016 4.708943013540503
8 3.554640862768825 4.680770998010695
And here is my code:
import java.math.*;
// If there is a stable cycle, the iterates of 1/2 converge to the cycle.
// This was proved by Fatou and Julia.
// (What's special about x = 1/2 is that it is the critical point, the point at which the logistic map's derivative is 0.)
// Source: http://classes.yale.edu/fractals/chaos/Cycles/LogisticCycles/CycleGeneology.html
public class Feigenbaum4
{
public static BigDecimal r[] = new BigDecimal[19];
public static int iter = 0;
public static int iter1 = 20; // Iterations for tolerance level 1
public static int iter2 = 10; // Iterations for tolerance level 2
public static BigDecimal tol1 = new BigDecimal("2E-31"); // Tolerance for convergence level 1
public static BigDecimal tol2 = new BigDecimal("2E-27"); // Tolerance for convergence level 2
public static BigDecimal step = new BigDecimal("0.01"); // step when looking for second superstable a
public static BigDecimal x0 = new BigDecimal(".5");
public static BigDecimal aZero = new BigDecimal("2.0");
public static void main(String [] args)
{
System.out.println("Feigenbaum constant calculation (using superstable points):");
System.out.println("j\t\ta\t\t\td");
System.out.println("-----------------------------------------------------");
int n = 20;
if (FindFirstTwo())
{
FindRoots(n);
}
}
public static BigDecimal F(BigDecimal a, BigDecimal x)
{
BigDecimal temp = new BigDecimal("1");
temp = temp.subtract(x);
BigDecimal ans = (a.multiply(x.multiply(temp)));
return ans;
}
public static BigDecimal Dfdx(BigDecimal a, BigDecimal x)
{
BigDecimal ans = (a.subtract(x.multiply(a.multiply(new BigDecimal("2")))));
return ans;
}
public static BigDecimal Dfda(BigDecimal x)
{
BigDecimal temp = new BigDecimal("1");
temp = temp.subtract(x);
BigDecimal ans = (x.multiply(temp));
return ans;
}
public static BigDecimal NewtonStep(BigDecimal a, BigDecimal x, int n)
{
// This function returns the Newton step for finding the root, a,
// of fn(x,a) - x = 0 for a fixed x = X
BigDecimal fval = F(a, x);
BigDecimal dval = Dfda(x);
for (int i = 1; i < n; i++)
{
dval = Dfda(fval).add(Dfdx(a, fval).multiply(dval));
fval = F(a, fval);
}
BigDecimal ans = fval.subtract(x);
ans = ans.divide(dval, MathContext.DECIMAL64);
ans = ans.negate();
return ans;
}
public static BigDecimal Root(BigDecimal a0, int n)
{
// Find the root a of fn(x,a) - x = 0 for fixed x = X
// with Newton’s method. The initial guess is a0.
//
// On return iter is the number of iterations if
// the root was found. If not, iter is -1.
BigDecimal a = a0;
BigDecimal a_old = a0;
BigDecimal ans;
// First iter1 iterations with a stricter criterion,
// tol1 < tol2
for (iter = 0; iter < iter1; iter++)
{
a = a.add(NewtonStep(a, x0, n));
// check for convergence
BigDecimal temp = a.subtract(a_old);
temp = temp.divide(a_old, MathContext.DECIMAL64);
ans = temp.abs();
if (ans.compareTo(tol1) < 0)
{
return a;
}
a_old = a;
}
// If this doesn't work, do another iter2 iterations
// with the larger tolerance tol2
for (; iter < (iter1 + iter2); iter++)
{
a = a.add(NewtonStep(a, x0, n));
// check for convergence
BigDecimal temp = a.subtract(a_old);
temp = temp.divide(a_old, MathContext.DECIMAL64);
ans = temp.abs();
if (ans.compareTo(tol2) < 0)
{
return a;
}
a_old = a;
}
BigDecimal temp2 = a.subtract(a_old);
temp2 = temp2.divide(a_old, MathContext.DECIMAL64);
ans = temp2.abs();
// If not out at this point, iterations did not converge
System.out.println("Error: Iterations did not converge,");
System.out.println("residual = " + ans.toString());
iter = -1;
return a;
}
public static boolean FindFirstTwo()
{
BigDecimal guess = aZero;
BigDecimal r0;
BigDecimal r1;
while (true)
{
r0 = Root(guess, 1);
r1 = Root(guess, 2);
if (iter == -1)
{
System.out.println("Error: Unable to find first two superstable orbits");
return false;
}
BigDecimal temp = r0.add(tol1.multiply(new BigDecimal ("2")));
if (temp.compareTo(r1) < 0)
{
System.out.println("1\t\t" + r0.doubleValue() + "\t\t\tN/A");
System.out.println("2\t" + r1.doubleValue() + "\t\tN/A");
r[0] = r0;
r[1] = r1;
return true;
}
guess = guess.add(step);
}
}
public static void FindRoots(int n)
{
int n1 = 4;
BigDecimal delta = new BigDecimal(4.0);
BigDecimal guess;
for (int i = 2; i < n; i++)
{
// Computation
BigDecimal temp = (r[i-1].subtract(r[i-2])).divide(delta, MathContext.DECIMAL64);
guess = r[i-1].add(temp);
r[i] = Root(guess, n1);
BigDecimal temp2 = r[i-1].subtract(r[i-2]);
BigDecimal temp3 = r[i].subtract(r[i-1]);
delta = temp2.divide(temp3, MathContext.DECIMAL64);
// Output
System.out.println(n1 + "\t" + r[i].doubleValue() + "\t" + delta.doubleValue());
// Step to next superstable orbit
n1 = n1 * 2;
}
}
}
EDIT:
Phil Steitz's Answer essentially solved my problem. I looked at some thread dumps, and after doing a bit of research to try and understand them, and compiling my program with debugging info, I was able to find that the main thread was stalling at the line:
dval = Dfda(fval).add(Dfdx(a, fval).multiply(dval));
as Phil Steit's said, by using
MathContext.DECIMAL128
in not only this line:
dval = Dfda(fval).add(Dfdx(a, fval).multiply(dval));
but also in my multiplication operations in the methods F, Dfda, and Dfdx, I was able to get my code to work properly.
I used DECIMAL128 because the smaller precision made the calculation non-functional, because I compare them to such low numbers for the tolerance check.
I think that what is going on here is that when n is larger than about 10, your NewtonStep method becomes very slow because none of your multiply invocations limit the scale by providing a MathContext. When no MathContext is provided, the result of a multiply gets the sum of the scales of the multiplicands. With the code above, the scales of dval and fval inside the for loop in NewtonStep get very large for large n, resulting in very slow multiplications in this method and the methods that it calls. Try specifying MathContext.DECIMAL64 (or something else) in the multiply activations as you do for the divides.

Finding Number of combinations C(n,r) for large n (Precision of decimal representation)

This is a problem from CodeSprint3
https://cs3.interviewstreet.com/challenges/dashboard/#problem/50877a587c389
Basically the problem is to calculate the number of possible combinations,nCr for given n and r.Also, 1 <= n <= 1000000000 and 0 <= r <= n.
Output all answers modulo 142857.
Since 6C4=6!/4! 2!
=6*5/2!
=6*5/2*1
I thought overflow could be avoided using division at every step.That is
to start with value of n (n is 6 in this case).
Decrement n and multiply it with previous value (so this becomes 6*5)
Perform division with denominator and then decrement it ( 6*5 /2 and denominator 2 becomes 1)
Repeat the steps until n is less than the of maximum of 2 denominators and in same number of iterations the divisor (Minimum of denominators will become 1)
int count(int n,int r)
{int maxDen=r>(n-r)?r:n-r; //larger number in the denominator
int minDen=n-maxDen; //the smaller number in denominator
double num=1;
for(int j=n;j>maxDen;j--)
{num=j*num; //for C(6,4) example num=6*5 and so on
// System.out.println("num "+num +" minDen "+minDen);
num=num/minDen; //divide num 6*5 in this case by 2
minDen--;
}
num=num%142875; //output the result modulo 142875
return (int) num;
}
But perhaps due to loss precision as more divisions are performed,it gives wrong values but then it still gives correct output for some values.As it stands correct for 22 17 but not for 24 17.
(22 17) = 26334 //gives Correct value
(24 17)= 60353 //wrong value correct value is 60390
(25,17)=81450 //wrong value correct value is 81576
(16 15)= 16 //gives correct value
(87 28)= 54384 //wrong value correct value is 141525
I tried to use num as a BigDecimal and as a consequence i had to replace everything with a BigDecimal to perform the operations.The output then was the same for the inputs which gave correct results in above code.But for inputs which gave wrong results,the program throws an exception
Exception in thread "main" **java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.**
at java.math.BigDecimal.divide(Unknown Source)
at Combination.NcRcount2.count(NcRcount2.java:16)
at Combination.NcRcount2.main(NcRcount2.java:37)
Line 16 is num=num.divide(minDen); //in replacement to earlier used num/minDen,both num and minDen are BigDecimal in this case
Even though if the number does not have an exact decimal representation,given the arbitrary precision of BigDecimal the error in results would have been minimized if it didn't threw an exception.
** If the result of division on floats or doubles does not have an exact decimal representation then why isn't an exception thrown?**
I verified the results using BigDecimal with the dynamic programming approach as
C(n,r)=C(n-1,r-1)+C(n-1,r)
This works correctly in all cases as it appears to me but there must be a better way
BigDecimal Comb (int n, int k)
{ if(k>n-k)
k=n-k;
BigDecimal B[][]=new BigDecimal[n+1] [k+1];
for (int i = 0; i <= n; i++)
{ int min;
if(i>=k)
min=k;
else
min=i;
for (int j = 0; j <= min; j++)
{ if (j == 0 || j == i)
B[i][j] =new BigDecimal(1);
else{
if(j>i-j)
B[i][j]=B[i][i-j];
else
B[i][j] = B[i - 1][j - 1].add(B[i - 1] [j]);
}
}
}
BigDecimal div=new BigDecimal(142857);
return B[n][k].remainder(div);
}
Please suggest me a better way to do this without using BigDecimal
public class Solution {
public static void main(String arg[]) {
Scanner s = new Scanner(System.in);
List<BigInteger> ar = new ArrayList<BigInteger>();
int tot = Integer.parseInt(s.nextLine());
BigInteger max = BigInteger.ZERO;
for (int i = 0; i < tot; i++) {
String str[] = s.nextLine().split(" ");
Long n1 = Long.parseLong(str[0]);
Long r1 = Long.parseLong(str[1]);
Long nr1 = n1 - r1;
BigInteger n = BigInteger.valueOf(n1);
BigInteger r = BigInteger.valueOf(r1);
BigInteger nr = BigInteger.valueOf(nr1);
ar.add(n);
ar.add(r);
ar.add(nr);
if (n.compareTo(max)==1) {
max=n;
}
if (r.compareTo(max)==1) {
max=r;
}
if (nr.compareTo(max)==1) {
max=nr;
}
}
HashMap<BigInteger,BigInteger> m=new HashMap<BigInteger,BigInteger>();
m.put(BigInteger.ZERO, BigInteger.ONE);
BigInteger fact=BigInteger.ONE;
for(BigInteger i=BigInteger.ONE;i.compareTo(max.add(BigInteger.ONE))==-1;i=i.add(BigInteger.ONE)){
fact=fact.multiply(i);
if(ar.contains(i)){
m.put(i, fact);
}
}
for(int i=0;i<ar.size();i=i+3){
BigInteger n=m.get(ar.get(i));
BigInteger r=m.get(ar.get(i+1));
BigInteger nr=m.get(ar.get(i+2));
BigInteger rem=r.multiply(nr);
BigInteger act=n.divide(rem);
BigInteger res=act.remainder(BigInteger.valueOf(142857));
System.out.println(res);
}
}
}
I think this code might will help you .
Rather straightforward implementation:
public long combinations(int n, int k) {
BigInteger factorialN = factorial(n);
BigInteger factorialK = factorial(k);
BigInteger factorialNMinusK = factorial(n - k);
return factorialN.divide(factorialK.multiply(factorialNMinusK)).longValue();;
}
private BigInteger factorial(int n) {
BigInteger ret = BigInteger.ONE;
for (int i = 1; i <= n; ++i) ret = ret.multiply(BigInteger.valueOf(i));
return ret;
}
The part of your question about an exception with BigDecimal code isn't clear to me so I won't comment on that.
Regarding a sequence of multiplies and divides to compute nCr, wikipedia shows a formula that's easy to implement. Your first section of code in the question might be equivalent to it, as may be the bit of python code just below. It computes up to 61C30 using 64-bit integer arithmetic; 62C31 requires another bit or two.
def D(n, k):
c, j, k = 1, n, min(k,n-k)
for i in range(1,k+1):
c, j = c*j/i, j-1
return c
The reason that this order of computation works, with all divisions being exact divisions, is that nC(j+1) = nCj * (n-j)/(j+1) as is easily verified from nCj = n!/j!(n-j)! and some algebra. That is, you can compute nCr for large n and r completely in integer arithmetic without needing any decimal places.
Suppose K=142857.
Note that reduction of intermediate terms modulo K will cause problems and may be infeasible. If the numerator is reduced mod K, some divisions won't be exact in ordinary arithmetic. If K were prime, the extended GCD algorithm could be used to find inverses mod K for all numbers. But K=3*9*11*13*37 and inverses mod K will not exist for numbers that are multiples of 3, 11, 13, or 37, as a consequence of Bézout's lemma and some modular algebra.
You should not divide.
Draw Pascal triangle in memory. This will require only additions and will easily allow to apply modular arithmetic.
Also, this will last not longer than with divisions, because you can not avoid of calculating factorials.
package tests.StackOverflow;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class q13241166 {
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String s;
String[] ss;
int[] n;
int[] r;
int T;
/*
System.out.println("Input T:");
s = in.readLine();
T = Integer.parseInt(s);
if( T < 1 || T > 100000) {
throw new IllegalArgumentException();
}
*/
T = 9;
/*
n = new int[T];
r = new int[T];
System.out.println("Input n r pairs:");
for(int i=0; i<T; ++i) {
s = in.readLine();
ss = s.split("\\s+");
n[i] = Integer.parseInt(ss[0]);
if( n[i] < 1 || n[i] > 1000000000) {
throw new IllegalArgumentException();
}
r[i] = Integer.parseInt(ss[1]);
if( r[i] < 0 || r[i] > n[i]) {
throw new IllegalArgumentException();
}
}
*/
n = new int[] {2, 4, 5, 10, 22, 24, 25, 16, 87};
r = new int[] {1, 0, 2, 3, 17, 17, 17, 15, 28};
int modulobase = 142857;
int[] answers_old, answers = null;
System.out.println("Output");
for(int i=0; i<T; ++i) {
for( int nn=0; nn<=n[i]; ++nn) {
answers_old = answers;
answers = new int[nn+1];
for( int rr=0; rr<=nn; ++rr) {
if( rr == 0 || rr == nn ) {
answers[rr] = 1;
}
else {
answers[rr] = answers_old[rr-1] + answers_old[rr];
}
answers[rr] %= modulobase;
}
}
System.out.println(answers[r[i]]);
}
}
}
Output follows:
Output
2
1
10
120
26334
60390
81576
16
141525

Counting trailing zeros of numbers resulted from factorial

I'm trying to count trailing zeros of numbers that are resulted from factorials (meaning that the numbers get quite large). Following code takes a number, compute the factorial of the number, and count the trailing zeros. However, when the number is about as large as 25!, numZeros don't work.
public static void main(String[] args) {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
double fact;
int answer;
try {
int number = Integer.parseInt(br.readLine());
fact = factorial(number);
answer = numZeros(fact);
}
catch (NumberFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static double factorial (int num) {
double total = 1;
for (int i = 1; i <= num; i++) {
total *= i;
}
return total;
}
public static int numZeros (double num) {
int count = 0;
int last = 0;
while (last == 0) {
last = (int) (num % 10);
num = num / 10;
count++;
}
return count-1;
}
I am not worrying about the efficiency of this code, and I know that there are multiple ways to make the efficiency of this code BETTER. What I'm trying to figure out is why the counting trailing zeros of numbers that are greater than 25! is not working.
Any ideas?
Your task is not to compute the factorial but the number of zeroes. A good solution uses the formula from http://en.wikipedia.org/wiki/Trailing_zeros (which you can try to prove)
def zeroes(n):
i = 1
result = 0
while n >= i:
i *= 5
result += n/i # (taking floor, just like Python or Java does)
return result
Hope you can translate this to Java. This simply computes [n / 5] + [n / 25] + [n / 125] + [n / 625] + ... and stops when the divisor gets larger than n.
DON'T use BigIntegers. This is a bozosort. Such solutions require seconds of time for large numbers.
You only really need to know how many 2s and 5s there are in the product. If you're counting trailing zeroes, then you're actually counting "How many times does ten divide this number?". if you represent n! as q*(2^a)*(5^b) where q is not divisible by 2 or 5. Then just taking the minimum of a and b in the second expression will give you how many times 10 divides the number. Actually doing the multiplication is overkill.
Edit: Counting the twos is also overkill, so you only really need the fives.
And for some python, I think this should work:
def countFives(n):
fives = 0
m = 5
while m <= n:
fives = fives + (n/m)
m = m*5
return fives
The double type has limited precision, so if the numbers you are working with get too big the double will be only an approximation. To work around this you can use something like BigInteger to make it work for arbitrarily large integers.
You can use a DecimalFormat to format big numbers. If you format your number this way you get the number in scientific notation then every number will be like 1.4567E7 this will make your work much easier. Because the number after the E - the number of characters behind the . are the number of trailing zeros I think.
I don't know if this is the exact pattern needed. You can see how to form the patterns here
DecimalFormat formater = new DecimalFormat("0.###E0");
My 2 cents: avoid to work with double since they are error-prone. A better datatype in this case is BigInteger, and here there is a small method that will help you:
public class CountTrailingZeroes {
public int countTrailingZeroes(double number) {
return countTrailingZeroes(String.format("%.0f", number));
}
public int countTrailingZeroes(String number) {
int c = 0;
int i = number.length() - 1;
while (number.charAt(i) == '0') {
i--;
c++;
}
return c;
}
#Test
public void $128() {
assertEquals(0, countTrailingZeroes("128"));
}
#Test
public void $120() {
assertEquals(1, countTrailingZeroes("120"));
}
#Test
public void $1200() {
assertEquals(2, countTrailingZeroes("1200"));
}
#Test
public void $12000() {
assertEquals(3, countTrailingZeroes("12000"));
}
#Test
public void $120000() {
assertEquals(4, countTrailingZeroes("120000"));
}
#Test
public void $102350000() {
assertEquals(4, countTrailingZeroes("102350000"));
}
#Test
public void $1023500000() {
assertEquals(5, countTrailingZeroes(1023500000.0));
}
}
This is how I made it, but with bigger > 25 factorial the long capacity is not enough and should be used the class Biginteger, with witch I am not familiar yet:)
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
System.out.print("Please enter a number : ");
long number = in.nextLong();
long numFactorial = 1;
for(long i = 1; i <= number; i++) {
numFactorial *= i;
}
long result = 0;
int divider = 5;
for( divider =5; (numFactorial % divider) == 0; divider*=5) {
result += 1;
}
System.out.println("Factorial of n is: " + numFactorial);
System.out.println("The number contains " + result + " zeroes at its end.");
in.close();
}
}
The best with logarithmic time complexity is the following:
public int trailingZeroes(int n) {
if (n < 0)
return -1;
int count = 0;
for (long i = 5; n / i >= 1; i *= 5) {
count += n / i;
}
return count;
}
shamelessly copied from http://www.programcreek.com/2014/04/leetcode-factorial-trailing-zeroes-java/
I had the same issue to solve in Javascript, and I solved it like:
var number = 1000010000;
var str = (number + '').split(''); //convert to string
var i = str.length - 1; // start from the right side of the array
var count = 0; //var where to leave result
for (;i>0 && str[i] === '0';i--){
count++;
}
console.log(count) // console shows 4
This solution gives you the number of trailing zeros.
var number = 1000010000;
var str = (number + '').split(''); //convert to string
var i = str.length - 1; // start from the right side of the array
var count = 0; //var where to leave result
for (;i>0 && str[i] === '0';i--){
count++;
}
console.log(count)
Java's doubles max out at a bit over 9 * 10 ^ 18 where as 25! is 1.5 * 10 ^ 25. If you want to be able to have factorials that high you might want to use BigInteger (similar to BigDecimal but doesn't do decimals).
I wrote this up real quick, I think it solves your problem accurately. I used the BigInteger class to avoid that cast from double to integer, which could be causing you problems. I tested it on several large numbers over 25, such as 101, which accurately returned 24 zeros.
The idea behind the method is that if you take 25! then the first calculation is 25 * 24 = 600, so you can knock two zeros off immediately and then do 6 * 23 = 138. So it calculates the factorial removing zeros as it goes.
public static int count(int number) {
final BigInteger zero = new BigInteger("0");
final BigInteger ten = new BigInteger("10");
int zeroCount = 0;
BigInteger mult = new BigInteger("1");
while (number > 0) {
mult = mult.multiply(new BigInteger(Integer.toString(number)));
while (mult.mod(ten).compareTo(zero) == 0){
mult = mult.divide(ten);
zeroCount += 1;
}
number -= 1;
}
return zeroCount;
}
Since you said you don't care about run time at all (not that my first was particularly efficient, just slightly more so) this one just does the factorial and then counts the zeros, so it's cenceptually simpler:
public static BigInteger factorial(int number) {
BigInteger ans = new BigInteger("1");
while (number > 0) {
ans = ans.multiply(new BigInteger(Integer.toString(number)));
number -= 1;
}
return ans;
}
public static int countZeros(int number) {
final BigInteger zero = new BigInteger("0");
final BigInteger ten = new BigInteger("10");
BigInteger fact = factorial(number);
int zeroCount = 0;
while (fact.mod(ten).compareTo(zero) == 0){
fact = fact.divide(ten);
zeroCount += 1;
}
}

Categories