@@ -2349,9 +2349,35 @@ \section{Random Primes}
23492349
23502350
23512351\section {Prime Sieve }
2352- The prime sieve is implemented as a simple segmented Sieve of Eratosthenes. It is only moderately optimized for
2353- space and runtime but should be small enough and also fast enough for almost all use-cases; quite quick for
2354- sequential access but relatively slow for random access.
2352+ The prime sieve is implemented as a simple segmented Sieve of Eratosthenes.
2353+
2354+ This library needs some small sequential amounts for divisibility tests starting at two and
2355+ some random small primes for the Miller--Rabin test. That means we need a small base sieve
2356+ for quick results with a cold start and small segments to get random small primes fast.
2357+
2358+ The base sieve holds odd values only and even with a size of \texttt {4096 } bytes it is
2359+ small enough to get build quickly, in about 50 $ \mu $ sec on the author's old machine.
2360+
2361+ The choice of the size for the individual segments varies more in the results. See table
2362+ \ref {table:sievebenchmarks } for some data.
2363+
2364+ \begin {table }[h]
2365+ \begin {center }
2366+ \begin {tabular }{r c l}
2367+ \textbf {Segment Size (bits) } & \textbf {Random Access in $ \mu $ sec } & \textbf {Full Primesum } \\
2368+ \texttt { 0x7F } & 70 & 90(!) min \\
2369+ \texttt {0x1000 } & 100 & 2 min 33 sec \\
2370+ \texttt {0x4000 } & 150 & 1 min 18 sec \\
2371+ \texttt { 0xFFFF } & 350 & 0 min 57 sec \\
2372+ \texttt {0x20000 } & 600 & 0 min 55 sec \\
2373+ \texttt { 0xFFFFFFFF } & 300 & 0 min 35 sec
2374+ \end {tabular }
2375+ \caption {Average access times (warm) with the default base sieve (\texttt {MP-64BIT })} \label {table:sievebenchmarks }
2376+ \end {center }
2377+ \end {table }
2378+
2379+ The default sizes are in \texttt {tommath\_ private.h }: \texttt {MP\_ SIEVE\_ PRIME\_ MAX\_ SQRT } is
2380+ the size of the base sieve and \texttt {MP\_ SIEVE\_ RANGE\_ A\_ B } is the size of the segment.
23552381
23562382\subsection {Initialization and Clearing }
23572383Initializing. It cannot fail because it only sets some default values. Memory is allocated later according to needs.
@@ -2402,20 +2428,12 @@ \subsection{Find Adjacent Primes}
24022428
24032429\subsection {Useful Constants }
24042430\begin {description }
2405- \item [\texttt {MP\_ SIEVE\_ BIGGEST\_ PRIME }] \texttt {read-only } The biggest prime the sieve can offer. It is
2406- $ 4 \, 294 \, 967 \, 291 $ for \texttt {MP\_ 16BIT }, \texttt {MP\_ 32BIT } and \texttt {MP\_ 64BIT }; and
2407- $ 18 \, 446 \, 744 \, 073 \, 709 \, 551 \, 557 $ for \texttt {MP\_ 64BIT } if the macro\\
2408- \texttt {LTM\_ SIEVE\_ USE\_ LARGE\_ SIEVE } is defined.
2431+ \item [\texttt {MP\_ SIEVE\_ BIGGEST\_ PRIME }] \texttt {read-only } The biggest prime the sieve can offer.
2432+ It is $ 4 \, 294 \, 967 \, 291 $ for all \texttt {MP\_ xBIT }.
24092433
24102434\item [\texttt {mp\_ sieve\_ prime }] \texttt {read-only } The basic type for the numbers in the sieve. It
2411- is \texttt {uint32\_ t } for \texttt {MP\_ 16BIT }, \texttt {MP\_ 32BIT } and \texttt {MP\_ 64BIT }; and
2412- \texttt {uint64\_ t } for \texttt {MP\_ 64BIT } if the macro \texttt {LTM\_ SIEVE\_ USE\_ LARGE\_ SIEVE } is defined.
2413-
2414- \item [\texttt {LTM\_ SIEVE\_ USE\_ LARGE\_ SIEVE }] \texttt {read-only } A compile time flag to make a large sieve.
2415- No advantage has been seen in using 64-bit integers if available except the ability to get a sieve up
2416- to $ 2 ^64 $ . But in this case the base sieve gets 0.25 Gibibytes large and the segments 0.5 Gibibytes
2417- (although you can change \texttt {LTM\_ SIEVE\_ RANGE\_ A\_ B } in \texttt {bn\_ mp\_ sieve.c } to get smaller segments)
2418- and it needs a long time to fill.
2435+ is \texttt {uint32\_ t } for \texttt {MP\_ 16BIT }, \texttt {MP\_ 32BIT }; and
2436+ \texttt {uint64\_ t } for \texttt {MP\_ 64BIT }..
24192437
24202438\item [\texttt {MP\_ SIEVE\_ PR\_ UINT }] Choses the correct macro from \texttt {inttypes.h } to print a\\
24212439 \texttt {mp\_ sieve\_ prime }. The header \texttt {inttypes.h } must be included before\\
@@ -2453,148 +2471,36 @@ \subsubsection{Primality Test}
24532471int main(int argc, char **argv)
24542472{
24552473 mp_sieve_prime number;
2456- mp_sieve *base = NULL;
2457- mp_sieve *segment = NULL;
2458- mp_sieve_prime single_segment_a = 0;
2474+ mp_sieve sieve;
24592475 int e;
2460-
24612476 /* variable holding the result of mp_is_small_prime */
24622477 mp_sieve_prime result;
24632478
24642479 if (argc != 2) {
24652480 fprintf(stderr,"Usage %s number\textbackslash{}n", argv[0]);
24662481 exit(EXIT_FAILURE);
24672482 }
2468-
24692483 number = (mp_sieve_prime) strtoul(argv[1],NULL, 10);
24702484 if (errno == ERANGE) {
24712485 fprintf(stderr,"strtoul(l) failed: input out of range\textbackslash{}n");
24722486 goto LTM_ERR;
24732487 }
2474-
24752488 mp_sieve_init(&sieve);
2476-
24772489 if ((e = mp_is_small_prime(number, &result, &sieve)) != MP_OKAY) {
24782490 fprintf(stderr,"mp_is_small_prime failed: \textbackslash{}"%s\textbackslash{}"\textbackslash{}n",
24792491 mp_error_to_string(e));
24802492 goto LTM_ERR;
24812493 }
2482-
24832494 printf("The number %" LTM_SIEVE_PR_UINT " is %s prime\textbackslash{}n",
24842495 number,(result)?"":"not");
24852496
2486-
2487- mp_sieve_clear(&sieve);
2488- exit(EXIT_SUCCESS);
2489- LTM_ERR:
2490- mp_sieve_clear(&sieve);
2491- exit(EXIT_FAILURE);
2492- }
2493- \end {alltt }
2494- \subsubsection {Find Adjacent Primes }
2495- To sum up all primes up to and including \texttt {MP\_ SIEVE\_ BIGGEST\_ PRIME } you might do something like:
2496- \begin {alltt }
2497- #include <stdlib.h>
2498- #include <stdio.h>
2499- #include <errno.h>
2500- #include <tommath.h>
2501- int main(int argc, char **argv)
2502- {
2503- mp_sieve_prime number;
2504- mp_sieve sieve;
2505- mp_sieve_prime k, ret;
2506- mp_int total, t;
2507- int e;
2508-
2509- if (argc != 2) {
2510- fprintf(stderr,"Usage %s integer\textbackslash{}n", argv[0]);
2511- exit(EXIT_FAILURE);
2512- }
2513-
2514- if ((e = mp_init_multi(&total, &t, NULL)) != MP_OKAY) {
2515- fprintf(stderr,"mp_init_multi(segment): \textbackslash{}"%s\textbackslash{}"\textbackslash{}n",
2516- mp_error_to_string(e));
2517- goto LTM_ERR_1;
2518- }
2519- errno = 0;
2520- #if ( (defined MP_64BIT) && (defined LTM_SIEVE_USE_LARGE_SIEVE) )
2521- number = (mp_sieve_prime) strtoull(argv[1],NULL, 10);
2522- #else
2523- number = (mp_sieve_prime) strtoul(argv[1],NULL, 10);
2524- #endif
2525- if (errno == ERANGE) {
2526- fprintf(stderr,"strtoul(l) failed: input out of range\textbackslash{}n");
2527- return EXIT_FAILURE
2528- }
2529-
2530- mp_sieve_init(&sieve);
2531-
2532- for (k = 0, ret = 0; ret < number; k = ret) {
2533- if ((e = mp_next_small_prime(k + 1, &ret, &sieve)) != MP_OKAY) {
2534- if (e == LTM_SIEVE_MAX_REACHED) {
2535- #ifdef MP_64BIT
2536- if ((e = mp_add_d(&total, (mp_digit) k, &total)) != MP_OKAY) {
2537- fprintf(stderr,"mp_add_d (1) failed: \textbackslash{}"%s\textbackslash{}"\textbackslash{}n",
2538- mp_error_to_string(e));
2539- goto LTM_ERR;
2540- }
2541- #else
2542- if ((e = mp_set_long(&t, k)) != MP_OKAY) {
2543- fprintf(stderr,"mp_set_long (1) failed: \textbackslash{}"%s\textbackslash{}"\textbackslash{}n",
2544- mp_error_to_string(e));
2545- goto LTM_ERR;
2546- }
2547- if ((e = mp_add(&total, &t, &total)) != MP_OKAY) {
2548- fprintf(stderr,"mp_add (1) failed: \textbackslash{}"%s\textbackslash{}"\textbackslash{}n",
2549- mp_error_to_string(e));
2550- goto LTM_ERR;
2551- }
2552- #endif
2553- break;
2554- }
2555- fprintf(stderr,"mp_next_small_prime failed: \textbackslash{}"%s\textbackslash{}"\textbackslash{}n",
2556- mp_error_to_string(e));
2557- goto LTM_ERR;
2558- }
2559- /* The check if the prime is below the given limit
2560- * cannot be done in the for-loop conditions because if
2561- * it could we wouldn't need the sieve in the first place.
2562- */
2563- if (ret <= number) {
2564- #ifdef MP_64BIT
2565- if ((e = mp_add_d(&total, (mp_digit) k, &total)) != MP_OKAY) {
2566- fprintf(stderr,"mp_add_d failed: \textbackslash{}"%s\textbackslash{}"\textbackslash{}n",
2567- mp_error_to_string(e));
2568- goto LTM_ERR;
2569- }
2570- #else
2571- if ((e = mp_set_long(&t, k)) != MP_OKAY) {
2572- fprintf(stderr,"mp_set_long failed: \textbackslash{}"%s\textbackslash{}"\textbackslash{}n",
2573- mp_error_to_string(e));
2574- goto LTM_ERR;
2575- }
2576- if ((e = mp_add(&total, &t, &total)) != MP_OKAY) {
2577- fprintf(stderr,"mp_add failed: \textbackslash{}"%s\textbackslash{}"\textbackslash{}n",
2578- mp_error_to_string(e));
2579- goto LTM_ERR;
2580- }
2581- #endif
2582- }
2583- }
2584- printf("total: ");
2585- mp_fwrite(&total,10,stdout);
2586- putchar('\textbackslash{}n');
2587-
2588- mp_clear_multi(&total, &t, NULL);
25892497 mp_sieve_clear(&sieve);
25902498 exit(EXIT_SUCCESS);
25912499LTM_ERR:
2592- mp_clear_multi(&total, &t, NULL);
25932500 mp_sieve_clear(&sieve);
25942501 exit(EXIT_FAILURE);
25952502}
25962503\end {alltt }
2597- It took about a minute on the authors machine from 2015 to get the expected $ 425 \, 649 \, 736 \, 193 \, 687 \, 430 $ for the sum of all primes up to $ 2 ^{32}$ , about the same runtime as Pari/GP version 2.9.4 (with a GMP-5.1.3 kernel).
25982504
25992505\chapter {Random Number Generation }
26002506\section {PRNG }
0 commit comments