for loop C work weird? - c

I have a problem with for loop in C.
The purpose of the program is to find prime numbers in known quantity k.
Here is my program:
unsigned int i, k, j;
unsigned long int prime;
int _tmain(int argc, _TCHAR* argv[]) {
printf("How many prime numbers do you want to print out in order? "); scanf_s("%u", &k);
printf("%u fist prime numbers are: ", k);
i = 1;
prime = 2;
while (i <= k)
{
for (j = 2; j <= prime; j++)
{
if (prime % j == 0)
{
if (j == prime && prime != 2)
{
printf("%lu, ", prime);
i++;
}
prime++;
j = 2;
}
}
}
_getch();
return 0;
}
And when I run the program, it returns infinite sequence of numbers. But if I adds "else j++;" like this:
for (j = 2; j <= prime; j++)
{
if (prime % j == 0)
{
if (j == prime && prime != 2)
{
printf("%lu, ", prime);
i++;
}
prime++;
j = 2;
}
else j++;
}
Then the program will work out properly. I think this is kinda weird and can't explain why?
Thanks in advance (and sorry for my bad English).

As I mentioned in comments, the problem was caused by your having no "break" in the for-loop to cause it to return to the outer while loop when you detected a valid divisor.
This was compounded by your poor use of variable names confusing you - your original code appears to be confused about what "j" and "prime" are.
Here I've refactored your code to be cleaner and give a significant performance increase for large prime searches:
#include <stdio.h>
#define FALSE (0)
#define TRUE (!(FALSE))
int main()
{
int numPrimes = 0;
int candidate, divisor;
int isPrime;
printf("How many prime numbers do you want to print out in order? ");
scanf("%u", &numPrimes);
printf("\n%u first prime numbers are:\n", numPrimes);
if (numPrimes > 0) {
printf("2, ");
--numPrimes;
}
// we only need to test odd numbers.
for (candidate = 3; numPrimes > 0; candidate += 2) {
// N / (N/2) + 1 is always < 1, so we only have to test half the values.
// we also only need to test odd divisors
isPrime = TRUE;
for (divisor = 3; divisor <= candidate / 2; ++divisor) {
// it's not prime if testNumber divides in
if (candidate % divisor == 0) {
isPrime = FALSE;
break;
}
}
if (isPrime) {
printf("%lu, ", candidate);
--numPrimes;
}
}
printf("\n");
return 0;
}
Live demo here: http://ideone.com/yrUPBy
Which gladly tells me
How many prime numbers do you want to print out in order?
1000 first prime numbers are:
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31,
37, 41, 43, 47, 53, 59, 61, 67, 71, 73,
79, 83, 89, 97, 101, 103, 107, 109, 113, 127,
...
7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841,
7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919,

Your loop has j <= prime as the end condition, meaning the last value of j will be equal to prime. In that case (prime % j == 0) will always be true.
When you add the extra j++ you're skipping half the values of j which accidentally skips past the problem. The program still isn't working correctly.

When the program prints the prime 3, the variables have the following values:
i = 1
j = 3
prime = 3
Then you increment i and prime, and set j = 2, so it's:
i = 2
j = 2
prime = 4
Now you return to the top of the loop, which does j++:
i = 2
j = 3
prime = 4
Since j <= prime, the loop continues. Since prime % j is not 0, it skips the body of that if, and returns to the top of the loop, which increments j again:
i =2
j = 4
prime = 4
This time prime % j == 0, so it prints prime, even though it's not actually a prime number.
This keeps happening for every value of prime.
When you add j++ to the else clause, it causes j to be incremented twice in the failing case. So it goes from 3 to 5, and never makes it to the case where j == prime and it prints the number. Then j <= prime fails, so the for loop terminates.

Related

Make an array multiply only the columns behind it, going one at a time until the last one and save the answer in c

