Confused about prime number checking function - math

I came across a question on stack overflow about how to check if a number is prime. The answer was the code below. The function int is_prime(int num) returns 1 when the number is prime 0 is returned otherwise.
int is_prime(int num)
{
if (num <= 1) return 0;
if (num % 2 == 0 && num > 2) return 0;
for(int i = 3; i < num / 2; i+= 2)
{
if (num % i == 0)
return 0;
}
return 1;
}
All the logic in the if statements makes sense to me except for the for loop expressions. I don't get why the division i < num / 2 happens and why i+= 2 is being used. Sure one is there to advance the counter and the other is to halt the loop. but why half the number and why increment by two. Any reasonable explanation will be appreciated. Thanks.

Regarding the loop's increment:
The second if (if (num % 2 == 0)) checks if the number is even, and terminates the function if it is. If the function isn't terminated, we know that it's odd, and thus, may only be divisible by other odd numbers. Hence, the loop starts at 3 and checks the number against a series of odd numbers - i.e., increments the potential divisor by 2 on each iteration.
Regarding the loop's stop condition:
The smallest integer larger than 1 is 2. Thus, the largest integer that could ever divide an integer n is n/2. Thus, the loop works it's way up to num/2. If it didn't find a divisor for num by the time it reaches num/2, it has no chance to ever find such a divisor, so it's pointless to keep on going.

Related

How many zero total in 100 factorial

I have a homework that count total zero in n factorial. What should i do?
I only find way to count trailing of factorial
static int findTrailingZeros(int n)
{
// Initialize result
int count = 0;
// Keep dividing n by powers
// of 5 and update count
for (int i = 5; n / i >= 1; i *= 5)
count += n / i;
return count;
}
The total number of zeros in n! is given by sequence A027869 in the On-line Encyclopedia of Integer Sequences. There really seems to be no way to compute the total number of zeros in n! short of computing n! and counting the number of zeros. With a big int library, this is easy enough. A simple Python example:
import math
def zeros(n): return str(math.factorial(n)).count('0')
So, for example, zeros(100) evaluates to 30. For larger n you might want to skip the relatively expensive conversion to a string and get the 0-count arithmetically by repeatedly dividing by 10.
As you have noted, it is far easier to compute the number of trailing zeros. Your code, in Python, is essentially:
def trailing_zeros(n):
count = 0
p = 5
while p <= n:
count += n//p
p *= 5
return count
As a heuristic way to estimate the total number of zeros, you can first count the number of trailing zeros, subtract that from the number of digits in n!, subtract an additional 2 from this difference (since neither the first digit of n! nor the final digit before the trailing zeros are candidate positions for non-trailing zeros) and guess that 1/10 of these digits will in fact be zeros. You can use Stirling's formula to estimate the number of digits in n!:
def num_digits(n):
#uses Striling's formula to estimate the number of digits in n!
#this formula, known as, Kamenetsky's formula, gives the exact count below 5*10^7
if n == 0:
return 1
else:
return math.ceil(math.log10(2*math.pi*n)/2 + n *(math.log10(n/math.e)))
Hence:
def est_zeros(n):
#first compute the number of candidate postions for non-trailing zerpos:
internal_digits = max(0,num_digits(n) - trailing_zeros(n) - 2)
return trailing_zeros(n) + internal_digits//10
For example est_zeros(100) evaluates to 37, which isn't very good, but then there is no reason to think that this estimation is any better than asymptotic (though proving that it is asymptotically correct would be very difficult, I don't actually know if it is). For larger numbers it seems to give reasonable results. For example zeros(10000) == 5803 and est_zeros == 5814.
How about this then.
count = 0
s = str(fact)
for i in s:
if i=="0":
count +=1
print(count)
100! is a big number:
100! = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
To be more precise it need ~525 bit and can not be computed without some form of bigint math.
However trailing zeros might be computable on normal integers:
The idea is to limit the result to still fit into your data type. So after each iteration test if the result is divisible by 10. If it is increment your zeros counter and divide the result by 10 while you can. The same goes for any primes except those that divide 10 so not: 2,5 (but without incrementing your zeros counter). This way you will have small sub-result and count of trailing zeros.
So if you do a 2,5 factorization of all the multiplicants in n! the min of the both exponents of 2,5 will be the number of trailing zeros as each pair produces one zero digit (2*5 = 10). If you realize that exponent of 5 is always smaller or equal than exponent of 2 its enough to do the factorization of 5 (just like you do in your updated code).
int fact_trailing_zeros(int n)
{
int i,n5;
for (n5=0,i=5;n>=i;i*=5) n5+=n/i;
return n5;
}
With results:
Trailing zeors of n!
10! : 2
100! : 24
1000! : 249
10000! : 2499
100000! : 24999
1000000! : 249998
10000000! : 2499999
100000000! : 24999999
[ 0.937 ms]
However 100! contains also non trailing zeros and to compute those I see no other way than compute the real thing on a bigint math ... but that does not mean there is no workaround like for trailing zeros...
If it helps here are computed factorials up to 128! so you can check your results:
Fast exact bigint factorial
In case n is bounded to small enough value you can use LUT holding all the factorials up to the limit as strings or BCD and just count the zeros from there... or even have just the final results as a LUT ...
Here some bad code, but it works. You have to use TrailingZeros() only
public static int TrailingZeros(int n)
{
var fac = Factorial(n);
var num = SplitNumber(fac);
Array.Reverse(num);
int i = 0;
int res = 0;
while (num[i] == 0)
{
if (num[i] == 0)
{
res++;
}
i++;
}
return res;
}
public static BigInteger Factorial(int number)
{
BigInteger factorial = 1; // значение факториала
for (int i = 2; i <= number; i++)
{
factorial = factorial * i;
}
return factorial;
}
public static int[] SplitNumber(BigInteger number)
{
var result = new int[0];
int count = 0;
while (number > 0)
{
Array.Resize(ref result, count + 1);
result[count] = (int)(number % 10);
number = number / 10;
count++;
}
Array.Reverse(result);
return result;
}

