@@ -2347,6 +2347,255 @@ \section{Random Primes}
2347
2347
\label {fig:primeopts }
2348
2348
\end {figure }
2349
2349
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
+
2350
2599
\chapter {Random Number Generation }
2351
2600
\section {PRNG }
2352
2601
\index {mp\_ rand}
@@ -2417,6 +2666,9 @@ \subsection{To ASCII}
2417
2666
mp_err mp_fwrite(const mp_int *a, int radix, FILE *stream);
2418
2667
\end {alltt }
2419
2668
2669
+
2670
+
2671
+
2420
2672
\subsection {From ASCII }
2421
2673
\index {mp\_ read\_ radix}
2422
2674
\begin {alltt }
0 commit comments