I'm trying to calculate an appropriate timeout time for a real time simulator that I'm writing:
For p = probability of success, the time for a successful request = m, and the time for a failed attempt = f. What is the average time for 5 successful requests?
Let's call the total number of tries x.
x = 5p + (x-5)(1-p)
x = 5 / p
The total time would be
t = 5m + (x-5)f
or
t = 5m + (5 / p - 5)f
If m=1, f=2, and p=0.1, the answer should be 5 * 1 + 45 * 2 = 95. This checks out.
There might be errors in here, but I did my best.
This is probably more appropriate on the stats exchange, by the way, but here's the answer:
If you want the average time, you need to average over the possible total number of trials required to get your five successes. This could be anywhere from 5 to infinite (it requires at least 5 trials to get 5 successes, and you could in theory have an infinitely long sequence of failures). I would suggest you could happily cut this off at a reasonable point to get an answer accurate to several decimal places for anything other than pathological values of p. Let n be the number of trials, from which we want to observe x=5 successes. The probability for 5 successes in n trials is given by the binomial distribution, parameterised by x, n, and p. Let Bin(x; n,p) be the binomial probability, then the time associated with this is:
5m + (n-5)f
To get the expectation (average) of this quantity, then you want the sum:
Bin(5; n,p) * 5m + (n-5)f
for for n=5 to n=inf. Depending on your value of p, you should be able to stop at n=20 to 30 and still obtain fairly accurate answers. Beware if you're using a naive implementation of the binomial probability that the computation of the binomial coefficient, which involves a term of n!, may fail for moderately large n, so you may want to consider the normal approximation to the binomial.
Related
I am looking for an explanation for this question since i'm studying for GRE:
An algorithm is run in 10 seconds for a size 50 entry. If the algorithm is quadratic, how long in seconds does it spend to approximately on the same computer if the input has size 100?
I can't see a relation between time and the input.
Considering: O(n^2) -> O(50^2) =! 10 (seconds)
Also, i would like to study more about this topic, so please add any source if you can.
Thanks.
Note that the terminology is sloppy, time complexity has no notion of time (yes, the name is deceiving).
Neglecting terms smaller than O(n2) since we are working under the big-O framework, a quadratic function can be expressed as
t = c * n2
Given the (t, n) pair with value (10, 50) we have
10 = c * 2500
c = 1/250 = 4/1000
Solving for (t, 100) we get
t = 4/1000 * 10000 = 40
There is a faster and more insightful way to solve this problem.
The trained eye can spot the answer as 40 immediately.
Consider this function power function:
t = c * nk
Now lets consider the inputs m0 and m1, with m1 = a * m0 being an (integer) multiple of m0.
Lets compare the respective t0, t1:
t0 = c * (m0)k
t1 = c * (m1)k = c * ak * (m0)k
So we see that for a polynomial time function t1/t0 = ak, or t1 = ak * t0.
The ratio between two output is the ratio between their inputs, to the k-th power.
For a quadratic function k = 2, thus the ration between two outputs is the square of the ratio between two inputs.
If the input doubles (ratio = 2) the output quadruples (ratio = 22 = 4).
If the input triples (ratio = 3) the output is nine-fold (ratio = 32 = 9).
A good mnemonic trick is to remember that the function from the inputs ratio to the outputs ratio is of the same kind of the given function.
We are given a quadratic function so that is the kind of relationship between the inputs and outputs ratios:
input output
ratio ratio
1 1
2 4
3 9
4 16
5 25
... ...
The problem tells you that the output doubles (from 50 to 100 entries) so the output must quadruple (from 10 to 40) as the function is quadratic.
As you can see all the data from the problem is used elegantly and without any hardcore computation.
Suggesting out-site sources is frowned upon but in this case I can't help but recomending the reading of:
Introduction to the Theory Computation - Michael Sipser
See if you can answer these questions:
If the input is now 150 entries, how much time does it take?
90
If the input is now 30 entries, how much time does it take?
90/25 ~ 4
If the input is now 100 entries but the program is run in a computer that is twice as fast, how much time does it take?
20
What size of the input is necessary to make the program run for at least 1000 seconds?
500
Given the time complexity you can't calculate the exact running time (in seconds) of the algorithm. However, it does give you a good idea of the growth rate of measured time.
In a linear time algorithm (O(n)), time is expected to increase linearly as a function of the input. For example, if 10,000 items take one second to process in some machine, then you should expect 50,000 items to take about 5 seconds, and so on. This isn't the case in a quadratic algorithm (O(n^2)), which "punishes" you more as the input size is larger; an increase of x2 in input size will result in x4 processing time, an increase x5 in input size will result in x25 processing time, etc (Just like the function F(x)=x^2 behaves).
You can use this post as an introduction, and this one as a more formal explanation.
The Big-O doesn't inform you about the exact correlation between entry size and the execution time, but instead it tells what's the approximate correlation between the entry size growth and the execution time growth. So: O(n) complexity means that the entry size and the execution time are in direct proportion (if the input is 3 times bigger, then the execution time will also be 3 times longer), O(n^2) means that if the entry size is 3 times bigger, then the execution time will be 9 times longer etc.
In your case, the initial execution time for a size 50 entry is 10 seconds. If the input changes to a size 100 entry, then by simply dividing we can tell that it's 100 / 50 = 2 times bigger. Knowing that the algorithm's Big-O is O(n^2), we can tell that the execution time will be 2^2 = 4 times longer. So if the initial execution time was 10 seconds, then the execution time for the bigger input will be approximately 10 seconds * 4 = 40 seconds.
Related SO question: Rough estimate of running time from Big O
Nice article about the big-o: https://rob-bell.net/2009/06/a-beginners-guide-to-big-o-notation/
I basically stucked on rather simple problem:
Toss N coins and discover, how many of them land heads
Solution performance must not depend on N, so we can't just call Math.random() < 0.5 N times. Obviously, there is Gaussian distribution to the rescue.
I used Box-Muller method for it:
function gaussian_random(mean, variance) {
var s;
var x;
var y;
do {
x = Math.random() * 2.0 - 1.0;
y = Math.random() * 2.0 - 1.0;
s = Math.pow(x, 2) + Math.pow(y, 2);
} while ( (s > 1) || (s == 0) );
var gaussian = x * Math.sqrt(-2*Math.log(s)/s);
return mean + gaussian * Math.sqrt(variance);
}
Math says, that mean of N coin tosses is N/2 and variance is N/4
Then, I made test, which tosses N coins M times, giving Minimum, Maximum, and Average number of heads.
I compared results of naive approach (Math.random() many times) and Gaussian Box-Muller approach.
There is typical output of tests:
Toss 1000 coins, 10000 times
Straight method:
Elapsed time: 127.330 ms
Minimum: 434
Maximum: 558
Average: 500.0306
Box-Muller method:
Elapsed time: 2.575 ms
Minimum: 438.0112461962819
Maximum: 562.9739632480057
Average: 499.96195358695064
Toss 10 coins, 10000 times
Straight method:
Elapsed time: 2.100 ms
Minimum: 0
Maximum: 10
Average: 5.024
Box-Muller method:
Elapsed time: 2.270 ms
Minimum: -1.1728354576573263
Maximum: 11.169478925333504
Average: 5.010078819562535
As we can see on N = 1000 it fits almost perfectly.
BUT, on N = 10 Box-Muller goes crazy: it allows such tests outcomes, where i can get (quite rarely, but it is possible) 11.17 heads from 10 coin tosses! :)
No doubt, i am doing something wrong. But what exactly?
There is source of test, and link to launch it
Updated x2: it seems, previously I didn't describe problem well. There is general version of it:
How to get sample mean of N uniform random values (either discrete or continuous) in amortized constant time. Gaussian distribution is efficient for large N, but is there a way to make it work good on small N? Or on which exactly N, solution should switch from Gaussian method to some other (for exampled straightforward).
Math says, that mean of N coin tosses is N/2 and variance is N/4.
Math only says that if it's a fair coin. And there's no way the solution doesn't depend on N.
Assuming all tosses are independent of each other, for exact behaviors use a binomial distribution rather than a normal distribution. Binomial has two parameters: N is the number of coin tosses, and p is the probability of getting heads (or tails if you prefer). In pseudocode...
function binomial(n, p) {
counter = 0
successes = 0
while counter < n {
if Math.random() <= p
successes += 1
counter += 1
}
return successes
}
There are faster algorithms for large N, but this is straightforward and mathematically correct.
Based on what discussed in approved answer i came up to this particular solution.
There is rule of thumb n*p >= 10 and n*(1-p) >= 10, but lets define stricter one.
First of all, Box-Muller gonna be hard capped at [-6,6], to ensure proper outcome (640 kB ought..., I mean, 6 sigmas ought to be enough for everybody).
Then, using 6 constant, we state, that in order for Box-Muller to produce valid results, Math.sqrt(variance) * 6 must not exceed mean. After using N/2 and N/4 as mean and variance respectively, and reductions, we end up with this:
Math.sqrt(N) * 6 <= N
N >= 36
While this condition is true, we can safely use capped Box-Muller Gaussian.
On any lower sample size, stick to the Binomial solution.
Just checked this rule statistically - on relatively large amount (10 million) of tests, minimum value stops falling out of boundaries from sample size 32 and above.
Suppose an algorithm is known to be O(N2) and solving a problem of size M takes 5 minutes. About how long will it take to solve a problem of size 4M?
Is it as simple as ...
M=5min
4M=20min
?
Since Big O is just an approximation you can not compute the real time but yes you can have some estimation. In your case it would be
1 M ~ 5 min
4 M ~ 5 *(4*4) min ~ 80 min.
Note : I used symbol ~ to show approximation.
O(N^2) => problem with size N will take approximately N^2 time
M will take approximately M^2 time
O(M)~ O(1M)
=> 1^2*M^2
=> M^2
=> 5 min
O(4M) ~ (4M)^2
=> 4^2*M^2
=> 16*M^2
=> 16*5
=> 80 min
If the complexity is O(N^2), this means the time for a problem of size N is roughly k*N^2 for some fixed but unknown value of k.
If you represent the approximate time to run the algorithm on a problem of size N as T(N), then mathematically you have this:
T(N) = k*N^2
T(M) = k*M^2
T(M) = 5 minutes
T(4*M) = k*(4*M)^2
= 16*k*M^2
= 16*T(M)
= 80 minutes
In a nutshell, not necesarily.
When we say that a problem's time complexity is O(N2), what that means is that given a problem of size N, the time it takes to run conforms roughly to some equation of the form a + bN + cN2, where a, b, and c are unknown coefficients.
This does mean that eventually the N2 term will dominate the run-time. But eventually might be a long time away. There might be a large constant set-up time built in (that is, a in the formula above is big), such that 4 of the 5 minutes of your hypothetical scenario don't vary with problem size. In that case, perhaps a problem of size 4M might take less than twice as long to run.
Situations along these lines can happen frequently with algorithms that involve hashing (such as some associative array implementations), particularly if a slow hash function such as SHA2 is being used. Which is why for small collections of elements searching a simple array to see if it contains an element might be faster than searching a hash table, even though searching an array is O(N) and searching a hash set is O(1).
Yes, it is simple, but your calculation is wrong.
What you have calculated is a linear growth, e.g. something of growth of O(n) e.g. if some input takes five minutes, you double the size of your input, then time spend is twice that time. You state that your algorithm run in O(n^2) which is exponential growth.
So your calculation would look like this:
M^2 = 5 minutes <=>
M = sqrt(5) = 2.23607 (approx)
so
(4M)^2 = (4*2.23607)^2 = 80 minutes
Which is exponential growth.
This is also why you never talk about specific run times in computer science. Whether something takes 5 minutes or 5 hours is not interesting. What is interesting is what happens when we change the size of the input. Because when we implement algorithms we want something that runs faster, no matter what computer is used for testing when the size of the input moves towards infinite.
Your guess is correct in case you have O(n), but we have O(n^2) which means you need to square the constant
T(M) = (M)^2 = M^2 = 5 minutes
T(4M) = (4 * M)^2 = 4^2 * M^2 = 16 * M^2
Substitute: M^2 = 5 minutes
T(4M) = 16 * M^2 = 16 * 5 minutes
T(4M) = 80 minutes
We have 3 functions with big o notations:
Func A: O(n)
Func B: O(n^2)
Func C: O(2^n)
If these functions does n proccesses in 10 seconds, how much time need to proccess 2 * n processes for each functions ? Also if you explain why i will be happy.
Thank You
Actually, you really can't tell with only one data point. By way of example, a simplistic answer for the first one would be "twice as long", 20 seconds, since O(n) means the time complexity rises directly proportional to the input parameter.
However, that fails to take into account that the big-O is usually simplified to show only the highest effect. The actual time taken may well be proportional to n plus a constant 5 - in other words, there's a constant 5 second set-up time that doesn't depend on n at all, then half a second per n after that.
That would mean the time take would be 15 seconds rather than 20. And, for the other cases mentioned it's even worse since O(n2) may actually be proportional to n^2 + 52n + 7 which means you would need three data points, assuming you even know all the components of the equation. It could even be something hideous like:
1 12
n^2 + 52*n + 7 + --- + ------
n 47*n^5
which would still technically be O(n2).
If they are simplistic equation (which is likely for homework), then you just need to put together the equations and then plug in 2n wherever you have n, then re-do the equation in terms of the original:
Complexity Equation Double N Time Multiplier
---------- -------- ------------- ---------------
O(n) t = n t = 2n 2
O(n^2) t = n^2 t = (2n)^2
= 4 * n^2 4
O(2^n) t = 2^n t = 2^(2n)
= 2^n * 2^n 2^n
(i.e., depends on
original n)
So., the answers I would have given would have been:
(A) 20 seconds;
(B) 40 seconds; and
(C) 10 x 2n seconds.
A: 2 times as much
B: 4 times as much
C: 2^n times as much
?
time depends on n now
given time is 10 seconds and n also 10, this makes 20, 40 and 1024 seconds respectively :)
but if n is 1, it will be 20, 40 and 40...
Here's a hint
Func A is your base measure that takes 1 unit of time to complete. In this problem, your unit of time is 10 seconds. So O(2*n) = 2*O(n) = 2 * Units = 2 * 10 sec = 20 sec.
Just plug 2*n into the n^2 and 2^n functions to get
O((2*n)^2) = O(2^2 * n^2) = O(4 * n^2)
O(2^(2*n)) = O((2^2)^n) = O(4^n)
Now just figure out how many time units each represents and multiply by 10 seconds.
EDIT: C is 10*2^n, I made a mistake in my answer. I'll leave it below but here is the mistake:
The real formula includes the processing rate, which I left out in my original answer. The processing rate falls away in the first two, but it doesn't in C.
2^n/p=10 (where p is the processing rate of units/second)
2^n=10*p
y=2^(n*2)/p
y=(2^n)^2/p
y=(10*p)^2/p
y=100*p^2/p
y=100*p (so we need to know the processing rate. If we know n, then we know the processing rate)
The units are fine above, as we have seconds^2/seconds = seconds.
Original Answer:
A: 20
B: 40
C: 100
The existing answers already explain A and B. Regarding the C equation, if my mathematics serve me correctly....
Part 1: What does n equal
2^n=10
log(2^n)=log(10)
n*log(2)=log(10)
n=log(10)/log(2)
Part 2: Now replace n with 2*n
x = 2^(2*n)
x = 2^(2*log(10)/log(2))
x = 100 (thanks excel: =2^(2*LOG(10)/LOG(2)))
Still I haven't used logarithms in 6 years, so please be forgiving if I'm wrong.
EDIT: Found a simpler way.
Given t is orginal time, and y is the new time.
t=2^n
y=2^(n*2)
y=(2^n)^2
y=t^2
y=10^2
y=100
Link to the original problem
It's not a homework question. I just thought that someone might know a real solution to this problem.
I was on a programming contest back in 2004, and there was this problem:
Given n, find sum of digits of n!. n can be from 0 to 10000. Time limit: 1 second. I think there was up to 100 numbers for each test set.
My solution was pretty fast but not fast enough, so I just let it run for some time. It built an array of pre-calculated values which I could use in my code. It was a hack, but it worked.
But there was a guy, who solved this problem with about 10 lines of code and it would give an answer in no time. I believe it was some sort of dynamic programming, or something from number theory. We were 16 at that time so it should not be a "rocket science".
Does anyone know what kind of an algorithm he could use?
EDIT: I'm sorry if I didn't made the question clear. As mquander said, there should be a clever solution, without bugnum, with just plain Pascal code, couple of loops, O(n2) or something like that. 1 second is not a constraint anymore.
I found here that if n > 5, then 9 divides sum of digits of a factorial. We also can find how many zeros are there at the end of the number. Can we use that?
Ok, another problem from programming contest from Russia. Given 1 <= N <= 2 000 000 000, output N! mod (N+1). Is that somehow related?
I'm not sure who is still paying attention to this thread, but here goes anyway.
First, in the official-looking linked version, it only has to be 1000 factorial, not 10000 factorial. Also, when this problem was reused in another programming contest, the time limit was 3 seconds, not 1 second. This makes a huge difference in how hard you have to work to get a fast enough solution.
Second, for the actual parameters of the contest, Peter's solution is sound, but with one extra twist you can speed it up by a factor of 5 with 32-bit architecture. (Or even a factor of 6 if only 1000! is desired.) Namely, instead of working with individual digits, implement multiplication in base 100000. Then at the end, total the digits within each super-digit. I don't know how good a computer you were allowed in the contest, but I have a desktop at home that is roughly as old as the contest. The following sample code takes 16 milliseconds for 1000! and 2.15 seconds for 10000! The code also ignores trailing 0s as they show up, but that only saves about 7% of the work.
#include <stdio.h>
int main() {
unsigned int dig[10000], first=0, last=0, carry, n, x, sum=0;
dig[0] = 1;
for(n=2; n <= 9999; n++) {
carry = 0;
for(x=first; x <= last; x++) {
carry = dig[x]*n + carry;
dig[x] = carry%100000;
if(x == first && !(carry%100000)) first++;
carry /= 100000; }
if(carry) dig[++last] = carry; }
for(x=first; x <= last; x++)
sum += dig[x]%10 + (dig[x]/10)%10 + (dig[x]/100)%10 + (dig[x]/1000)%10
+ (dig[x]/10000)%10;
printf("Sum: %d\n",sum); }
Third, there is an amazing and fairly simple way to speed up the computation by another sizable factor. With modern methods for multiplying large numbers, it does not take quadratic time to compute n!. Instead, you can do it in O-tilde(n) time, where the tilde means that you can throw in logarithmic factors. There is a simple acceleration due to Karatsuba that does not bring the time complexity down to that, but still improves it and could save another factor of 4 or so. In order to use it, you also need to divide the factorial itself into equal sized ranges. You make a recursive algorithm prod(k,n) that multiplies the numbers from k to n by the pseudocode formula
prod(k,n) = prod(k,floor((k+n)/2))*prod(floor((k+n)/2)+1,n)
Then you use Karatsuba to do the big multiplication that results.
Even better than Karatsuba is the Fourier-transform-based Schonhage-Strassen multiplication algorithm. As it happens, both algorithms are part of modern big number libraries. Computing huge factorials quickly could be important for certain pure mathematics applications. I think that Schonhage-Strassen is overkill for a programming contest. Karatsuba is really simple and you could imagine it in an A+ solution to the problem.
Part of the question posed is some speculation that there is a simple number theory trick that changes the contest problem entirely. For instance, if the question were to determine n! mod n+1, then Wilson's theorem says that the answer is -1 when n+1 is prime, and it's a really easy exercise to see that it's 2 when n=3 and otherwise 0 when n+1 is composite. There are variations of this too; for instance n! is also highly predictable mod 2n+1. There are also some connections between congruences and sums of digits. The sum of the digits of x mod 9 is also x mod 9, which is why the sum is 0 mod 9 when x = n! for n >= 6. The alternating sum of the digits of x mod 11 equals x mod 11.
The problem is that if you want the sum of the digits of a large number, not modulo anything, the tricks from number theory run out pretty quickly. Adding up the digits of a number doesn't mesh well with addition and multiplication with carries. It's often difficult to promise that the math does not exist for a fast algorithm, but in this case I don't think that there is any known formula. For instance, I bet that no one knows the sum of the digits of a googol factorial, even though it is just some number with roughly 100 digits.
This is A004152 in the Online Encyclopedia of Integer Sequences. Unfortunately, it doesn't have any useful tips about how to calculate it efficiently - its maple and mathematica recipes take the naive approach.
I'd attack the second problem, to compute N! mod (N+1), using Wilson's theorem. That reduces the problem to testing whether N is prime.
Small, fast python script found at http://www.penjuinlabs.com/blog/?p=44. It's elegant but still brute force.
import sys
for arg in sys.argv[1:]:
print reduce( lambda x,y: int(x)+int(y),
str( reduce( lambda x, y: x*y, range(1,int(arg)))))
$ time python sumoffactorialdigits.py 432 951 5436 606 14 9520
3798
9639
74484
5742
27
141651
real 0m1.252s
user 0m1.108s
sys 0m0.062s
Assume you have big numbers (this is the least of your problems, assuming that N is really big, and not 10000), and let's continue from there.
The trick below is to factor N! by factoring all n<=N, and then compute the powers of the factors.
Have a vector of counters; one counter for each prime number up to N; set them to 0. For each n<= N, factor n and increase the counters of prime factors accordingly (factor smartly: start with the small prime numbers, construct the prime numbers while factoring, and remember that division by 2 is shift). Subtract the counter of 5 from the counter of 2, and make the counter of 5 zero (nobody cares about factors of 10 here).
compute all the prime number up to N, run the following loop
for (j = 0; j< last_prime; ++j) {
count[j] = 0;
for (i = N/ primes[j]; i; i /= primes[j])
count[j] += i;
}
Note that in the previous block we only used (very) small numbers.
For each prime factor P you have to compute P to the power of the appropriate counter, that takes log(counter) time using iterative squaring; now you have to multiply all these powers of prime numbers.
All in all you have about N log(N) operations on small numbers (log N prime factors), and Log N Log(Log N) operations on big numbers.
and after the improvement in the edit, only N operations on small numbers.
HTH
1 second? Why can't you just compute n! and add up the digits? That's 10000 multiplications and no more than a few ten thousand additions, which should take approximately one zillionth of a second.
You have to compute the fatcorial.
1 * 2 * 3 * 4 * 5 = 120.
If you only want to calculate the sum of digits, you can ignore the ending zeroes.
For 6! you can do 12 x 6 = 72 instead of 120 * 6
For 7! you can use (72 * 7) MOD 10
EDIT.
I wrote a response too quickly...
10 is the result of two prime numbers 2 and 5.
Each time you have these 2 factors, you can ignore them.
1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15...
1 2 3 2 5 2 7 2 3 2 11 2 13 2 3
2 3 2 3 5 2 7 5
2 3
The factor 5 appears at 5, 10, 15...
Then a ending zero will appear after multiplying by 5, 10, 15...
We have a lot of 2s and 3s... We'll overflow soon :-(
Then, you still need a library for big numbers.
I deserve to be downvoted!
Let's see. We know that the calculation of n! for any reasonably-large number will eventually lead to a number with lots of trailing zeroes, which don't contribute to the sum. How about lopping off the zeroes along the way? That'd keep the sizer of the number a bit smaller?
Hmm. Nope. I just checked, and integer overflow is still a big problem even then...
Even without arbitrary-precision integers, this should be brute-forceable. In the problem statement you linked to, the biggest factorial that would need to be computed would be 1000!. This is a number with about 2500 digits. So just do this:
Allocate an array of 3000 bytes, with each byte representing one digit in the factorial. Start with a value of 1.
Run grade-school multiplication on the array repeatedly, in order to calculate the factorial.
Sum the digits.
Doing the repeated multiplications is the only potentially slow step, but I feel certain that 1000 of the multiplications could be done in a second, which is the worst case. If not, you could compute a few "milestone" values in advance and just paste them into your program.
One potential optimization: Eliminate trailing zeros from the array when they appear. They will not affect the answer.
OBVIOUS NOTE: I am taking a programming-competition approach here. You would probably never do this in professional work.
another solution using BigInteger
static long q20(){
long sum = 0;
String factorial = factorial(new BigInteger("100")).toString();
for(int i=0;i<factorial.length();i++){
sum += Long.parseLong(factorial.charAt(i)+"");
}
return sum;
}
static BigInteger factorial(BigInteger n){
BigInteger one = new BigInteger("1");
if(n.equals(one)) return one;
return n.multiply(factorial(n.subtract(one)));
}