Efficient way to count the digits of very big factorials - java

Suppose that we have a very large factorial such as (10^7)!, Is there an efficient way to count its exact digits? (Wolfram alpha result says (10^7)! has 65,657060 digits)
Of course, I can't use the naive implementation by successively multiplying the value one by one since it will be too slow to evaluate the result.
I think the solution to this question might ended up in either
How to find the digit of the factorial without calculating the factorial
How to compute the factorial more efficiently (BigInteger or BigDecimal is preferable)
I would prefer 1. rather than 2. since I just want to know how many digits of the factorial.
Any suggestion?

Adding up the logs of all the numbers you would multiply by should do the trick:
public long facDigits(long n) {
double logFacN = 0;
for (long i = 2; i <= n; i++) {
logFacN += Math.log10(i);
}
return (long) logFacN + 1;
}
public void test() {
double tenToThe7th = Math.pow(10, 7);
long digits = facDigits((long) tenToThe7th);
System.out.println("Digits in " + tenToThe7th + "! = " + digits);
}
prints
Digits in 1.0E7! = 65657060
The logic here is that as you multiply by x while calculating the factorial you are actually adding log10(x) digits so here I just add those up.

#OldCurmudgeon's solution is good but you can try to use Kamentsky's formula:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
int numOfTests = Integer.parseInt(in.readLine());
in.lines()
.limit(numOfTests)
.map(n -> Integer.parseInt(n))
.forEach(n -> System.out.println(KamenetskyFormula(n)));
}
private static long KamenetskyFormula(int n) {
if (n < 2) {
return 1;
}
double x = n * Math.log10(n / Math.E) + Math.log10(2 * Math.PI * n) / 2.0;
return (long) (Math.floor(x) + 1);
}
}
connected to Count number of digits in factorial - performance issue

Related

Stochastic Search to lambda expression

Thanks for all your help and sharing.
My question is in regards of the Stochastic Search. This technique is used to do approximations of data through a defined amount of cicles over a, an in general, mathematical calculation. Please see following code, I tried to reduce it to its minimum. My expectation is to have this code setup as a lambda expression, the for loop, I would like to have the best performance of it. I have some intents but I'm not sure if I got the most of it.
package stochasticsearch;
import java.util.Random;
public class StochasticSearch {
public static double f(double x) {
return -(x - 1) * (x - 1) + 2;
}
public static void main(String[] args) {
final Random random = new Random();
double startPointX = 0;
double max = f(startPointX);
long begin = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
double index = 2 * random.nextDouble();
if (f(index) > max) {
max = f(index);
}
}
System.out.println("Elapsed time: " + (System.currentTimeMillis() - begin));
System.out.println("Maximum value y=f(x) is " + max);
}
}
Thanks, have a nice day.
Your code completes in a little under 23 seconds on my system, and I was able to modify it so that it takes under 2 seconds. Here's what I found:
You're using Random when you could be using ThreadLocalRandom instead; this switch results in a relatively-large speedup.
You're calculating f(index) twice inside your for-loop in certain cases when it should only be computed once per iteration.
Because you're iterating over a large range of values, you could utilize a parallel stream instead; this results in a relatively-large speedup as well.
You're adding 2 to every result in f, so it's better to add it a single time once max has been calculated.
public static double f(double x) {
double y = x - 1;
return -y * y;
}
public static void main(String[] args) {
final ThreadLocalRandom random = ThreadLocalRandom.current();
long begin = System.currentTimeMillis();
double max = IntStream.range(0, 1_000_000_000)
.parallel()
.mapToDouble(i -> f(random.nextDouble() * 2))
.max()
.orElse(f(0)) + 2;
System.out.println("Elapsed time: " + (System.currentTimeMillis() - begin));
System.out.println("Maximum value y=f(x) is " + max);
}

Reducing the time complexity/Optimizing the solution