I'm making a program in C that factors any number using primes and saves these primes, multiplying them you find all the divisors of a number.
But I can't make an array that multiplies the previous columns and saves the results. follow the example
60 / 2
30 / 2
15 / 3
5 / 5
divisors = 2, 2, 3, 5
now i need`add 1 to array array {1, 2, 2, 3, 5}
i need this now start colune 2 {1, 2} 2 * 1 = 2 save.
next colune 3 {1, 2, 2} 2 * 1 = 2 but we already have 2 so don't save it.
continue 2 * 2 = 4 save.
colune 4 {1, 2, 2, 3} 3 * 1 = 3 save, 3 * 2 = 6 save, 3 * 4 = 12 save.
colune 5 {1, 2, 2, 3, 5} 5 * 1 = 5 save, 5* 2 = 10, 5 * 4 = 20 save, 5 * 3= 15 save, 5 * 6 = 30 save, 5 * 12 = 60 save.
now we found all divisors of 60 = 1, 2, 3, 4, 5, 6, 10 ,12 , 15,20, 30, 60.
It is important to mention that I need the program to be like this, I know there are other ways... but I only need this one, I have been unable to complete it for 1 week
video to help https://www.youtube.com/watch?v=p0v5FpONddU&t=1s&ab_channel=MATEM%C3%81TICAFORALLLUISCARLOS
my program so far
#include <stdlib.h>
#include <stdio.h>
int N = 1;
int verificarPrimo(int numero);
int main()
{
int num = 60, i, primo = 1, resultados[N], j = 1;
for (i = 0; i < 60; i++)
{
if (primo == 1)
{
resultados[N - 1] = primo;
i = 2;
primo = i;
}
if (verificarPrimo(i))
{
while (num % i == 0)
{
num = num / i;
resultados[N] = i;
N++;
}
}
}
for (i = 1; i < N; i++)
{
printf("%d \n", resultados[i]);
}
}
int verificarPrimo(int primo)
{
int i;
if (primo <= 1)
return 0;
for (i = 2; i <= primo / 2; i++)
{
if (primo % i == 0)
return 0;
}
return 1;
}
I tried out your code and ran into some issues with how the results were being stored. First off, the results array is being initially defined as an array with a size of "1", and that it not what you probably want.
int num = 60, i, primo = 1, resultados[N], j = 1;
With that in mind and determining the spirit of this project, following is tweaked version of the code to test for one or more values and their factors.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int verificarPrimo(int primo)
{
int sq = sqrt(primo) + 1; /* Usual checking for a prime number is from '2' to the square root of the number being evaluated */
if (primo <= 1)
return 0;
for (int i = 2; i < sq; i++)
{
if (primo % i == 0)
return 0;
}
return 1;
}
int main()
{
int N = 0;
int num = 0, entry = 0, resultados[100]; /* The results array needs to be defined with some value large enough to contain the assorted factors a number might have */
printf("Enter a number to evaluate for factors: "); /* Using a prompt to allow various values to be tested */
scanf("%d", &entry);
num = entry;
if (verificarPrimo(num)) /* Catchall in case the entered number is a prime number */
{
printf("This number is a prime number and has no factors other than one and itself\n");
return 0;
}
resultados[0] = 1; /* Normally the value '1' is implied in a list of factors, so these lines could be omitted */
N = 1;
for (int i = 2; i < entry; i++)
{
if (verificarPrimo(i))
{
while (num % i == 0)
{
num = num / i;
resultados[N] = i;
N++;
}
}
}
printf("Factors for %d\n", entry);
for (int i = 0; i < N; i++)
{
printf("%d ", resultados[i]);
}
printf("\n");
return 0;
}
Some items to point out in this tweaked code.
In the prime number verification function, it is usually customary to set up a for loop in testing for prime numbers to go from the value of "2" to the square root of the number being tested. There usually is no need travel to one half of the number being tested. For that, the #include <math.h> statement was added (FYI, "-lm" would need to be added to link in the math library).
Instead of defining the results array with a value of one element, an arbitrary value of "60" was chosen for the holding the possible number of results when evaluating factors for a given value. Your original code had the potential of storing data past the end of the array and causing a "smashing" error.
The value of "1" is usually left out of the list of factors for a number, but was left in as the initial result value. This might be left out of the completed code.
An additional entry field was added to allow for user entry to be tested to give the code some flexibility in testing numbers.
A test was also added to see if the entered number is itself a prime number, which would only have factors of "1" and itself.
Following is some sample terminal output testing out your original value of "60" along with some other values.
#Dev:~/C_Programs/Console/Factors/bin/Release$ ./Factors
Enter a number to evaluate for factors: 60
Factors for 60
1 2 2 3 5
#Dev:~/C_Programs/Console/Factors/bin/Release$ ./Factors
Enter a number to evaluate for factors: 63
Factors for 63
1 3 3 7
#Dev:~/C_Programs/Console/Factors/bin/Release$ ./Factors
Enter a number to evaluate for factors: 29
This number is a prime number and has no factors other than one and itself
Give that a try to see if it meets the spirit of your project.

How to iterate over numbers in C

I've gotta count how many times a certain digit is repeated in each number in a range. For example, in the numbers between 0 and 20, there is only one occurrence of 1 being repeated twice (11). I originally did this by converting the int to a str and iterating over it, but I would like to be able to solve this in an arithmetic way. Any ideas?
here is a general solution that you can use , your problem didn't contain much information so I assumed that you want to count the number of repeating of each digit in each number.
so what I did is like hashing where the digits in each number will never cross the value 9 , so they are from 0 to 9 so I made that hash table called arr, so what I did is to come to every single digit in number and increment the position of that digit in arr
for example , number 554 will cause arr[5]++; twice and arr[4]++; only once , simple idea of using hash tables.
and then at the end I iterate over the hash array printing the number of occurrence of each digit in each number.
and here is the code :
#include <stdio.h>
#include <math.h>
int main()
{
int arr[6] = {5555, 12112, 14, -3223, 44, 10001};
int tempArr[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
for (int i = 0; i < 6; i++) {
int temp1 = arr[i];
// get the number of occurrences of each digit in each number
do{
tempArr[(abs(temp1) % 10)]++;
temp1 /= 10;
}while(temp1 != 0);
// loop over the array to know how many times each digit occurred
printf("the number of occurrences in number called %d\n", arr[i]);
for (int j = 0; j < 10; j++) {
if(tempArr[j] > 1)
printf("number %d occurred %d times\n", j, tempArr[j]);
// resetting that position of the array
tempArr[j] = 0;
}
}
return 0;
}
and here is the output :
the number of occurrences in number called 5555
number 5 occurred 4 times
the number of occurrences in number called 12112
number 1 occurred 3 times
number 2 occurred 2 times
the number of occurrences in number called 14
the number of occurrences in number called -3223
number 2 occurred 2 times
number 3 occurred 2 times
the number of occurrences in number called 44
number 4 occurred 2 times
the number of occurrences in number called 10001
number 0 occurred 3 times
number 1 occurred 2 times
You can divide your number multiple times by 10:
int number = 72;
int rest;
while(number)
{
rest = number % 10;
printf("%d\n", rest);
number /= 10;
}
Here rest contains '2' and then '7'
how many times a certain digit is repeated in each number in a range.
Pseudo code*1
Get the range: imin, imax (any int pair where imin <= imax)
Get the digit: digit 0 to 9
Iterate m from imin to imax, inclusive
.... Print m
.... Set digit_count = 0
.... Repeat
....... Last digit ld of m is abs(m%10).
....... If ld == digit, increment digit_count.
........ Divide m by 10
.... Until m == 0
.... Print digit_count
Done
*1 As OP did not provide code, seemed best to not provide a code answer.
Riffing on the answer provided by #Abdo Salm presented only to demonstrate a slightly alternative approach. All credit to Abdo.
EDIT: Going beyond single, arbitrary numbers to generating ascending contiguous sequence of numbers to be evaluated.
#include <stdio.h>
#include <string.h>
#include <limits.h>
void process( int n, int cnts[] ) {
// count occurences of each digit (right to left)
while( n )
cnts[ abs(n % 10) ]++, n /= 10;
}
void report( int cnts[], int thresh ) {
char *sep = "";
for( int j = 0; j < 10; j++ )
if( cnts[ j ] > thresh )
printf( "%s%dx%d", sep, cnts[ j ], j ), sep = ", ";
if( !*sep )
printf( "no digit occurred multiple times" );
putchar( '\n' );
}
int main() {
#ifndef PROVE
int tests[] = {
0, 11, 121, 5555, 12112, 14,
-3223, 44, 1223334444,
INT_MIN, INT_MAX,
};
// proof of concept: run through multiple arbitrary test values
for( int i = 0; i < sizeof tests/sizeof tests[0]; i++ ) {
// counter for each digit, all init'd to zero
int cnts[ 10 ];
memset( cnts, 0, sizeof cnts );
process( tests[ i ], cnts );
// report only digits appearing multiple times
printf( "%11d: ", tests[ i ] );
report( cnts, 1 );
}
#else // with "ranges" instead of arbitrary test cases
int ranges[][2] = {
{ 0, 10, },
{ 0, 22, },
{ 110, 133, },
{ 447, 448, },
};
for( int r = 0; r < sizeof ranges/sizeof ranges[0]; r++ ) {
int metacnts[10];
memset( metacnts, 0, sizeof metacnts );
for( int i = ranges[r][0]; i <= ranges[r][1]; i++ ) {
int cnts[ 10 ];
memset( cnts, 0, sizeof cnts );
process( i, cnts );
for( int j = 0; j < 10; j++ )
if( cnts[ j ] > 1 )
metacnts[ j ]++;
}
// report only digits appearing multiple times in numbers between min & max
printf( "Range %3d-%3d (incl) ", ranges[r][0], ranges[r][1] );
report( metacnts, 0 );
}
#endif
return 0;
}
/*
Output from arbitrary sequence:
0: no digit occurred multiple times
11: 2x1
121: 2x1
5555: 4x5
12112: 3x1, 2x2
14: no digit occurred multiple times
-3223: 2x2, 2x3
44: 2x4
1223334444: 2x2, 3x3, 4x4
-2147483648: 3x4, 2x8
2147483647: 3x4, 2x7
Output from arbitrary ranges:
Range 0- 10 (incl) no digit occurred multiple times
Range 0- 22 (incl) 1x1, 1x2
Range 110-133 (incl) 12x1, 1x2, 1x3
Range 447-448 (incl) 2x4
*/

program stops responding when I run for loop in C

Logic: I am trying to loop from 3 to 100 and put all prime numbers in that range in an array. I do this by first putting 2 manually into the array. After that, I loop over all the numbers and if a number is not divisible by all the prime numbers I have added to the array, it is a prime. The logic itself is not really valid in my opinion but this is a homework problem and I need to do it the way the professor wants it to be done.
So I try to loop and it gets to a point and the program just crashes. What am I doing wrong here?
int primeNums_lessThan100[25] = {2}; //25 is the size here because there are only 25 prime numbers under 100.
int primeNums_lessThan100_length = 1;
for(int counter = 3 ; counter < 100 ; counter++)
{
printf("Entered here!\n");
for(int array_idx = 0; array_idx < primeNums_lessThan100_length ; array_idx++)
{
if(counter % primeNums_lessThan100[array_idx] != 0)
{
printf("Entered here, TOO!\n");
primeNums_lessThan100[array_idx+1] = counter;
primeNums_lessThan100_length++;
}
else
{
continue;
}
}
}
You have a basic error in your logic. It's not enough to find out the counter value is coprime with some previously found prime to determine counter is prime itself. You need to test it is coprime with all primes found.
Suppose counter == 9 and you test it against the first item of your 'prime' numbers, which is 2. The result of 9 % 2 is of course 1, which is not equal zero and your program adds 9 to the array as a prime number. It happens even earlier for counter == 4 — first you find out it is divisible by 2 and reiterate the loop to find out in the next step 4 % 3 != 0 and add 4 to 'primes'.
As a further result the array overflows (you put more numbers into it than you expected and declared; actually, you put every natural number to it, because each N greater than 2 is not divisible by (N-1)), which means you eventually write past the end of the array, thus triggering an Undefined Behavior.
That displays also a basic error in the design: you do not check your array_idx against the array size, which might allow you to handle the error in some civilized manner.
the following proposed code:
cleanly compiles
performs the desired functionality
comments in code explain what is being done
note use of size_t for numbers that will never be less than 0
Note that all prior prime values are checked against the testPrime
Note that when a prime is found, it is placed in the next available entry in the array: `primeNums[]
and now, the proposed code:
#include <stdio.h> // puts(), printf()
// eliminate ''magic' numbers by giving them meaningful names
//25 is the size here because there are only 25 prime numbers under 100
#define MAX_PRIMES 25
#define TEST_LIMIT 100
int main( void )
{
// declare prime number array and init to 0
int primeNums[ MAX_PRIMES ] = {0};
// pre-set first prime number
primeNums[0] = 2;
// init number of primes found
size_t primeCount = 1;
// test all values of interest
for( int testPrime = 3 ; testPrime < TEST_LIMIT ; testPrime++ )
{
// init 'prime' indicator, 1 means value is prime
size_t Prime = 1;
for( size_t prime_idx = 0; prime_idx < MAX_PRIMES; prime_idx++ )
{
// check that array of prime values contains a valid prime
if( primeNums[ prime_idx ] )
{
if( testPrime % primeNums[ prime_idx ] == 0 )
{
// indicate not a prime number
Prime = 0;
}
}
else
{ // else, all previously found prime numbers checked
break;
} // end if
} // end for each prime already found
if( Prime )
{ // then test number was prime
// update the array of primes
primeNums[ primeCount ] = testPrime;
// update the count of primes found
primeCount++;
}
}
// display the found primes
for( size_t i = 0; i < primeCount; i++ )
{
printf( "%d, ", primeNums[i] );
}
// assure the data gets displayed on the terminal before the program exits
puts( "" );
}
a run of the proposed code results in:
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,

