@@ -2347,6 +2347,255 @@ \section{Random Primes}
23472347 \label {fig:primeopts }
23482348\end {figure }
23492349
2350+
2351+ \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.
2355+
2356+ \subsection {Initialization and Clearing }
2357+ Initializing. It cannot fail because it only sets some default values. Memory is allocated later according to needs.
2358+ \index {mp\_ sieve\_ init}
2359+ \begin {alltt }
2360+ void mp_sieve_init(mp_sieve *sieve);
2361+ \end {alltt }
2362+ The function \texttt {mp\_ sieve\_ init } is equivalent to
2363+ \begin {alltt }
2364+ mp_sieve sieve = {NULL, NULL, 0};
2365+ \end {alltt }
2366+
2367+ Free the memory used by the sieve with
2368+ \index {mp\_ sieve\_ clear}
2369+ \begin {alltt }
2370+ void mp_sieve_clear(mp_sieve *sieve);
2371+ \end {alltt }
2372+
2373+ \subsection {Primality Test of Small Numbers }
2374+ Individual small numbers can be tested for primality with
2375+ \index {mp\_ is\_ small\_ prime}
2376+ \begin {alltt }
2377+ int mp_is_small_prime(mp_sieve_prime n, mp_sieve_prime *result,
2378+ mp_sieve *sieve);
2379+ \end {alltt }
2380+ The implementation of this function does all the heavy lifting--the building of the base sieve and the segment
2381+ if one is necessary. The base sieve stays, so this function can be used to `` warm up'' the sieve and, if
2382+ \texttt {n } is slightly larger than the upper limit of the base sieve, `` warm up'' the first segment, too.
2383+
2384+ It will return \texttt {MP\_ SIEVE\_ MAX\_ REACHED } to flag the content of \texttt {result } as the last valid one.
2385+
2386+ \subsection {Find Adjacent Primes }
2387+ To find the prime bigger than a number \texttt {n } use
2388+ \index {mp\_ next\_ small\_ prime}
2389+ \begin {alltt }
2390+ int mp_next_small_prime(mp_sieve_prime n, mp_sieve_prime *result,
2391+ mp_sieve *sieve);
2392+ \end {alltt }
2393+ and to find the one smaller than \texttt {n }
2394+ \index {mp\_ prec\_ small\_ prime}
2395+ \begin {alltt }
2396+ int mp_prec_small_prime(mp_sieve_prime n, mp_sieve_prime *result,
2397+ mp_sieve *sieve);
2398+ \end {alltt }
2399+ Both functions return \texttt {n } if \texttt {n } is prime. Use \texttt {n + 1 } to get
2400+ the prime after \texttt {n } if \texttt {n } is prime and \texttt {n - 1 } to get the
2401+ the prime preceding \texttt {n } if \texttt {n } is prime.
2402+
2403+ \subsection {Useful Constants }
2404+ \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.
2409+
2410+ \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.
2419+
2420+ \item [\texttt {MP\_ SIEVE\_ PR\_ UINT }] Choses the correct macro from \texttt {inttypes.h } to print a\\
2421+ \texttt {mp\_ sieve\_ prime }. The header \texttt {inttypes.h } must be included before\\
2422+ \texttt {tommath.h } for it to work.
2423+ \end {description }
2424+ \subsection {Examples }\label {sec:spnexamples }
2425+ \subsubsection {Initialization and Clearing }
2426+ Using a sieve follows the same procedure as using a bigint:
2427+ \begin {alltt }
2428+ /* Declaration */
2429+ mp_sieve sieve;
2430+
2431+ /*
2432+ Initialization.
2433+ Cannot fail, only sets a handful of default values.
2434+ Memory allocation is done in the library itself
2435+ according to needs.
2436+ */
2437+ mp_sieve_init(&sieve);
2438+
2439+ /* use the sieve */
2440+
2441+ /* Clean up */
2442+ mp_sieve_clear(&sieve);
2443+ \end {alltt }
2444+ \subsubsection {Primality Test }
2445+ A small program to test the input of a small number for primality.
2446+ \begin {alltt }
2447+ #include <stdlib.h>
2448+ #include <stdio.h>
2449+ #include <errno.h>
2450+ /*inttypes.h is needed for printing and must be included before tommath.h*/
2451+ #include <inttypes.h>
2452+ #include "tommath.h"
2453+ int main(int argc, char **argv)
2454+ {
2455+ mp_sieve_prime number;
2456+ mp_sieve *base = NULL;
2457+ mp_sieve *segment = NULL;
2458+ mp_sieve_prime single_segment_a = 0;
2459+ int e;
2460+
2461+ /* variable holding the result of mp_is_small_prime */
2462+ mp_sieve_prime result;
2463+
2464+ if (argc != 2) {
2465+ fprintf(stderr,"Usage %s number\textbackslash{}n", argv[0]);
2466+ exit(EXIT_FAILURE);
2467+ }
2468+
2469+ number = (mp_sieve_prime) strtoul(argv[1],NULL, 10);
2470+ if (errno == ERANGE) {
2471+ fprintf(stderr,"strtoul(l) failed: input out of range\textbackslash{}n");
2472+ goto LTM_ERR;
2473+ }
2474+
2475+ mp_sieve_init(&sieve);
2476+
2477+ if ((e = mp_is_small_prime(number, &result, &sieve)) != MP_OKAY) {
2478+ fprintf(stderr,"mp_is_small_prime failed: \textbackslash{}"%s\textbackslash{}"\textbackslash{}n",
2479+ mp_error_to_string(e));
2480+ goto LTM_ERR;
2481+ }
2482+
2483+ printf("The number %" LTM_SIEVE_PR_UINT " is %s prime\textbackslash{}n",
2484+ number,(result)?"":"not");
2485+
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);
2589+ mp_sieve_clear(&sieve);
2590+ exit(EXIT_SUCCESS);
2591+ LTM_ERR:
2592+ mp_clear_multi(&total, &t, NULL);
2593+ mp_sieve_clear(&sieve);
2594+ exit(EXIT_FAILURE);
2595+ }
2596+ \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).
2598+
23502599\chapter {Random Number Generation }
23512600\section {PRNG }
23522601\index {mp\_ rand}
@@ -2417,6 +2666,9 @@ \subsection{To ASCII}
24172666mp_err mp_fwrite(const mp_int *a, int radix, FILE *stream);
24182667\end {alltt }
24192668
2669+
2670+
2671+
24202672\subsection {From ASCII }
24212673\index {mp\_ read\_ radix}
24222674\begin {alltt }
0 commit comments