The motto is to find the sum of all the multiples of 3 or 5 below N.
Here's my code:
public class Solution
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
int t = in.nextInt();
long n=0;
long sum=0;
for(int a0 = 0; a0 < t; a0++)
{
n = in.nextInt();
sum=0;
for(long i=1;i<n;i++)
{
if(i%3==0 || i%5==0)
sum = sum + i;
}
System.out.println(sum);
}
}
}
It's taking more than 1sec to execute for some of the test cases. Can anyone please help me out so as to reduce the time complexity?
We can find the sum of all multiples of number d that are below N as a sum of an arithmetic progression (their sum is equal to d + 2*d + 3*d + ...).
long multiplesSum(long N, long d) {
long highestMultiple = (N-1) / d * d;
long numberOfMultiples = highestMultiple / d;
return (d + highestMultiple) * numberOfMultiples / 2;
}
Then the result will be equal to:
long resultSum(long N) {
return multiplesSum(N, 3) + multiplesSum(N, 5) - multiplesSum(N, 3*5);
}
We need to subtract multiplesSum(N, 15) because there are numbers that are multiples of both 3 and 5 and we added them twice.
Complexity: O(1)
You can't reduce the time complexity in this case as there are still O(N) of each set of numbers. However you can reduce the constant multiplier by using integer division:
static int findMultiples(int N, int s)
{
int c = N / s, sum = 0;
for (int i = 0, k = s; i < c; i++, k += s)
sum += k;
return sum;
}
This way you only loop through the multiples themselves instead of the whole range [0, N].
Note that you will need to do findMultiples(N, 3) + findMultiples(N, 5) - findMultiples(N, 15), to remove the duplicated multiples of both 3 and 5. The number of loops is therefore N/3 + N/5 + N/15 = 0.6N instead of N.
EDIT: in general the solution for an arbitrary number of divisors is sum(findMultiples(N,divisor_i) - findMultiples(N,LCM(all_divisors)); however it is only worth doing this if sum(1/divisor_i) + 1/LCM(all_divisors) < 1, otherwise there will be more loops. Luckily this will never be true for 2 divisors.
The sum of all numbers from 1 to (including) N is known to be N(N+1)/2 (no need for iteration).
So, the sum of all multiples of K, from K to KM is K times the above formula, giving KM(M+1)/2.
Combine this with #meowgoesthedog's findMultiples(N, 3) + findMultiples(N, 5) - findMultiples(N, 15) idea, and you have a constant-time solution.
A solution for your problem.Fastest method for solving your problem.
import java.util.*;
class Solution {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int t = in.nextInt();
while(t!=0)
{
long a=in.nextLong();
long q=a-1;
long aa=q/3;
long bb=q/5;
long cc=q/15;
long aaa=((aa*(aa+1))/2)*3;
long bbb=((bb*(bb+1))/2)*5;
long ccc=((cc*(cc+1))/2)*15;
System.out.println(aaa+bbb-ccc);
t-=1;}
}
}

Parallel factorial calculation of ALL elements up until a given number

I have a task to write a parallel program that calculates pi (Chudnovsky formula). However, it has factorial in the calculations. So for decomposition of the task, I want to calculate the factorials before I start calculating the formula (that is, calculate all factorials, store them somewhere, and then just read them when they need to be read, instead of calculating those factorials on the spot).
I've read several questions here, but they are about the parallel calculation of a single factorial number. They aren't very helpful when I need to calculate ALL the numbers up until a given index (they are based on the parallel sum/product method). Does anyone have an idea for a good decomposition of the task?
For this you can apply dynamic programmig. Dynamic programming is a way to solve problems in most efficient way. It’s actually avoid to compute sub problem again and again. For the factorial n you always multiply n by (n-1)! If you apply this I think the faster way to compute all factorials is serial:
BigInteger current = BigInteger.ONE;
List<BigInteger> fact = new ArrayList<>();
fact.add(BigInteger.ONE);
for (int i = 1; i <= n; i++) {
current = current.multiply(BigInteger.valueOf(i));
fact.add(current);
}
You can use fork and join parallel strategy here.
Let's say you have to calculate factorial of 10. For this you'll have to multiply numbers from 2 to 10. You can divide this task till your task becomes multiplication of 2 or 3 numbers.
Here is sample code for this:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
public class ForkTest {
public static void main(String[] args) {
ForkJoinPool forkJoinPool = new ForkJoinPool(4);
for (int i = 2; i < 11; i++) {
Factorial myRecursiveAction = new Factorial(2, i);
forkJoinPool.invoke(myRecursiveAction);
System.out.println("i=" + i + " result=" + myRecursiveAction.getRawResult());
}
}
}
class Factorial extends RecursiveTask<Long> {
private int low;
private int high;
public Factorial(int low, int high) {
this.low = low;
this.high = high;
}
protected Long compute() {
if (high - low >= 2) {
//System.out.println("Dividing number from : " + low + " - " + high);
int mid = (high + low) / 2;
Factorial lowerRange = new Factorial(low, mid);
Factorial higherRange = new Factorial(mid + 1, high);
List<Factorial> subtasks = new ArrayList<Factorial>();
subtasks.add(lowerRange);
subtasks.add(higherRange);
for (Factorial subtask : subtasks) {
subtask.fork();
}
long result = 1;
for (Factorial subtask : subtasks) {
result *= subtask.join();
}
return result;
} else {
long facto = low;
for (int i = low + 1; i <= high; i++) {
facto = facto * i;
}
//System.out.println("Multiplying number from : " + low + " - " + high + " result=" + facto);
return facto;
}
}
}

