@@ -2349,9 +2349,44 @@ \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. Size must be of the form $ -1 + 2 ^n$ .
2363+ Default size is \texttt {0xFFF }. It might be of interest that the biggest prime gap
2364+ below $ 2 ^{32}$ is $ 335 $ .
2365+
2366+ \begin {table }[h]
2367+ \begin {center }
2368+ \begin {tabular }{r c l}
2369+ \textbf {Segment Size (bits) } & \textbf {Random Access in $ \mu $ sec } & \textbf {Full Primesum } \\
2370+ \texttt { 0x1F } & (60) & - \\
2371+ \texttt { 0x3F } & (75) & - \\
2372+ \texttt { 0x7F } & 63 & - \\
2373+ \texttt { 0xFF } & 70 & 26 min \\
2374+ \texttt { 0x1FF } & 73 & 13 min \\
2375+ \texttt { 0x3FF } & 75 & 7 min 17 sec \\
2376+ \texttt { 0x7FF } & 85 & 4 min 10 sec \\
2377+ \texttt { 0xFFF } & 100 & 2 min 52 sec \\
2378+ \texttt { 0x1FFF } & 120 & 1 min 45 sec \\
2379+ \texttt { 0x3FFF } & 145 & 1 min 19 sec \\
2380+ \texttt { 0x7FFF } & 200 & 1 min 04 sec \\
2381+ \texttt { 0xFFFF } & 350 & 0 min 57 sec \\
2382+ \texttt { 0xFFFFFFFF } & 300 & 0 min 35 sec
2383+ \end {tabular }
2384+ \caption {Average access times (warm) with the default base sieve (\texttt {MP-64BIT })} \label {table:sievebenchmarks }
2385+ \end {center }
2386+ \end {table }
2387+
2388+ The default sizes are in \texttt {tommath\_ private.h }: \texttt {MP\_ SIEVE\_ PRIME\_ MAX\_ SQRT } is
2389+ the size of the base sieve and \texttt {MP\_ SIEVE\_ RANGE\_ A\_ B } is the size of the segment.
23552390
23562391\subsection {Initialization and Clearing }
23572392Initializing. It cannot fail because it only sets some default values. Memory is allocated later according to needs.
@@ -2402,20 +2437,12 @@ \subsection{Find Adjacent Primes}
24022437
24032438\subsection {Useful Constants }
24042439\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.
2440+ \item [\texttt {MP\_ SIEVE\_ BIGGEST\_ PRIME }] \texttt {read-only } The biggest prime the sieve can offer.
2441+ It is $ 4 \, 294 \, 967 \, 291 $ for all \texttt {MP\_ xBIT }.
24092442
24102443\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.
2444+ is \texttt {uint32\_ t } for \texttt {MP\_ 16BIT }, \texttt {MP\_ 32BIT }; and
2445+ \texttt {uint64\_ t } for \texttt {MP\_ 64BIT }..
24192446
24202447\item [\texttt {MP\_ SIEVE\_ PR\_ UINT }] Choses the correct macro from \texttt {inttypes.h } to print a\\
24212448 \texttt {mp\_ sieve\_ prime }. The header \texttt {inttypes.h } must be included before\\
@@ -2453,148 +2480,36 @@ \subsubsection{Primality Test}
24532480int main(int argc, char **argv)
24542481{
24552482 mp_sieve_prime number;
2456- mp_sieve *base = NULL;
2457- mp_sieve *segment = NULL;
2458- mp_sieve_prime single_segment_a = 0;
2483+ mp_sieve sieve;
24592484 int e;
2460-
24612485 /* variable holding the result of mp_is_small_prime */
24622486 mp_sieve_prime result;
24632487
24642488 if (argc != 2) {
24652489 fprintf(stderr,"Usage %s number\textbackslash{}n", argv[0]);
24662490 exit(EXIT_FAILURE);
24672491 }
2468-
24692492 number = (mp_sieve_prime) strtoul(argv[1],NULL, 10);
24702493 if (errno == ERANGE) {
24712494 fprintf(stderr,"strtoul(l) failed: input out of range\textbackslash{}n");
24722495 goto LTM_ERR;
24732496 }
2474-
24752497 mp_sieve_init(&sieve);
2476-
24772498 if ((e = mp_is_small_prime(number, &result, &sieve)) != MP_OKAY) {
24782499 fprintf(stderr,"mp_is_small_prime failed: \textbackslash{}"%s\textbackslash{}"\textbackslash{}n",
24792500 mp_error_to_string(e));
24802501 goto LTM_ERR;
24812502 }
2482-
24832503 printf("The number %" LTM_SIEVE_PR_UINT " is %s prime\textbackslash{}n",
24842504 number,(result)?"":"not");
24852505
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);
25892506 mp_sieve_clear(&sieve);
25902507 exit(EXIT_SUCCESS);
25912508LTM_ERR:
2592- mp_clear_multi(&total, &t, NULL);
25932509 mp_sieve_clear(&sieve);
25942510 exit(EXIT_FAILURE);
25952511}
25962512\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).
25982513
25992514\chapter {Random Number Generation }
26002515\section {PRNG }
0 commit comments