is a given array a sub sequence of another array

building a code that will check if a group of numbers in s_array[] is a sub-sequence of array[], that means that { 1, 5, 4 } is not a sub-sequence of array, whereas { 1, 4, 5} is one (order matters)
my code will first check if the first element of s_array[] exists in array[], once a common element is found it will proceed to check if the rest of s_array[]'s elements also exist in array[] and in the same order (other elements can be between them)
#include <stdio.h>
void main(){
int s_array[] = { 5, 7, 13 };
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
int i, Bcount, m, counter = 1, j = 4;
//i, Bcount and m are loop counters
//counter will count number of repeated elements
//j is the number of elements in s_array + 1
for( i = 0; i <= 15; i++ ){
if( s_array[0] == array[i] ){ // does the first element exist?
for( Bcount = 1; Bcount < j; Bcount++ ){ //checking the rest
for( m = i; m < 15; m++){
if( s_array[Bcount] == array[m] ){
counter++;
i = m;
break;
}
}
}
}
if( j == counter ){
printf( "B is a sub-sequence of A.\n" );
break;
}
else{
printf( "B is not a sub-sequence of A.\n" );
break;
}
}
}
and honestly I can't see if it is the algorithm or that I did something wrong with the coding
First of all the first loop is wrong as i goes up to 15 and at this index you access array out of bounds (undefined behavior).
Then the loop is quite simple. You only need
one loop i index for array and si for s_array
only increment si if you find the number array[i] at s_array[si]
stop the loop if i covered array, or if si got the number of sub array elements (3)
if si is at least 3, the sub sequence was found
That is
int s_array[] = { 5, 7, 13 };
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
int si,i;
for (si=0,i=0 ; i<15 && si<3 ; i++) {
if (s_array[si] == array[i]) si++;
}
printf ("Sub was %s\n", si<3 ? "not found":"found");
Should J not be equal to 3 and the first fot loop index to 14 (or make it strictly less than 15 rather than less than or equal to)? In your second for loop j may be equal to 3 and s_array[3] is invalid. I would try something like:
Bcount = 0;
counter = 1;
for( i = 0; i <= 14; i++ ){
if( s_array[Bcount] == array[i] ){
counter++;
Bcount++;
if(counter == 3){
printf("Success");
break;
}
}
}
In your example, the problem is that the loop get's terminated by the outer if condition:
if( j == counter ){
printf( "B is a sub-sequence of A.\n" );
break;
}
else{
printf( "B is not a sub-sequence of A.\n" );
break;
}
after the first loop cycle, the program checks this condition and breaks.
This condition should be outside the loop.