Project Euler #6 Two codes, different answers ONLY for big inputs. Why?

Here are two codes for solving problem 6 in project euler: Why do they give similar answers until I make the number larger? (100,000)
The sum of the squares of the first ten natural numbers is,
12 + 22 + ... + 102 = 385
The square of the sum of the first ten
natural numbers is,
(1 + 2 + ... + 10)2 = 552 = 3025
Hence the difference between the sum
of the squares of the first ten natural numbers and the square of the
sum is 3025 − 385 = 2640.
Find the difference between the sum of the squares of the first one
hundred natural numbers and the square of the sum.
Code 1:
public class Problem_Six_V2 {
public static void main(String[] args) {
long limit = 100000;
long sum = (limit * (limit + 1)) / 2;
long sumOfSqr = (long)((((2*limit)*limit)+((2*limit)*1)+(1*limit)+(1*1))*limit)/6;
System.out.println(Math.pow(sum, 2) +" "+ sumOfSqr);
System.out.println(Math.pow(sum, 2) - sumOfSqr);
}
}
^^^ Outputs = 2.500016666416665E19
Here's code two:
public class Problem_Six {
public static void main(String[] args) {
long sum = 0;
long sumSqr = 0;
long sumOfSqr = 0;
for(long i = 1; i <= 100000; i++){
sum += i;
sumOfSqr += Math.pow(i,2);
}
sumSqr = (long) Math.pow(sum, 2);
System.out.println(sumSqr +" "+ sumOfSqr);
System.out.println(sumSqr - sumOfSqr);
}
}
^^ Outputs = 9223038698521425807
I guess it's something to two with the types being used, but they seem similar in both codes..hmm
Math.pow(i,2) accepts doubles as parameters. Doubles are not 100% precise,
you lose precision. Stick to operations on int/long only. The answer is pretty small
and fits even into an int.
Not sure why you use 100000 as your limit, problem 6 has 100 as a limit.
In Java when results of integer arithmetic don't fit into int variables,
you should use long, when they don't fit even into long variables, you
should use BigInteger.
But avoid doubles, they are not precise for such kinds of tasks.
Here is your program corrected.
import java.math.BigInteger;
public class Problem_Six {
public static void main(String[] args) {
BigInteger sum = BigInteger.ZERO;
BigInteger sumSqr = BigInteger.ZERO;
BigInteger sumOfSqr = BigInteger.ZERO;
for (long i = 1; i <= 100000; i++) {
sum = sum.add(BigInteger.valueOf(i));
sumOfSqr = sumOfSqr.add(BigInteger.valueOf(i * i));
}
sumSqr = sum.multiply(sum);
System.out.println(sumSqr + " " + sumOfSqr);
System.out.println(sumSqr.subtract(sumOfSqr).toString());
// System.out.println(Long.MAX_VALUE);
}
}

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