35 |
//integer, which speeds the division. Additionally, there isn't |
//integer, which speeds the division. Additionally, there isn't |
36 |
//much use in trying to factor larger integers on a web page. |
//much use in trying to factor larger integers on a web page. |
37 |
//This subfunction is "parlor trivia" grade only. |
//This subfunction is "parlor trivia" grade only. |
38 |
// |
// |
39 |
//INPUT PARAMETERS |
//INPUT PARAMETERS |
40 |
//---------------- |
//---------------- |
41 |
//This subfunction accepts the following parameters, in order. |
//This subfunction accepts the following parameters, in order. |
98 |
// the code of the last factor. |
// the code of the last factor. |
99 |
// |
// |
100 |
//The return value (exit code) from this subfunction is always 0. |
//The return value (exit code) from this subfunction is always 0. |
101 |
// |
// |
102 |
|
|
103 |
#define MODULE_SUBFUNC_PFACT_18 |
#define MODULE_SUBFUNC_PFACT_18 |
104 |
|
|
174 |
return(0); |
return(0); |
175 |
} |
} |
176 |
|
|
177 |
//Copy the command-line arguments to a safe place where we can manipulate them. |
//Copy the command-line arguments to a safe place where we can manipulate them. |
178 |
//Leave 2 characters of space in case we assign a "0". |
//Leave 2 characters of space in case we assign a "0". |
179 |
arg1 = (char *)malloc((AUXFUNCS_size_t_max(1, strlen(argv[2])) + 1) * sizeof(char)); |
arg1 = (char *)malloc((AUXFUNCS_size_t_max(1, strlen(argv[2])) + 1) * sizeof(char)); |
180 |
arg2 = (char *)malloc((AUXFUNCS_size_t_max(1, strlen(argv[3])) + 1) * sizeof(char)); |
arg2 = (char *)malloc((AUXFUNCS_size_t_max(1, strlen(argv[3])) + 1) * sizeof(char)); |
215 |
return(0); |
return(0); |
216 |
} |
} |
217 |
|
|
218 |
//If the number to factor exceeds 18 digits, abort. Anything that has |
//If the number to factor exceeds 18 digits, abort. Anything that has |
219 |
//18 or fewer digits is allowed. |
//18 or fewer digits is allowed. |
220 |
if (strlen(arg1) >18) |
if (strlen(arg1) >18) |
221 |
{ |
{ |
227 |
//GMP type. |
//GMP type. |
228 |
mpz_set_str(number_to_factor, arg1, 10); |
mpz_set_str(number_to_factor, arg1, 10); |
229 |
|
|
230 |
//Assign the number of Miller-Rabin repetitons to use, subject to an |
//Assign the number of Miller-Rabin repetitons to use, subject to an |
231 |
//absolute maximum of 1000 and minimum of 1. |
//absolute maximum of 1000 and minimum of 1. |
232 |
miller_rabin_iterations = 25; |
miller_rabin_iterations = 25; |
233 |
if (strlen(arg2) > 3) |
if (strlen(arg2) > 3) |
238 |
{ |
{ |
239 |
sscanf(arg2, "%d", &miller_rabin_iterations); |
sscanf(arg2, "%d", &miller_rabin_iterations); |
240 |
if (miller_rabin_iterations < 1) |
if (miller_rabin_iterations < 1) |
241 |
miller_rabin_iterations = 1; |
miller_rabin_iterations = 1; |
242 |
} |
} |
243 |
|
|
244 |
//Assign the maximum time allowed, subject to a maximum of 1000 and minimum of 3. |
//Assign the maximum time allowed, subject to a maximum of 1000 and minimum of 3. |
250 |
{ |
{ |
251 |
sscanf(arg3, "%d", &max_time); |
sscanf(arg3, "%d", &max_time); |
252 |
if (max_time < 3) |
if (max_time < 3) |
253 |
max_time = 3; |
max_time = 3; |
254 |
} |
} |
255 |
|
|
256 |
//Output the header information before beginning the search. |
//Output the header information before beginning the search. |
257 |
printf("S\n"); |
printf("S\n"); |
258 |
mpz_out_str(stdout, 10, number_to_factor); |
mpz_out_str(stdout, 10, number_to_factor); |
259 |
printf("\n"); |
printf("\n"); |
260 |
printf("%d\n", miller_rabin_iterations); |
printf("%d\n", miller_rabin_iterations); |
261 |
printf("%d\n", max_time); |
printf("%d\n", max_time); |
262 |
|
|
270 |
|
|
271 |
//Factor out all occurrences that we can. |
//Factor out all occurrences that we can. |
272 |
while (mpz_divisible_ui_p(number_to_factor, SIEVE_ERATOSTHENES_sieve_factors[i])) |
while (mpz_divisible_ui_p(number_to_factor, SIEVE_ERATOSTHENES_sieve_factors[i])) |
273 |
{ |
{ |
274 |
mpz_divexact_ui(number_to_factor, number_to_factor, SIEVE_ERATOSTHENES_sieve_factors[i]); |
mpz_divexact_ui(number_to_factor, number_to_factor, SIEVE_ERATOSTHENES_sieve_factors[i]); |
275 |
multiplicity++; |
multiplicity++; |
276 |
} |
} |
277 |
|
|
278 |
//Now output the information record to the stdout if we could factor it. |
//Now output the information record to the stdout if we could factor it. |
279 |
if (multiplicity) |
if (multiplicity) |
280 |
{ |
{ |
281 |
printf("P\n"); |
printf("P\n"); |
282 |
printf("%u\n", SIEVE_ERATOSTHENES_sieve_factors[i]); |
printf("%u\n", SIEVE_ERATOSTHENES_sieve_factors[i]); |
283 |
printf("%d\n", multiplicity); |
printf("%d\n", multiplicity); |
284 |
} |
} |
285 |
} |
} |
286 |
|
|
287 |
//Gear up for tabulated operation as we sieve. |
//Gear up for tabulated operation as we sieve. |
288 |
new_trial_divisor = trial_divisor = SIEVE_ERATOSTHENES_FIRST_TRIAL_DIVISOR; |
new_trial_divisor = trial_divisor = SIEVE_ERATOSTHENES_FIRST_TRIAL_DIVISOR; |
289 |
sieve_table_index = SIEVE_ERATOSTHENES_FIRST_SIEVE_INDEX; |
sieve_table_index = SIEVE_ERATOSTHENES_FIRST_SIEVE_INDEX; |
299 |
exit_flag = 1; |
exit_flag = 1; |
300 |
|
|
301 |
//Effectively, we may have broken down the number to factor |
//Effectively, we may have broken down the number to factor |
302 |
//with just a few operations. So, effectively, we are |
//with just a few operations. So, effectively, we are |
303 |
//starting afresh here. We only need to proceed to the |
//starting afresh here. We only need to proceed to the |
304 |
//square root of the current number to factor (not the |
//square root of the current number to factor (not the |
305 |
//original one. |
//original one. |
306 |
mpz_sqrt(square_root_limit, number_to_factor); |
mpz_sqrt(square_root_limit, number_to_factor); |
312 |
{ |
{ |
313 |
if (mpz_cmp_ui(number_to_factor, 1)) |
if (mpz_cmp_ui(number_to_factor, 1)) |
314 |
{ |
{ |
315 |
exit_flag = 1; |
exit_flag = 1; |
316 |
printf("P\n"); |
printf("P\n"); |
317 |
mpz_out_str(stdout, 10, number_to_factor); |
mpz_out_str(stdout, 10, number_to_factor); |
318 |
printf("\n"); |
printf("\n"); |
319 |
printf("1\n"); |
printf("1\n"); |
320 |
goto done; |
goto done; |
321 |
} |
} |
322 |
} |
} |
323 |
|
|
324 |
//If Miller-Rabin says that the remaining number is probably prime, that is good |
//If Miller-Rabin says that the remaining number is probably prime, that is good |
327 |
{ |
{ |
328 |
exit_flag = 1; |
exit_flag = 1; |
329 |
printf("p\n"); |
printf("p\n"); |
330 |
mpz_out_str(stdout, 10, number_to_factor); |
mpz_out_str(stdout, 10, number_to_factor); |
331 |
printf("\n"); |
printf("\n"); |
332 |
printf("1\n"); |
printf("1\n"); |
333 |
goto done; |
goto done; |
334 |
} |
} |
335 |
|
|
336 |
//Loop entry condition. |
//Loop entry condition. |
347 |
|
|
348 |
//Factor out all occurrences that we can of the trial divisor, if we can. |
//Factor out all occurrences that we can of the trial divisor, if we can. |
349 |
while (mpz_divisible_ui_p(number_to_factor, trial_divisor)) |
while (mpz_divisible_ui_p(number_to_factor, trial_divisor)) |
350 |
{ |
{ |
351 |
mpz_divexact_ui(number_to_factor, number_to_factor, trial_divisor); |
mpz_divexact_ui(number_to_factor, number_to_factor, trial_divisor); |
352 |
multiplicity++; |
multiplicity++; |
353 |
} |
} |
354 |
|
|
355 |
//Now output the information record to the stdout if we could factor it. |
//Now output the information record to the stdout if we could factor it. |
356 |
if (multiplicity) |
if (multiplicity) |
357 |
{ |
{ |
358 |
printf("P\n"); |
printf("P\n"); |
359 |
printf("%u\n", trial_divisor); |
printf("%u\n", trial_divisor); |
360 |
printf("%d\n", multiplicity); |
printf("%d\n", multiplicity); |
365 |
//If we are over the square root bound, the remaining number to factor |
//If we are over the square root bound, the remaining number to factor |
366 |
//is prime and we should exit. |
//is prime and we should exit. |
367 |
if (mpz_cmp_ui(square_root_limit, trial_divisor) <= 0) |
if (mpz_cmp_ui(square_root_limit, trial_divisor) <= 0) |
368 |
exit_flag = 1; |
exit_flag = 1; |
369 |
|
|
370 |
//Are we over the time bound? We might has well check here, |
//Are we over the time bound? We might has well check here, |
371 |
//because finding prime factors is rare. |
//because finding prime factors is rare. |
372 |
if ((time(NULL) - time_snapshot) > max_time) |
if ((time(NULL) - time_snapshot) > max_time) |
373 |
exit_flag = 1; |
exit_flag = 1; |
374 |
|
|
375 |
//Does the Miller-Rabin test say that the remaining number |
//Does the Miller-Rabin test say that the remaining number |
376 |
//is with near perfect certainty prime? |
//is with near perfect certainty prime? |
377 |
if (mpz_probab_prime_p(number_to_factor, miller_rabin_iterations) >= 1) |
if (mpz_probab_prime_p(number_to_factor, miller_rabin_iterations) >= 1) |
378 |
exit_flag = 1; |
exit_flag = 1; |
379 |
|
|
380 |
//Is the remaining number "1", indicating we've factored it fully? |
//Is the remaining number "1", indicating we've factored it fully? |
381 |
if (!mpz_cmp_ui(number_to_factor, 1)) |
if (!mpz_cmp_ui(number_to_factor, 1)) |
382 |
exit_flag = 1; |
exit_flag = 1; |
383 |
|
|
384 |
//Set multiplicity to zero again so don't re-enter until successful |
//Set multiplicity to zero again so don't re-enter until successful |
385 |
//division again. |
//division again. |
391 |
|
|
392 |
//If the new is < the old, we've rolled over. This means an exit is necessary. |
//If the new is < the old, we've rolled over. This means an exit is necessary. |
393 |
if (new_trial_divisor < trial_divisor) |
if (new_trial_divisor < trial_divisor) |
394 |
exit_flag = 1; |
exit_flag = 1; |
395 |
|
|
396 |
//Advance the sieve index. |
//Advance the sieve index. |
397 |
sieve_table_index = (sieve_table_index + 1) % SIEVE_ERATOSTHENES_N_SIEVE; |
sieve_table_index = (sieve_table_index + 1) % SIEVE_ERATOSTHENES_N_SIEVE; |
398 |
|
|
399 |
//This is our only chance to check for termination conditions that |
//This is our only chance to check for termination conditions that |
400 |
//don't come about from a successful division. But we don't do |
//don't come about from a successful division. But we don't do |
401 |
//this often. |
//this often. |
402 |
mask_counter++; |
mask_counter++; |
403 |
if (!(mask_counter & 0xFFFFF)) |
if (!(mask_counter & 0xFFFFF)) |
404 |
{ |
{ |
405 |
//First, have we exceeded the square root bound? |
//First, have we exceeded the square root bound? |
406 |
if (mpz_cmp_ui(square_root_limit, trial_divisor) <= 0) |
if (mpz_cmp_ui(square_root_limit, trial_divisor) <= 0) |
407 |
exit_flag = 1; |
exit_flag = 1; |
408 |
//Second, are we over the time budget? |
//Second, are we over the time budget? |
409 |
if ((time(NULL) - time_snapshot) > max_time) |
if ((time(NULL) - time_snapshot) > max_time) |
410 |
exit_flag = 1; |
exit_flag = 1; |
411 |
} |
} |
412 |
} |
} |
413 |
|
|
414 |
//If we've made it out of the loop, there are a variety of reasons for that. |
//If we've made it out of the loop, there are a variety of reasons for that. |
415 |
//Find the right one and close up. |
//Find the right one and close up. |
416 |
if (!mpz_cmp_ui(number_to_factor, 1)) |
if (!mpz_cmp_ui(number_to_factor, 1)) |
421 |
{ |
{ |
422 |
//We are at or over the square root limit. The remaining number is definitely prime. |
//We are at or over the square root limit. The remaining number is definitely prime. |
423 |
printf("P\n"); |
printf("P\n"); |
424 |
mpz_out_str(stdout, 10, number_to_factor); |
mpz_out_str(stdout, 10, number_to_factor); |
425 |
printf("\n"); |
printf("\n"); |
426 |
printf("1\n"); |
printf("1\n"); |
427 |
} |
} |
428 |
else if (mpz_probab_prime_p(number_to_factor, miller_rabin_iterations) == 0) |
else if (mpz_probab_prime_p(number_to_factor, miller_rabin_iterations) == 0) |
429 |
{ |
{ |
430 |
//Miller-Rabin says the remaining number is definitely composite. |
//Miller-Rabin says the remaining number is definitely composite. |
431 |
printf("C\n"); |
printf("C\n"); |
432 |
mpz_out_str(stdout, 10, number_to_factor); |
mpz_out_str(stdout, 10, number_to_factor); |
433 |
printf("\n"); |
printf("\n"); |
434 |
printf("1\n"); |
printf("1\n"); |
435 |
} |
} |
436 |
else if (mpz_probab_prime_p(number_to_factor, miller_rabin_iterations) == 1) |
else if (mpz_probab_prime_p(number_to_factor, miller_rabin_iterations) == 1) |
437 |
{ |
{ |
438 |
//Miller-Rabin says the remaining number is probably prime. |
//Miller-Rabin says the remaining number is probably prime. |
439 |
printf("p\n"); |
printf("p\n"); |
440 |
mpz_out_str(stdout, 10, number_to_factor); |
mpz_out_str(stdout, 10, number_to_factor); |
441 |
printf("\n"); |
printf("\n"); |
442 |
printf("1\n"); |
printf("1\n"); |
443 |
} |
} |
444 |
else if (mpz_probab_prime_p(number_to_factor, miller_rabin_iterations) == 2) |
else if (mpz_probab_prime_p(number_to_factor, miller_rabin_iterations) == 2) |
445 |
{ |
{ |
446 |
//Miller-Rabin says the remaining number is definitely prime. |
//Miller-Rabin says the remaining number is definitely prime. |
447 |
printf("P\n"); |
printf("P\n"); |
448 |
mpz_out_str(stdout, 10, number_to_factor); |
mpz_out_str(stdout, 10, number_to_factor); |
449 |
printf("\n"); |
printf("\n"); |
450 |
printf("1\n"); |
printf("1\n"); |
451 |
} |
} |
452 |
|
|
453 |
//Output the invariant footer information. |
//Output the invariant footer information. |
454 |
done: |
done: |
455 |
printf("X\n"); |
printf("X\n"); |
456 |
printf("S\n"); |
printf("S\n"); |
457 |
|
|
458 |
//Always return 0. |
//Always return 0. |
459 |
return(0); |
return(0); |
460 |
} |
} |
461 |
|
|
462 |
//******************************************************************************** |
//******************************************************************************** |
463 |
// End of SUBFUNC_PFACT_18.C. |
// End of SUBFUNC_PFACT_18.C. |