Summation of all proper divisors

I have solved a question that says:
Given a natural number n (1 <= n <= 500000), please output the summation of all its proper divisors.
Definition: A proper divisor of a natural number is the divisor that is strictly less than the number.
e.g. number 20 has 5 proper divisors: 1, 2, 4, 5, 10, and the divisor summation is: 1 + 2 + 4 + 5 + 10 = 22.
Input
An integer stating the number of test cases (equal to about 200000), and that many lines follow, each containing one integer between 1 and 500000 inclusive.
Output
One integer each line: the divisor summation of the integer given respectively.
Example
Sample Input:
3
2
10
20
Sample Output:
1
8
22
My code is as follows:
/* #BEGIN_OF_SOURCE_CODE */
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[])
{
int sum = 0,
cases = 0,
i, j, buff;
scanf("%d", &cases); //Number of tests
int *n;
n = (int*) malloc(cases * sizeof(int)); //Defining array for numbers to be tested///////
for (i = 0; i < cases; i++) {
scanf("%d", &n[i]);
}
for (i = 0; i < cases; i++ ) {
buff = n[i] / 2;
if (n[i] == 1) {
sum = -1;
}
if (!(n[i] & 1)) {
for (j = 2; j < buff; j++) {
if (n[i] % j == 0) {
sum += n[i] / j + j;
buff /= j;
}
}
}
else {
for (j = 3; j < buff; j += 2) {
if (n[i] % j == 0) {
if (n[i] / j == j) { sum += j; break; }
else sum += n[i] / j + j;
}
buff /= j;
}
}
printf("%d\n", ++sum);
sum = 0;
}
return 0;
}
/* #END_OF_SOURCE_CODE */
but it is not fast enough. Any suggestions?
I have updated the code below to terminate sooner. Running it for all integers from 1 to 500,000 takes under half a second on a MacBookPro6,1 (2.66 GHz Intel Core i7), compiled with Apple GCC 4.2.1 with -O3.
It uses the formula for σx(n) in the Properties section of the Wikipedia page for the divisor function. It could be made faster with a list of precalculated primes. (126 are needed to support inputs up to 500,000, and this reduces the time to less than a quarter of a second.) There are also some divisions that can be eliminated, at the expense of cluttering the code slightly.
// Return the least power of a that does not divide x.
static unsigned int LeastPower(unsigned int a, unsigned int x)
{
unsigned int b = a;
while (x % b == 0)
b *= a;
return b;
}
// Return the sum of the proper divisors of x.
static unsigned int SumDivisors(unsigned int x)
{
unsigned int t = x;
unsigned int result = 1;
// Handle two specially.
{
unsigned int p = LeastPower(2, t);
result *= p-1;
t /= p/2;
}
// Handle odd factors.
for (unsigned int i = 3; i*i <= t; i += 2)
{
unsigned int p = LeastPower(i, t);
result *= (p-1) / (i-1);
t /= p/i;
}
// At this point, t must be one or prime.
if (1 < t)
result *= 1+t;
return result - x;
}
You don't have to allocate space. Just do line by line.
For each line, there is an O( n ^ 1/2 ) algorithm.
#include <iostream>
using std::cout; using std::endl; using std::cin;
int main() {
int count, number;
cin >> count;
for (int i = 0; i < count; ++i) {
cin >> number;
int sum = 1;
for ( int j = 2; j * j <= number; ++j ) {
if ( number % j == 0 ) {
sum += j;
sum += number / j;
}
if ( j * j == number ) sum -= j; // recalculate twice
}
cout << sum << endl;
}
}
This is the runtime for 200,000 test case
real 0m55.420s
user 0m0.016s
sys 0m16.124s
I would start by NOT storing the numbers in an array at all. You don't need to - just read the value, process it, and output the result. The compiler may well not realize that n[i] is the same value throughout the loop, and that nothing else modifies it.
The logic doesn't seem very clear to me. And if (n[i] == 1) { sum = 1} else ... would make more sense than setting sum = -1.
You could perhaps also, keep a list of "common factors" (http://en.wikipedia.org/wiki/Memoization), so that you don't have to recalculate the same thing many times over. [If you know that somehing has the factor 24, then it also has 2, 3, 4, 6 and 8, for example.
I replied to a similar question on stackoverflow
There is a faster performing algorithm which is based on a formula for the sum of divisor using the decomposition in prime factors.
First you construct a primetable such that the last prime squared is smaller than the upper bound for your number. Then you apply the formula to each entry. If a number is written as
n = a1^p1 * a1^p2 *... *an^pn
the complexity of finding the sum for a given number n will be
p1+p2+...+pn = roughtly log(n)
which is better than the complexity O(sqrt(n)) of the first optimization which stop the loop early
Let's suppose you have a way to compute primes relatively quickly. This could be a one time upfront activity, bounded by the square root of the largest input value. In this case, you already know the bound of the largest input value (500000), so you can simply hard code a table of primes into the program.
static unsigned P[] = {
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317,
331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503,
509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607,
613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701
};
static int P_COUNT = sizeof(P)/sizeof(*P);
Now, from the primes, for each input value, you can:
Compute the prime factorization
Compute the product of the sums of the powers of each prime factor.
This will result in the sum of the divisors. Subtract the input value from the sum to obtain the sum of proper divisors. These two steps can be combined into a single loop.
This algorithm works because multiplying polynomials naturally results in sums of all combinations of the polynomial terms multiplied together. In the case where each polynomial term consists of powers of primes that divide the input, the combinations of the terms multiplied together make up the divisors. The algorithm is fast, and should be able to process 500000 numbers in the interval [1, 500000] in less than a second on a Core i3 or better processor.
The following function implements the method described above.
unsigned compute (unsigned n) {
unsigned sum = 1;
unsigned x = n;
for (int i = 0; i < P_COUNT; ++i) {
if (P[i] > x / P[i]) break; /* remaining primes won't divide x */
if (x % P[i] == 0) { /* P[i] is a divisor of n */
unsigned sub = P[i] + 1; /* add in power of P[i] */
x /= P[i]; /* reduce x by P[i] */
while (x % P[i] == 0) { /* while P[i] still divides x */
x /= P[i]; /* reduce x */
sub = sub * P[i] + 1; /* add by another power of P[i] */
}
sum *= sub; /* product of sums */
}
}
if (x > 1) sum *= x + 1; /* if x > 1, then x is prime */
return sum - n;
}
The complexity of this code in O(n * log(n)). But you can output the required answer with constant time.
int ans[500000 + 10], m = 500000;
int f(){
for(int i = 1; i <= m; i++){
for(int j = i + i; j <= m; j += i){
ans[j] += i;
}
}
}
Here ans is an array that contain sum of proper divisor from 2 to m.

Resources