Improve/fix prime factorization function - c

I have a function prime factorization, but it works wierdly and I have no idea how to make it right.
It's expected to print factors through 'x' and write like 2^(power) or 3^(power) if 2's or 3's are reapeating factors.
MyOutput: 2 >> 22^2 | 6 >> 2 x 3^2 | 8 >> 22^22^3 | 9 >> 3 x 3^2.
How do I change this code to make it work properly.
Note: I have stated in main() that if num == 1: print 1.
void prime_factors(int num)
{
int power = 0;
for (int factor = 2; num > 1; ++factor)
{
while (num % factor == 0)
{
if (factor >= 3 && power >= 1)
printf(" x %d", factor);
else
printf("%d", factor);
num /= factor;
++power;
if (power >= 1)
{
printf("^%d", power);
}
}
}
}

There are four problems:
power is not being reset to 0 for each factor
It is printing factor even if power is 0.
It should not print the factor and power until power has been fully determined. (Currently, the code is printing every time power is incremented.
It prints x at the beginning if the first factor is > 2.
Fixed version below:
void prime_factors(int num)
{
int power = 0;
int first = 1;
for (int factor = 2; num > 1; ++factor)
{
power = 0;
while (num % factor == 0)
{
num /= factor;
++power;
}
if (power >= 1)
{
if (first)
printf("%d", factor);
else
printf(" x %d", factor);
printf("^%d", power);
first = 0;
}
}
}
There are various ways to speed it up.
One way to speed it up is to skip factors when they get too large (larger than the square root of num, as suggested by #chux in the comments), leaving num as the only remaining factor. Rather than calculating the square root, a simple division can be used, as shown in the // speed up 1 code section below:
void prime_factors(int num)
{
int power = 0;
int first = 1;
for (int factor = 2; num > 1; ++factor)
{
power = 0;
// speed up 1
if (num / factor < factor)
{
// skip impossible factors
factor = num;
}
// end of speed up 1
while (num % factor == 0)
{
num /= factor;
++power;
}
if (power >= 1)
{
if (first)
printf("%d", factor);
else
printf(" x %d", factor);
printf("^%d", power);
first = 0;
}
}
}
Another way to speed it up is to increment factor by 2 in the for loop most of the time, except when factor is 2, so the sequence will be 2, 3, 5, 7, 9, 11, etc.:
for (int factor = 2; num > 1; factor += 1 + (factor & 1))
The factor += 1 + (factor & 1) increments factor by 1 when factor is even, and increments factor by 2 when factor is odd, so the only even value of factor will be the initial value 2.

Related

Attempting to run Luhn's Algorithm in C

So, I'm trying to make Luhn's algorithm in C, but it doesn't return the correct values when running it.
//Luhn's Algorithm
int tsum = 0;
if (count % 2 != 0)
{
for (int tempcount = count; tempcount > 0; tempcount--)
{
if (tempcount % 2 != 0)
{
tsum += (cardNum % 10);
}
else
{
tsum += (cardNum % 10)*2;
}
cardNum /= 10;
}
}
else
if (count % 2 == 0)
{
for (int tempcount = count; tempcount > 0; tempcount--)
{
if (tempcount % 2 == 0)
{
tsum += (cardNum % 10);
}
else
{
tsum += (cardNum % 10)*2;
}
cardNum /= 10;
}
}
tsum %= 10;
I have spent hours trying to troubleshoot and find the issue, count represents the number of digits in the card number, the rest define themselves.
I would appreciate somebody to tell me what I'm doing wrong, thank you.
EDIT: Apologies, cardNum is a long long. And I am expecitng a value of 0 for tsum when inputting any card number from Paypal's Standard Test Cards. I would also like to add, in my mind what this code should do is: using the checks for even and odd it will start from the rightmost digit and add it to tsum, every other digit will do the same. Then starting from the 2nd rightmost digit, the digit is multiplied by 2 then added to tsum, with every other digit doing the same. Then, the last line will check the rightmost digit of the current tsum and will tell me if the card is valid according to Luhn's Algorithm.
Here is what I usually do if I "try to implement" something I am not sure about: I use an interactive language, such as Common Lisp, tinker and test interactively until it works. Then, I usually have some good template I can use to write it in a less powerful language such as C.
(defun luhn-method (n)
(mod
(loop
for x = n then (floor x 10)
while (> x 0)
for double = nil then (not double)
for digit = (mod x 10)
for factor = (if double 2 1)
for y = (let ((a (* digit factor)))
(if (> a 9) (- a 9) a))
do (format t "~%~a" (list :x x :double double :digit digit :factor factor :y y))
summing y)
10))
I did this just from reading the wikipedia page about Luhn method (the german wiki page is easier to understand because it shows a simple exampple, while being less verbose than the english version).
From your Paypal site, the first number produces
(luhn-method 378282246310005)
(X 378282246310005 DOUBLE NIL DIGIT 5 FACTOR 1 Y 5)
(X 37828224631000 DOUBLE T DIGIT 0 FACTOR 2 Y 0)
(X 3782822463100 DOUBLE NIL DIGIT 0 FACTOR 1 Y 0)
(X 378282246310 DOUBLE T DIGIT 0 FACTOR 2 Y 0)
(X 37828224631 DOUBLE NIL DIGIT 1 FACTOR 1 Y 1)
(X 3782822463 DOUBLE T DIGIT 3 FACTOR 2 Y 6)
(X 378282246 DOUBLE NIL DIGIT 6 FACTOR 1 Y 6)
(X 37828224 DOUBLE T DIGIT 4 FACTOR 2 Y 8)
(X 3782822 DOUBLE NIL DIGIT 2 FACTOR 1 Y 2)
(X 378282 DOUBLE T DIGIT 2 FACTOR 2 Y 4)
(X 37828 DOUBLE NIL DIGIT 8 FACTOR 1 Y 8)
(X 3782 DOUBLE T DIGIT 2 FACTOR 2 Y 4)
(X 378 DOUBLE NIL DIGIT 8 FACTOR 1 Y 8)
(X 37 DOUBLE T DIGIT 7 FACTOR 2 Y 5)
(X 3 DOUBLE NIL DIGIT 3 FACTOR 1 Y 3)
0
making it easy to see every single step of the algorithm and convincing yourself it is correct.
To port this to C, first we need to explore, if C has an integer type wide enough for those credit card numbers (lisp has large integers by default - one thing less to worry about in our prototype). Lisp again:
(log 378282246310005 2)
48.426456
So, we need a 64 bit variable and should be good.
Since integers in C are implementation/platform/system specific, we should use some header file, giving us the correct type:
#include <stdint.h>
In there, the 64 bit unsigned integer is defined as uint64_t and if your compiler and your header files are correct for your system, using that makes sure, you do not get it wrong. The native "unsigned long long" etc. are just guesswork and not portable.
With that in place, we can simply port the code above to C:
uint64_t luhn(uint64_t n) {
uint64_t x = n;
uint64_t sum = 0;
uint64_t factor = 1;
while (x > 0) {
uint64_t y = (x % 10) * factor;
if (y > 9)
y = y - 9;
sum += y;
x = x / 10;
if (1 == factor) {
factor = 2;
} else {
factor = 1;
}
}
return sum % 10;
}
Summary:
A proper tool set helps getting stuff done. If you don't know yet, how to use a C debugger and step through code line by line while watching the content of variables, an interactive programming language is probably easier for you for prototyping.
Thank you for your help, I was able to solve this issue as it seems I had missed a step in Luhn's Algorithm.
//Luhn's Algorithm
int tsum = 0;
int luhn;
if (count % 2 != 0)
{
for (int tempcount = count; tempcount > 0; tempcount--)
{
if (tempcount % 2 != 0)
{
luhn = (cardNum % 10);
tsum += luhn;
}
else
{
luhn = (cardNum % 10) * 2;
if (luhn > 9)
{
tsum += (luhn - 9);
}
else
{
tsum += luhn;
}
}
cardNum /= 10;
}
}
else if (count % 2 == 0)
{
for (int tempcount = count; tempcount > 0; tempcount--)
{
if (tempcount % 2 == 0)
{
luhn = (cardNum % 10);
tsum += luhn;
}
else
{
luhn = (cardNum % 10) * 2;
if (luhn > 9)
{
tsum += (luhn - 9);
}
else
{
tsum += luhn;
}
}
cardNum /= 10;
}
}
tsum %= 10;
Here, I defined luhn as the next integer to be added to the tsum, in doing this I was able to fill in the missing step by subtracting 9 before adding to tsum if luhn exceeded 9.

Trying to implement Luhn's Algorithm in C

Iam trying to implement Luhn's algorithm in the C language to check credit card validity, for those who don't know... this is it:
Multiply every other digit by 2, starting with the number’s
second-to-last digit, and then add those products’ digits together.
Add the sum to the sum of the digits that weren’t multiplied by 2.
If the total’s last digit is 0 (or, put more formally, if the total
modulo 10 is congruent to 0), the number is valid!
and to implement that, I looped through the whole number and if the number place I was in had a modulo 2 equal to 0 then I would multiply by two and add to a variable called totalEven.
if that wasn't the case I would add the number I was in to totalOdd without multiplication.
I would then increment the place by one and check the other numbers until I reach 16 (the max digits for a card).
I would later add both variables and check if the total modulo ten was equal to 0. If it means the credit card number is correct, else it is false.
here is the code:
#include <stdio.h>
#include <cs50.h>
//list of variables
//is the card valid
bool isValid = true;
// the creditcard number
long input;
//mod stands for modules, and is used to single out each number as seen later
int mod = 10;
//the location at which number I am checking
int place = 1;
//num is the number I am checking that has been singled out
int num = 0;
//total of numbers * 2 located at locations numbered with even numbers
int totalEven = 0;
//total of numbers located at locations numbered with odd numbers
int totalOdd = 0;
//gets input and stores it in well.. input
input = get_long("Number: ");
// a formula to single out a number, starting with the ones and then as you can see, mod is muliplied by 10 to go over the second number.
num = ((input % mod) - (input % (mod /10))) / (mod/10);
//loops 16 times
for(int i = 0; i < 16; i++)
{
// if the place is even execute below
if(place % 2 == 0)
{
totalEven = totalEven + num * 2;
}
//else do this
else if (place % 2 != 0)
{
totalOdd = totalOdd + num;
}
//moves to the next number
mod = mod * 10;
place++;
}
//fufils the last step of the algorithm
if((totalEven + totalOdd) % 10 == 0 )
{
isValid = true;
}
else
{
isValid = false;
}
problem is that this block of code gives me invalid or !isValid even though the credit card number is supposed to be correct and I checked my "formula" and it works just fine...
I have absolutely no idea what to do... I am a humble hobbyist so plz don't roast me for the monstrosity above.
here is a complete version of the code
#include <stdio.h>
#include <cs50.h>
long power();
int main(void)
{
//AMERX 15 STRT 34 OR 37
//MC 16 STRT 51, 52, 53, 54, 55
//VZA 13 OR 16 STRT 4
long input;
bool isValid = true;
string type;
int mod = 10;
int place = 1;
int num = 0;
int totalEven = 0;
int totalOdd = 0;
do
{
input = get_long("Number: ");
}
while(input < 0);
for(int i = 0; i < 16; i++)
{
num = ((input % mod) - (input % (mod /10))) / (mod/10);
if(place % 2 == 0)
{
totalEven = totalEven + num * 2;
}
else
{
totalOdd = totalOdd + num;
}
mod = mod * 10;
place++;
}
if((totalEven + totalOdd) % 10 == 0 )
{
isValid = true;
}
else
{
isValid = false;
printf("%i , %i", totalEven, totalOdd);
}
if (isValid == true){
if((input < (38 * power(10, 13)) && input >=(37 * power(10, 13))) || (input < (35 * power(10,13)) && input >= (34 * power(10, 13))))
{
type = "AMEX\n";
}
else if(input >= (51 * power(10, 14)) && input < (56 * power(10, 14)))
{
type = "MASTERCARD\n";
}
else if((input < (5 * power(10, 12)) && input >= (4 * power(10, 12))) || (input < (5 * power(10, 15)) && input >= (4 * power(10, 15))))
{
type = "VISA\n";
}
else{
type = "error\n";
}
}
else
{
type = "INVALID\n";
}
if((totalEven + totalOdd) % 10 == 0 )
{
isValid = true;
}
else
{
isValid = false;
}
printf("%s", type);
}
long power(int n, int p)
{
long result = 1;
for(int i = 0; i<p; i++)
{
result = result * n;
}
return result;
I'm not an expert in Luhn algorithm but when I read https://en.wikipedia.org/wiki/Luhn_algorithm it seems to me that you are doing it wrong.
Quote from https://en.wikipedia.org/wiki/Luhn_algorithm :
From the rightmost digit (excluding the check digit) and moving left, double the value of every second digit. The check digit is neither doubled nor included in this calculation; the first digit doubled is the digit located immediately left of the check digit. If the result of this doubling operation is greater than 9 (e.g., 8 × 2 = 16), then add the digits of the result (e.g., 16: 1 + 6 = 7, 18: 1 + 8 = 9) or, alternatively, the same final result can be found by subtracting 9 from that result (e.g., 16: 16 − 9 = 7, 18: 18 − 9 = 9).
I don't see anywhere in your code where you handle that bolded part.
Instead of
totalEven = totalEven + num * 2;
I think you need
int tmp = num * 2;
if (tmp > 9) tmp = tmp - 9;
totalEven = totalEven + tmp;
That said - I think you are making the implementation much more complex than needed by storing the input as a number. Instead of a number you could use an array of digits.
That is - instead of
long input = 1122334455667788
use
int digits[] = {8, 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1};
// Notice that index zero is the rightmost digit
In this way the algorithm is much more simple:
// Double every second element and check for overflow
for (idx = 1; idx < 16; idx += 2)
{
digits[idx] = 2 * digits[idx];
if (digits[idx] > 9) digits[idx] = digits[idx] - 9;
}
// Calculate the sum
sum = 0;
for (idx = 0; idx < 16; ++idx)
{
sum = sum + digits[idx];
}
If you must receive the input as a number, start by calling a function that converts the number to an array of digits. You can find many, many examples of how that conversion is done here on SO. Here Converting integer into array of digits is just one of many examples.
As I was looking at your code, there some mistakes I want to point out.
You forgot: #include <string.h> as you did declare string type in the code.
input = get_long("Number: "); should have its own do-while loop in case user inputs letters or incorrect numbers.
if(place % 2 == 0){
totalEven = totalEven + num * 2;
}
else if (place % 2 != 0){
totalEven = totalEven + num;
} should totalOdd = totalOdd + num for the second part
totalEven = totalEven + num * 2 is right and wrong at the same time. It only works if the number multiplied by 2 is less than 10. If the num * 2 >= 10, lets say num = 6, then 6 * 2 is 12 which would then be 1 + 2 + totalEven.
num = ((input % mod) - (input % (mod /10))) / (mod/10); This should be in the first for loop.
In #include <math.h>, there is a power function called pow which does exactly as your power() function.
Caution: I have made use of CS50X Library as the question seems to be the one from the same.
#include <stdio.h>
#include <cs50.h>
// Luhn's Algorithm
int main(void)
{
long cardNumber = get_long("Please, enter your card number: ");
int sum1 = 0, num = 0, remainder = 0, sum2 = 0;
long temp = cardNumber;
while (temp > 0)
{
num = ((temp / 10) % 10) * 2; // Multiplying every other digit by 2, starting with the number’s second-to-last digit
while (num > 0)
{
remainder = num % 10;
sum1 += remainder; // Adding those products’ digits together
num /= 10;
}
temp /= 100;
}
// So as to restore the initial values of remainder and temp for the use in next loop
remainder = 0;
temp = cardNumber;
while (temp > 0)
{
remainder = temp % 10;
sum2 += remainder; // Sum of the digits that weren’t multiplied by 2
temp /= 100;
}
((sum1 + sum2) % 10) == 0 ? printf("Valid\n") : printf("Invalid\n");
return 0;
}

Trailing zeroes in a Factorial

I am trying to write a code for calculating the number of trailing zeroes in a factorial of a specific number (large numbers). However, for small numbers, i get the correct result, but for large the deviations keeps increasing. What's wrong with my logic
#include <stdio.h>
int main(void) {
int t;
scanf("%d", &t);
while (t > 0) {
int factorten = 0, factorfive = 0, factortwo = 0, remainingfive = 0,
remainingtwo = 0;
unsigned int factors = 0;
unsigned int n;
scanf("%u", &n);
for (unsigned int i = n; i > 0; i--) {
if (i % 10 == 0) {
factorten++;
continue;
} else if (i % 5 == 0) {
factorfive++;
continue;
} else if (i % 2 == 0) {
// int new = i;
// while(new % 2 == 0)
//{
// new = new / 2;
factortwo++;
//}
continue;
}
}
factors = factors + factorten;
printf("%u\n", factors);
if (factorfive % 2 == 0 && factorfive != 0) {
factors = factors + (factorfive / 2);
} else {
remainingfive = factorfive % 2;
factors = factors + ((factorfive - remainingfive) / 2);
}
printf("%u\n", factors);
if (factortwo % 5 == 0 && factortwo != 0) {
factors = factors + (factortwo / 5);
} else {
remainingtwo = factortwo % 5;
factors = factors + ((factortwo - remainingtwo) / 5);
}
printf("%u\n", factors);
if ((remainingfive * remainingtwo % 10) == 0 &&
(remainingfive * remainingtwo % 10) != 0) {
factors++;
}
printf("%u\n", factors);
t--;
}
}
Sample Input:
6
3
60
100
1024
23456
8735373
Sample Output:
0
14
24
253
5861
2183837
My OUTPUT
0
13
23
235
5394
2009134
Edit: ignore the first two, they are suboptimal. The third algorithm is optimal.
I think this does what you're trying to do, but is a lot simpler and works:
int tzif(int n)
{
int f2 = 0, f5 = 0;
for (;n > 1; n--)
{
int x = n;
for (;x % 2 == 0; x /= 2)
f2++;
for (;x % 5 == 0; x /= 5)
f5++;
}
return f2 > f5 ? f5 : f2;
}
It counts 2-factors and 5-factors of numbers N...2. Then it returns the smaller of the two (because adding 2-factors is useless without adding 5-factors and vice-versa). Your code is too strange for me to analyze.
I think this should work too, because a factorial will have enough 2-factors to "cover" the 5-factors:
int tzif(int n)
{
int f5 = 0;
for (;n > 1; n--)
for (x = n;x % 5 == 0; x /= 5)
f5++;
return f5;
}
This only counts 5-factors and returns that.
Another method I think should work:
int tzif(int n)
{
int f5 = 0;
for (int d = 5; d <= n; d *= 5)
f5 += n / d;
return f5;
}
Count every fifth number (each has a 5-factor), then every 25-th number (each has another 5-factor), etc.
Have 3 counters - c2,c5,c10.
I think the checks should be
divisible by 5 but not by 10 -> c5++
divisible by 2 but not by 10 -> c2++
divisible by 10. Here if true, then count number of 0's. (c10++)
At last number of 0's will be
smaller_of(c2,c5) + c10
Try to code using this. Should work.
First the trailing 0 in N! are determined by factors 2 and 5 (10). The factors 2 always would be more that the factors 5 in this case you only need to calculate how factors 5 are in the N!.
(N!/5) would give you the number of multiple of 5 (5^1) in N!
(N!/25) would give you the number of multiple of 25 (5^2) in N!
(N!/125) would give you the number of multiple of 125 (5^3) in N!
...
(N!/5^n) would give you the number of multiple of 5^n in N!
When you add the multiple of 5 you are adding too the multiple of 25, 125, ..., 5^n, when you add multiple of 25 you are adding too the multiple of 125, ..., 5^n, etc...
In that case you only need to iterate the power of 5 less or equal than N and add the number of multiple of that 5 power.
Code:
long long trailing_zeros(long long N) {
long long zeros = 0;
for (long long power5 = 5; power5 <= N; power5 *= 5)
zeros += N / power5;
return zeros;
}
#include<iostream>
int main()
{
int size,i;
std::cin >> size;
int*fact;
fact = new int[size];
for (i = 0; i < size; i++)
{
std::cin >> fact[size];
}
for (i = 0; i < size; i++)
{
int con = 5;
int multiple = 0;
do
{
multiple = multiple+(fact[size] / con);
con = con * 5;
} while (con < fact[size]);
std::cout << multiple <<'\n';
}
return 0;
}
this code works perfectly for a single input..bt for multiple inputs it prints the o/p for the last entered number...what is wrong..i jst cant think off it

Finding largest prime factor of a composite number in c

I am accepting a composite number as an input. I want to print all its factors and also the largest prime factor of that number. I have written the following code. It is working perfectly ok till the number 51. But if any number greater than 51 is inputted, wrong output is shown. how can I correct my code?
#include<stdio.h>
void main()
{
int i, j, b=2, c;
printf("\nEnter a composite number: ");
scanf("%d", &c);
printf("Factors: ");
for(i=1; i<=c/2; i++)
{
if(c%i==0)
{
printf("%d ", i);
for(j=1; j<=i; j++)
{
if(i%j > 0)
{
b = i;
}
if(b%3==0)
b = 3;
else if(b%2==0)
b = 2;
else if(b%5==0)
b = 5;
}
}
}
printf("%d\nLargest prime factor: %d\n", c, b);
}
This is a bit of a spoiler, so if you want to solve this yourself, don't read this yet :). I'll try to provide hints in order of succession, so you can read each hint in order, and if you need more hints, move to the next hint, etc.
Hint #1:
If divisor is a divisor of n, then n / divisor is also a divisor of n. For example, 100 / 2 = 50 with remainder 0, so 2 is a divisor of 100. But this also means that 50 is a divisor of 100.
Hint #2
Given Hint #1, what this means is that we can loop from i = 2 to i*i <= n when checking for prime factors. For example, if we are checking the number 100, then we only have to loop to 10 (10*10 is <= 100) because by using hint #1, we will get all the factors. That is:
100 / 2 = 50, so 2 and 50 are factors
100 / 5 = 20, so 5 and 20 are factors
100 / 10 = 10, so 10 is a factor
Hint #3
Since we only care about prime factors for n, it's sufficient to just find the first factor of n, call it divisor, and then we can recursively find the other factors for n / divisor. We can use a sieve approach and mark off the factors as we find them.
Hint #4
Sample solution in C:
bool factors[100000];
void getprimefactors(int n) {
// 0 and 1 are not prime
if (n == 0 || n == 1) return;
// find smallest number >= 2 that is a divisor of n (it will be a prime number)
int divisor = 0;
for(int i = 2; i*i <= n; ++i) {
if (n % i == 0) {
divisor = i;
break;
}
}
if (divisor == 0) {
// we didn't find a divisor, so n is prime
factors[n] = true;
return;
}
// we found a divisor
factors[divisor] = true;
getprimefactors(n / divisor);
}
int main() {
memset(factors,false,sizeof factors);
int f = 1234;
getprimefactors(f);
int largest;
printf("prime factors for %d:\n",f);
for(int i = 2; i <= f/2; ++i) {
if (factors[i]) {
printf("%d\n",i);
largest = i;
}
}
printf("largest prime factor is %d\n",largest);
return 0;
}
Output:
---------- Capture Output ----------
> "c:\windows\system32\cmd.exe" /c c:\temp\temp.exe
prime factors for 1234:
2
617
largest prime factor is 617
> Terminated with exit code 0.
I presume you're doing this to learn, so I hope you don't mind a hint.
I'd start by stepping through your algorithm on a number that fails. Does this show you where the error is?
You need to recode so that your code finds all the prime numbers of a given number, instead of just calculating for the prime numbers 2,3, and 5. In other words, your code can only work with the number you are calculating is a prime number or is a multiple of 2, 3, or 5. But 7, 11, 13, 17, 19 are also prime numbers--so your code should simply work by finding all factors of a particular number and return the largest factor that is not further divisible.
Really, this is very slow for all but the smallest numbers (below, say, 100,000). Try finding just the prime factors of the number:
#include <cmath>
void addfactor(int n) {
printf ("%d\n", n);
}
int main()
{
int d;
int s;
int c = 1234567;
while (!(c&1)) {
addfactor(2);
c >>= 1;
}
while (c%3 == 0) {
addfactor(3);
c /= 3;
}
s = (int)sqrt(c + 0.5);
for (d = 5; d <= s;) {
while (c % d == 0) {
addfactor(d);
c /= d;
s = (int)sqrt(c + 0.5);
}
d += 2;
while (c % d == 0) {
addfactor(d);
c /= d;
s = (int)sqrt(c + 0.5);
}
d += 4;
}
if (c > 1)
addfactor(c);
return 0;
}
where addfactor is some kind of macro that adds the factor to a list of prime factors. Once you have these, you can construct a list of all the factors of the number.
This is dramatically faster than the other code snippets posted here. For a random input like 10597959011, my code would take something like 2000 bit operations plus 1000 more to re-constitute the divisors, while the others would take billions of operations. It's the difference between 'instant' and a minute in that case.
Simplification to dcp's answer(in an iterative way):
#include <stdio.h>
void factorize_and_print(unsigned long number) {
unsigned long factor;
for(factor = 2; number > 1; factor++) {
while(number % factor == 0) {
number = number / factor;
printf("%lu\n",factor);
}
}
}
/* example main */
int main(int argc,char** argv) {
if(argc >= 2) {
long number = atol(argv[1]);
factorize_and_print(number);
} else {
printf("Usage: %s <number>%<number> is unsigned long", argv[0]);
}
}
Note: There is a number parsing bug here that is not getting the number in argv correctly.

Algorithm to find the factors of a given Number.. Shortest Method?

What could be the simplest and time efficient logic to find out the factors of a given Number.
Is there any algorithm that exist, based on the same.
Actually, my real problem is to find out the no. of factors that exist for a given Number..
So Any algorithm, please let me know on this..
Thanks.
Actually, my real problem is to find out the no. of factors that exist for a given Number..
Well, this is different. Let n be the given number.
If n = p1^e1 * p2^e2 * ... * pk^ek, where each p is a prime number, then the number of factors of n is (e1 + 1)*(e2 + 1)* ... *(ek + 1). More on this here.
Therefore, it is enough to find the powers at which each prime factor appears. For example:
read given number in n
initial_n = n
num_factors = 1;
for (i = 2; i * i <= initial_n; ++i) // for each number i up until the square root of the given number
{
power = 0; // suppose the power i appears at is 0
while (n % i == 0) // while we can divide n by i
{
n = n / i // divide it, thus ensuring we'll only check prime factors
++power // increase the power i appears at
}
num_factors = num_factors * (power + 1) // apply the formula
}
if (n > 1) // will happen for example for 14 = 2 * 7
{
num_factors = num_factors * 2 // n is prime, and its power can only be 1, so multiply the number of factors by 2
}
For example, take 18. 18 = 2^1 * 3*2 => number of factors = (1 + 1)*(2 + 1) = 6. Indeed, the 6 factors of 18 are 1, 2, 3, 6, 9, 18.
Here's a little benchmark between my method and the method described and posted by #Maciej. His has the advantage of being easier to implement, while mine has the advantage of being faster if change to only iterate over the prime numbers, as I have done for this test:
class Program
{
static private List<int> primes = new List<int>();
private static void Sieve()
{
bool[] ok = new bool[2000];
for (int i = 2; i < 2000; ++i) // primes up to 2000 (only need up to sqrt of 1 000 000 actually)
{
if (!ok[i])
{
primes.Add(i);
for (int j = i; j < 2000; j += i)
ok[j] = true;
}
}
}
private static int IVlad(int n)
{
int initial_n = n;
int factors = 1;
for (int i = 0; primes[i] * primes[i] <= n; ++i)
{
int power = 0;
while (initial_n % primes[i] == 0)
{
initial_n /= primes[i];
++power;
}
factors *= power + 1;
}
if (initial_n > 1)
{
factors *= 2;
}
return factors;
}
private static int Maciej(int n)
{
int factors = 1;
int i = 2;
for (; i * i < n; ++i)
{
if (n % i == 0)
{
++factors;
}
}
factors *= 2;
if (i * i == n)
{
++factors;
}
return factors;
}
static void Main()
{
Sieve();
Console.WriteLine("Testing equivalence...");
for (int i = 2; i < 1000000; ++i)
{
if (Maciej(i) != IVlad(i))
{
Console.WriteLine("Failed!");
Environment.Exit(1);
}
}
Console.WriteLine("Equivalence confirmed!");
Console.WriteLine("Timing IVlad...");
Stopwatch t = new Stopwatch();
t.Start();
for (int i = 2; i < 1000000; ++i)
{
IVlad(i);
}
Console.WriteLine("Total milliseconds: {0}", t.ElapsedMilliseconds);
Console.WriteLine("Timing Maciej...");
t.Reset();
t.Start();
for (int i = 2; i < 1000000; ++i)
{
Maciej(i);
}
Console.WriteLine("Total milliseconds: {0}", t.ElapsedMilliseconds);
}
}
Results on my machine:
Testing equivalence...
Equivalence confirmed!
Timing IVlad...
Total milliseconds: 2448
Timing Maciej...
Total milliseconds: 3951
Press any key to continue . . .
There is a large number of algorithms available - from simple trial devision to very sophisticated algorithms for large numbers. Have a look at Integer Factorization on Wikipedia and pick one that suits your needs.
Here is a short but inefficient C# implementation that finds the number of prime factors. If you need the number of factors (not prime factors) you have to store the prime factors with their multiplicity and calculate the number of factors afterwards.
var number = 3 * 3 * 5 * 7 * 11 * 11;
var numberFactors = 0;
var currentFactor = 2;
while (number > 1)
{
if (number % currentFactor == 0)
{
number /= currentFactor;
numberFactors++;
}
else
{
currentFactor++;
}
}
Here is a fruit of my short discussion with |/|ad :)
read given number in n
int divisorsCount = 1;
int i;
for(i = 2; i * i < n; ++i)
{
if(n % i == 0)
{
++divisorsCount;
}
}
divisorsCount *= 2;
if(i * i == n)
{
++divisorsCount;
}
Careful, this answer is not useful/fast for a single value of n.
Method 1:
You can get it in O(polylog(n)) if you maintain a look-up table (for the first prime factor of a number).
If gcd(a,b) == 1, then
no. of factors of a*b = (no. of factors of a) * (no. of factors of b)
Therefore, for a given number a*b, if gcd(a,b) != 1 then we can have two other numbers p and q where p = a and q = b/gcd(a,b). Thus, gcd(p,q) == 1. Now, we can recursively find the number of factors for p and q.
It will take only some small amount of efforts to ensure neither p nor q is 1.
P.S. This method is also useful when you need to know the number of factors of all numbers from 1 to n. It would be an order of O(nlogn + O(look-up table)).
Method 2: (I do not have ownership for this.)
If you have the look-up for first prime factor till n, then you can know it's all prime factors in O(logn) and thus find the number of factors from them.
P.S. Google 'Factorization in logn' for better explanation.
Euclid's Algorithm should suffice.

Resources