Dynamic Programming: Child running up a staircase

I'm starting to practice Dynamic Programming and I just can't wrap my head around this question:
Question:
A child is running up a staircase with n steps and can hop either 1 step, 2 steps, or 3 steps at a time. Implement a method to count how many possible ways the child can run up the stairs.
The solution from the cracking the coding interview book is like this:
"If we thought about all the paths to the nth step, we could just build them off the paths to the three previous steps. We can get up to the nth stop by any of the following:
Going to the (n-1) step and hopping 1 step
Going to the (n-2) step and hopping 2 steps
Going to the (n-3) step and hopping 3 steps"
Therefor to find the solution you just add the number of these path together !
That's what loses me ! Why isn't the answer like this: add number of those paths then add 3 ? Since if you are on step n-1 or n-2 or n-3, there are 3 ways to get the nth step? I understand that if you write down the answers for the first 4 bases cases (assuming that n=0 returns 1) You can see the fibonacci-like pattern. But you may not also see it so it's difficult.
And then they came up with this code:
public static int countWaysDP(int n, int[] map) {
if (n < 0)
return 0;
else if (n == 0)
return 1;
else if (map[n] > -1)
return map[n];
else {
map[n] = countWaysDP(n - 1, map) + countWaysDP(n - 2, map) + countWaysDP(n - 3, map);
return map[n]; }
}
So my second question. How does it return 1 when n == 0. Even if I accept that fact, I still can't figure out a way to solve it if I return 0 when n == 1.
Hope this makes sense.
Thank you
Here is how I wrapped my head around this-
From the book -
On the very last hop, up to the nth step, the child could have
done either a single, double, or triple step hop. That is, the last
move might have been a single step hop from step n-1, a double
step hop from step n-2, or a triple step hop from n-3. The
total number of ways of reaching the last step is therefore the sum of
the number of ways of reaching each of the last three steps
You are correctly contemplating -
Why isn't the answer like this: add number of those paths then add 3 ?
Since if you are on step n-1 or n-2 or n-3, there are 3 ways to get
the nth step?
The problem with such a base case is that it will be applicable only if n >= 3. You clearly will not add 3 if there are only 2 steps.
Let's break down the individual cases and understand what exactly is the base case here.
n=0
There are no stairs to climb.
Total number of ways = 0
n=1
Total number of ways = 1StepHop from (n-1)
Number of ways to do 1StepHop from Step 0(n-1) = 1
Total number of ways = 1
n=2
Total number of ways = 2StepHop from (n-2) + 1StepHop from (n-1)
Number of ways to do 2StepHop to reach Step 2 from Step 0(n-2) = 1
Number of ways to do 1StepHop to reach Step 2 from Step 1(n-1) = 1 (Previous answer for n=1)
Total number of ways = 1 + 1 = 2
n=3
Total number of ways = 3StepHop from (n-3) + 2StepHop from (n-2) + 1StepHop from (n-1)
Number of ways to do 3StepHop to reach Step 3 from Step 0(n-3) = 1
Number of ways to do 2StepHop to reach Step 3 from Step 1(n-2) = 2 (From previous answer for n = 2)
Number of ways to do 1StepHop to reach Step 3 from Step 2 = 1 (From previous answer for n=1)
Total number of ways = 1 + 2 + 1 = 4
Observation -
As you can see from above, we are correctly accounting for the last step in each case. Adding one for each of -> 1StepHop from n-1, 2StepHop from n-2 and 3StepHop from n-3.
Now looking at the code, the case where we return 1 if n==0 is a bit counter-intuitive since we already saw that the answer should be 0 if n==0. -
public static int countWaysDP(int n, int[] map) {
if (n < 0)
return 0;
else if (n == 0)
return 1; <------------- this case is counter-intuitive
else if (map[n] > -1)
return map[n];
else {
map[n] = countWaysDP(n - 1, map) + countWaysDP(n - 2, map) + countWaysDP(n - 3, map);
return map[n];
}
From the observation, you can see that this counter intuitive case of n==0 is actually the one which is accounting for the final step - 1StepHop from n-1, 2StepHop from n-2 and 3StepHop from n-3.
So hitting n==0 case makes sense only during recursion - which will happen only when the initial value of n is greater than 0.
A more complete solution to this problem may have a driver method which handles that case outside of the core recursive algorithm -
int countWays(int n) {
if (n <= 0 ) return 0;
int[] map = new int[n+1];
for(int i = 0; i<n+1; i++){
map[i] = -1;
}
return countWaysDP(n, map);
}
Hope this is helpful.
You can find the solution on
https://github.com/CrispenGari/Triple-Step-Algorithim/blob/master/main.cpp .
int count_Ways(int n){
if(n<0){
return 0;
}else if(n==0){
return 1;
}else{
return count_Ways(n-1) +count_Ways(n-2) + count_Ways(n-3);
}
}
int main(){
cout<<"Enter number of stairs: ";
int n;
cin>>n;
cout<<"There are "<< count_Ways(n)<<" possible ways the child can run up
thestairs."<<endl;
return 0;
}

How to find perfect numbers upto 10^18 in C?

I have a C code off finding large perfect numbers below,
#include <stdio.h>
int main ()
{
unsigned long long num,i,sum;
while (scanf ("%llu",&num) != EOF && num)
{
sum = 1;
for (i=2; i*i<=num; i++)
{
if (num % i == 0)
{
if (i*i == num)
sum += i;
else
sum += (i + num/i);
}
}
if (sum == num)
printf ("Perfect\n");
else if (sum > num)
printf ("Abundant\n");
else
printf ("Deficient\n");
}
return 0;
}
I tried to find whether a number is perfect, abundant or deficient. I run a loop upto the square root of numto minimize the runtime. It works fine <= 10^15 but for the larger values it takes too long time to execute.
For example,for the following input sets,
8
6
18
1000000
1000000000000000
0
this code shows the following outputs,
Deficient
Perfect
Abundant
Abundant
Abundant
But, for 10^16 it doesn't respond quickly.
So, is there any better way to find a perfect number for too long values? Or is there any better algorithm to implement here??? :)
Yes, there is a better algorithm.
Your algorithm is basically the simple one--adding up the divisors of a number to find... the sum of the divisors of a number (excluding itself). But you can use the number-theoretic formula for finding the sum of the divisors of a number (including itself). If the prime numbers dividing n are p1, p2, ..., pk and the powers of those primes in the canonical decomposition of n are a1, a2, ..., ak, then the sum of the divisors of n is
(p1**(a1+1) - 1) / (p1 - 1) * (p2**(a2+1) - 1) / (p2 - 1) * ...
* (pk**(ak+1) - 1) / (pk - 1)
You can find the prime divisors and their exponents more quickly than finding all the divisors of n. Subtract n from that expression above and you get the sum you want.
There are some tricks, of course, to find the pis and ais more efficiently: I'll leave that to you.
By the way, if your purpose is just to find the perfect numbers, as in your title, you would do better to use Euclid's formula for even prime numbers. Find the Mersenne prime numbers by examining all 2**p-1 for prime p to see if they are prime--there are shortcuts to doing this as well--then constructing a perfect number from that Mersenne prime. This would leave out any odd perfect numbers, though. If you find any, let the mathematical community know--that would make you world famous.
Of course, the fastest way of all to find perfect numbers is to use the lists already made of some of them.
It is a matter of factorization of numbers. You can read more here: https://en.wikipedia.org/wiki/Integer_factorization
Unfortunately no good news for you - the bigger the number gets, the longer it takes.
To start with your code, try not to multiply i*i each iteration.
Instead of:
for (i=2; i*i<=num; i++)
calculate square root of num first, and then compare
i <= square_root_of_num in the loop.
// Program to determine whether perfect or not
# include <bits/stdc++.h>
using namespace std;
map<long long int, int> mp; // to store prime factors and there frequency
void primeFactors(long long int n)
{
// counting the number of 2s that divide n
while (n%2 == 0)
{
mp[2] = mp[2]+1;
n = n/2;
}
long long int root = sqrt(n);
// n must be odd at this point. So we can skip every even numbers next
for (long long int i = 3; i <= root; i = i+2)
{
// While i divides n, count frequency of i prime factor and divide n
while (n%i == 0)
{
mp[i] = mp[i]+1;
n = n/i;
}
}
// This condition is to handle the case whien n is a prime number
// greater than 2
if (n > 2)
{
mp[n] = mp[n]+1;
}
}
long long int pow(long long int base, long long int exp)
{
long long int result = 1;
base = base;
while (exp>0)
{
if (exp & 1)
result = (result*base);
exp >>= 1;
base = (base*base);
}
return result;
}
int main ()
{
long long num, p, a, sum;
while (scanf ("%lld",&num) != EOF && num)
{
primeFactors(num);
sum = 1;
map<long long int, int> :: iterator i;
for(i=mp.begin(); i!=mp.end(); i++)
{
p = i->first;
a = i->second;
sum = sum*((pow(p,a+1)-1)/(p-1));
}
if (sum == 2*num)
printf ("Perfect\n");
else if (sum > num)
printf ("Abundant\n");
else
printf ("Deficient\n");
mp.clear();
}
return 0;
}

