In each part you are asked to modify the program from the previous part. In doing so, make a new file containing the new program. You may want to name the programs part0, part1, etc. Save the programs for each part, as you may need to run them again.
Each program should start by outputting which part of the assignment this is, your name and the number that you are trying to factor. It should then list all of the prime factors, one per line. The output the number again along with the product of the factors you have found. Do this in such a way that it is easy to tell that these two numbers agree. Make sure you also include the appropriate words along with your output so you can tell what the numbers mean. Sample output might look like this:
part1 written by S. Robbins Trying to factor 63269392157957 Number of prime factors is 2: 2712161 23328037 The prime factors of 63269392157957 multiply to 63269392157957Notice how the last two numbers of the output appear one below the other so it is clear that they have the same value.
At the end of the assignment, the requirements for turning in your program are described. Run all of the tests on the same machine, if possible.
Basic algorithm:
Given an integer n, find the factors that are less than sqrt(n)
by trying all possible values. If k is an integer between 2
and sqrt(n),
k is a factor of n if n%k is 0.
For each value of k in this range we test whether n%k is 0. If it is, we have found a factor. We store the factor, replace n by n/k and calculate a new sqrt(n). We then continue looking from where we left off. In doing so, we need to use the same value of k again in case a power of k divides n.
When we are done, we have a list of factors of n. Convince yourself that these must be prime factors. Multiply them together to get m. If m is not equal to n, then n/m is the remaining prime factor of n.
Do not modify the algorithm to make it more efficient. For example, we know that other than 2, prime factors must be odd. Do not use this fact.
Part 0
Write a program that takes one command line parameter, an integer, n,
and determines the prime factors of n using the method described.
Notes:
Part 1
Convert your program to use the data type long long.
This is usually a 64-bit data type.
Very little of your program needs to be changed, except for
replacing int by long long in the appropriate places.
Only use long long where necessary. For example, a counter
for the number of prime factors should still be an int.
You can use atoll to convert the command line string to a
long long.
Make sure saveValue can handle long long values.
Be sure that when you calculate sqrt(n) you round up, rather than
truncating. Some long long may not exactly fit in a double
and so the sqrt function may not give the exact answer when
n is a perfect square.
Try your program with the same values for Part 0, plus some additional larger values below.
Here are some larger values you might want to try:
The ones marked with a * may take a long time to run.
Part 2
Here we will prepare to exploit the use of 2 CPUs. We will break the
problem into two parts and eventually run each part on a different
CPU. For now we will run the two parts sequentially.
Modify Part 1 to use functions, findFactors1 and findFactors2. Each of these takes a number n as a parameter. The first function searches for factors in the first half on the range (2 to sqrt(n)/2) and the second one searches the second half of the range. Each of these should use the data type long long. If findFactors1 finds a factor, adjust the value of its n and its range, accordingly. Call findFactors1 followed by findFactors2. findFactors2 should use the original value of n.
Note: When findFactors1 finds a factor, it should adjust its maximum value to sqrt(n) rather than sqrt(n)/2. Why?
Note:There are cases in which findFactors2 will find factors that are not prime. Do not worry about this for now. It will be fixed in Part 3.
Part 3
When you ran the program from Part 2, you might have noticed that:
Part 4
We want to run findFactors1 and findFactors2 concurrently.
Fork a child. Have the parent run findFactors1 and have the child run
findFactors2. If the child finds a factor (it can find at most 1)
it must communicate that factor back to the parent. Note that this will
not fit in 8 bits, so the return value cannot be used. One way is to
use a pipe. Implement this.
If findFactors1 finds a factor, then the child cannot. Kill the child if findFactors1 finds a factor. This should speed up execution on a single-CPU machine.
Part 4 can run up to twice as fast as Part 3 if you have 2 CPUs. Run Parts 3 and 4 for some of the cases that take a long time and see how the running times compare. Most of the machines we have in the lab will only run one CPU. If you have access to a dual-core Linux machine, run some tests and determine under which circumstances Part 4 runs much faster than Part 3.
Part 5
We can speed this up even more in some cases.
When findFactors1 in Part 4 finds a factor and kills the child,
it has reduced the problem to a smaller size.
Have it handle only half of what is left and create a child to handle
the other half.
Handing in your assignment
You will hand in the source code for each of the 5 parts of the assignment.
In addition, you will run specific tests for each part. You will time each
test using the time command. Make sure the time command you are
using displays the user time, the system time and the elapsed time.
Run the following tests for each part:
For Part 0, run tests 1, 4, 8, 10 and 14. Include timing information
for each, but these should all run very quickly.
For each of the remaining parts, run the following test cases from the list under the Part 1 discussion: 9, 10, 17, 18, 19. Include timing information for each. Which of these tests run slower under Part 2 than Part 1? Did Part 3 solve this problem?
Use this cover sheet.