Parallel factorial calculation of ALL elements up until a given number - java

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;
}
}
}

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;}
}
}

Efficient way to count the digits of very big factorials

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

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);
}
}

Sum of the digits of the number 2^1000 [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
2^15 = 32768 and the sum of its digits is 3 + 2 + 7 + 6 + 8 = 26.
What is the sum of the digits of the number 2 power of 1000 (2^1000)?
Can anyone provide the solution or algorithm for this problem in java?
Here is my solution:
public static void main(String[] args) {
ArrayList<Integer> n = myPow(2, 100);
int result = 0;
for (Integer i : n) {
result += i;
}
System.out.println(result);
}
public static ArrayList<Integer> myPow(int n, int p) {
ArrayList<Integer> nl = new ArrayList<Integer>();
for (char c : Integer.toString(n).toCharArray()) {
nl.add(c - 48);
}
for (int i = 1; i < p; i++) {
nl = mySum(nl, nl);
}
return nl;
}
public static ArrayList<Integer> mySum(ArrayList<Integer> n1, ArrayList<Integer> n2) {
ArrayList<Integer> result = new ArrayList<Integer>();
int carry = 0;
int max = Math.max(n1.size(), n2.size());
if (n1.size() != max)
n1 = normalizeList(n1, max);
if (n2.size() != max)
n2 = normalizeList(n2, max);
for (int i = max - 1; i >= 0; i--) {
int n = n1.get(i) + n2.get(i) + carry;
carry = 0;
if (n > 9) {
String s = Integer.toString(n);
carry = s.charAt(0) - 48;
result.add(0, s.charAt(s.length() - 1) - 48);
} else
result.add(0, n);
}
if (carry != 0)
result.add(0, carry);
return result;
}
public static ArrayList<Integer> normalizeList(ArrayList<Integer> l, int max) {
int newSize = max - l.size();
for (int i = 0; i < newSize; i++) {
l.add(0, 0);
}
return l;
}
This code can be improved in many ways ... it was just to prove you can perfectly do it without BigInts.
The catch is to transform each number to a list. That way you can do basic sums like:
123456
+ 45
______
123501
int result = 0;
String val = BigInteger.valueOf(2).pow(1000).toString();
for(char a : val.toCharArray()){
result = result + Character.getNumericValue(a);
}
System.out.println("val ==>" + result);
It's pretty simple if you know how to use the biginteger.
I won't provide code, but java.math.BigInteger should make this trivial.
This problem is not simply asking you how to find the nearest big integer library, so I'd avoid that solution. This page has a good overview of this particular problem.
Create a vector of length 302, which is the length of 2^1000. Then, save 2 at index 0, then, double 1000 times. Just look at every index separetly and add 1 to the next index if the previous exeeds 10. Then just sum it up!
something like that sould do it bute force: - although there is a nice analytic solution (think pen& paper) using mathematics - that may also work for numbers greater than 1000.
final String bignumber = BigInteger.valueOf(2).pow(1000).toString(10);
long result = 0;
for (int i = 0; i < bignumber.length(); i++) {
result += Integer.valueOf(String.valueOf(bignumber.charAt(i)));
}
System.out.println("result: " + result);
How can 2^1000 be alternatively expressed?
I don't remember much from my maths days, but perhaps something like (2^(2^500))? And how can that be expressed?
Find an easy way to calculate 2^1000, put the result in a BigInteger, and the rest is perhaps trivial.
Here is my code... Please provide the necessary arguments to run this code.
import java.math.BigInteger;
public class Question1 {
private static int SumOfDigits(BigInteger inputDigit) {
int sum = 0;
while(inputDigit.bitLength() > 0) {
sum += inputDigit.remainder(new BigInteger("10")).intValue();
inputDigit = inputDigit.divide(new BigInteger("10"));
}
return sum;
}
public static void main(String[] args) {
BigInteger baseNumber = new BigInteger(args[0]);
int powerNumber = Integer.parseInt(args[1]);
BigInteger powerResult = baseNumber.pow(powerNumber);
System.out.println(baseNumber + "^" + powerNumber + " = " + powerResult);
System.out.println("Sum of Digits = " + Question1.SumOfDigits(powerResult));
}
}
2^1000 is a very large value, you would have to use BigIntegers. The algorithm would be something like:
import java.math.BigInteger;
BigInteger two = new BigInteger("2");
BigInteger value = two.pow(1000);
int sum = 0;
while (value > 0) {
sum += value.remainder(new BigInteger("10"));
value = value.divide(new BigInteger("10"));
}
Alternatively, you could grab a double and manipulate its bits. With numbers that are the power of 2, you won't have truncation errors. Then you can convert it to string.
Having that said, it's still a brute-force approach. There must be a nice, mathematical way to make it without actually generating a number.
In[1162] := Plus ## IntegerDigits[2^1000]
Out[1162] = 1366

Categories