Determining the big Oh for (n-1)+(n-1)

I have been trying to get my head around this perticular complexity computation but everything i read about this type of complexity says to me that it is of type big O(2^n) but if i add a counter to the code and check how many times it iterates per given n it seems to follow the curve of 4^n instead. Maybe i just misunderstood as i placed an count++; inside the scope.
Is this not of type big O(2^n)?
public int test(int n)
{
if (n == 0)
return 0;
else
return test(n-1) + test(n-1);
}
I would appreciate any hints or explanation on this! I completely new to this complexity calculation and this one has thrown me off the track.
//Regards
int test(int n)
{
printf("%d\n", n);
if (n == 0) {
return 0;
}
else {
return test(n - 1) + test(n - 1);
}
}
With a printout at the top of the function, running test(8) and counting the number of times each n is printed yields this output, which clearly shows 2n growth.
$ ./test | sort | uniq -c
256 0
128 1
64 2
32 3
16 4
8 5
4 6
2 7
1 8
(uniq -c counts the number of times each line occurs. 0 is printed 256 times, 1 128 times, etc.)
Perhaps you mean you got a result of O(2n+1), rather than O(4n)? If you add up all of these numbers you'll get 511, which for n=8 is 2n+1-1.
If that's what you meant, then that's fine. O(2n+1) = O(2⋅2n) = O(2n)
First off: the 'else' statement is obsolete since the if already returns if it evaluates to true.
On topic: every iteration forks 2 different iterations, which fork 2 iterations themselves, etc. etc. As such, for n=1 the function is called 2 times, plus the originating call. For n=2 it is called 4+1 times, then 8+1, then 16+1 etc. The complexity is therefore clearly 2^n, since the constant is cancelled out by the exponential.
I suspect your counter wasn't properly reset between calls.
Let x(n) be a number of total calls of test.
x(0) = 1
x(n) = 2 * x(n - 1) = 2 * 2 * x(n-2) = 2 * 2 * ... * 2
There is total of n twos - hence 2^n calls.
The complexity T(n) of this function can be easily shown to equal c + 2*T(n-1). The recurrence given by
T(0) = 0
T(n) = c + 2*T(n-1)
Has as its solution c*(2^n - 1), or something like that. It's O(2^n).
Now, if you take the input size of your function to be m = lg n, as might be acceptable in this scenario (the number of bits to represent n, the true input size) then this is, in fact, an O(m^4) algorithm... since O(n^2) = O(m^4).

Identify consecutive repetition in two-dimensional array [C]

I have a 2-dimensional array that looks like this:
1 1 0 0 1
1 0 1 1 0
0 0 1 1 0
1 1 0 1 1
0 0 1 1 1
I'm trying to figure out a way to identify the longest contiguous chain of 1's going either across or down. In this case, it starts at column 4, row 2, and its length is 4, going down.
I was thinking of using recursion, but I'm running into some issues keeping track of position, especially when encountering a 0.
So far, I have something along the lines of this (for checking across only):
main() {
...
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
if (G[i][j] == 1) {
CheckAcross(i, j, n);
}
...
}
void CheckAcross (int i, int j, int n) {
if (i < 0 || i >= n || j < 0 || j >= n) return; // outside of grid
if (G[i][j] == 0 ) return; //0 encountered
G[i][j] = WordCount + 1;
CheckAcross(i, j + 1, n);
}
where G[][] is the 2-dimensional array containing the 1's and 0's, n is the number of rows/columns, i is the row number and j is the column number.
Thanks for any assistance in advance!
Your current answer will take O(n3) time; to evaluate a single line, you check every possible start and end position (O(n) possibilities for each), and there are n lines.
Your algorithm is correct, but let's see if we can improve on the running time.
The problem might become simpler if we break it into simpler problems, i.e. "What is the longest contiguous chain of 1s in this 1-dimensional array?". If we solve it 2n times, then we have our answer, so we just need to get this one down to smaller than O(n2) for an improvement.
Well, we can simply go through the line, remembering the position (start and end) and length of the longest sequence of 1s. This takes O(n) time, and is optimal (if the sequence is all 1s or 0s, we would have to read every element to know where the start/end of the longest sequence is).
Then we can simply solve this for every row and every column, in O(n2) time.
Create a new n-by-n matrix called V. This will store, for each cell, the number of 1s at that cell and immediately above it. This will be O(n^2).
checkAllVertical(int n) {
V = malloc(....) // create V, an n-by-n matrix initialized to zero
for(int r=0; r<n; r++) {
for(int c=0; c<n; c++) {
if(G[r][c]=1) {
if(r==0)
V[r][c] = 1;
else
V[r][c] = 1 + V[r][c];
}
}
}
}
You don't really need to allocate all of V. One row at a time would suffice.

Resources