1 /* Factoring of uintmax_t numbers. Generation of needed tables.
2
3 Contributed to the GNU project by Torbjörn Granlund and Niels Möller
4 Contains code from GNU MP.
5
6 Copyright 2012-2023 Free Software Foundation, Inc.
7
8 This program is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free Software
10 Foundation; either version 3 of the License, or (at your option) any later
11 version.
12
13 This program is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
15 PARTICULAR PURPOSE. See the GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along with
18 this program. If not, see https://www.gnu.org/licenses/. */
19
20 #include <config.h>
21
22 #include <attribute.h>
23 #include <inttypes.h>
24
25 #include <limits.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <errno.h>
31
32 /* Deactivate "rpl_"-prefixed definitions of these symbols. */
33 #undef fclose
34 #undef free
35 #undef malloc
36 #undef strerror
37
38 /* An unsigned type that is no narrower than 32 bits and no narrower
39 than unsigned int. It's best to make it as wide as possible.
40 For GCC 4.6 and later, use a heuristic to guess whether unsigned
41 __int128 works on your platform. If this heuristic does not work
42 for you, please report a bug; in the meantime compile with, e.g.,
43 -Dwide_uint='unsigned __int128' to override the heuristic. */
44 #ifndef wide_uint
45 # if 4 < __GNUC__ + (6 <= __GNUC_MINOR__) && ULONG_MAX >> 31 >> 31 >> 1 != 0
46 typedef unsigned __int128 wide_uint;
47 # else
48 typedef uintmax_t wide_uint;
49 # endif
50 #endif
51
52 struct prime
53 {
54 unsigned p;
55 wide_uint pinv; /* Inverse mod b = 2^{bitsize of wide_uint} */
56 wide_uint lim; /* floor ((wide_uint) -1 / p) */
57 };
58
59 ATTRIBUTE_CONST
60 static wide_uint
binvert(wide_uint a)61 binvert (wide_uint a)
62 {
63 wide_uint x = 0xf5397db1 >> (4 * ((a / 2) & 0x7));
64 for (;;)
65 {
66 wide_uint y = 2 * x - x * x * a;
67 if (y == x)
68 return x;
69 x = y;
70 }
71 }
72
73 static void
process_prime(struct prime * info,unsigned p)74 process_prime (struct prime *info, unsigned p)
75 {
76 wide_uint max = -1;
77 info->p = p;
78 info->pinv = binvert (p);
79 info->lim = max / p;
80 }
81
82 static void
print_wide_uint(wide_uint n,int nesting,unsigned wide_uint_bits)83 print_wide_uint (wide_uint n, int nesting, unsigned wide_uint_bits)
84 {
85 /* Number of bits per integer literal. 8 is too many, because
86 uintmax_t is 32 bits on some machines so we cannot shift by 32 bits.
87 So use 7. */
88 int hex_digits_per_literal = 7;
89 int bits_per_literal = hex_digits_per_literal * 4;
90
91 unsigned remainder = n & ((1 << bits_per_literal) - 1);
92
93 if (n != remainder)
94 {
95 int needs_parentheses = n >> bits_per_literal >> bits_per_literal != 0;
96 if (needs_parentheses)
97 printf ("(");
98 print_wide_uint (n >> bits_per_literal, nesting + 1, wide_uint_bits);
99 if (needs_parentheses)
100 printf (")\n%*s", nesting + 3, "");
101 printf (" << %d | ", bits_per_literal);
102 }
103 else if (nesting)
104 {
105 printf ("(uintmax_t) ");
106 hex_digits_per_literal
107 = ((wide_uint_bits - 1) % bits_per_literal) % 4 + 1;
108 }
109
110 printf ("0x%0*xU", hex_digits_per_literal, remainder);
111 }
112
113 /* Work around <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109635>. */
114 #if 13 <= __GNUC__
115 # pragma GCC diagnostic ignored "-Wanalyzer-use-of-uninitialized-value"
116 #endif
117
118 static void
output_primes(const struct prime * primes,unsigned nprimes)119 output_primes (const struct prime *primes, unsigned nprimes)
120 {
121 unsigned i;
122 unsigned p;
123 int is_prime;
124
125 /* Compute wide_uint_bits by repeated shifting, rather than by
126 multiplying sizeof by CHAR_BIT, as this works even if the
127 wide_uint representation has holes. */
128 unsigned wide_uint_bits = 0;
129 wide_uint mask = -1;
130 for (wide_uint_bits = 0; mask; wide_uint_bits++)
131 mask >>= 1;
132
133 puts ("/* Generated file -- DO NOT EDIT */\n");
134 printf ("#define WIDE_UINT_BITS %u\n", wide_uint_bits);
135
136 for (i = 0, p = 2; i < nprimes; i++)
137 {
138 unsigned int d8 = i + 8 < nprimes ? primes[i + 8].p - primes[i].p : 0xff;
139 if (255 < d8) /* this happens at 668221 */
140 abort ();
141 printf ("P (%u, %u,\n (", primes[i].p - p, d8);
142 print_wide_uint (primes[i].pinv, 0, wide_uint_bits);
143 printf ("),\n UINTMAX_MAX / %u)\n", primes[i].p);
144 p = primes[i].p;
145 }
146
147 printf ("\n#undef FIRST_OMITTED_PRIME\n");
148
149 /* Find next prime */
150 do
151 {
152 p += 2;
153 for (i = 0, is_prime = 1; is_prime; i++)
154 {
155 if (primes[i].p * primes[i].p > p)
156 break;
157 if (p * primes[i].pinv <= primes[i].lim)
158 {
159 is_prime = 0;
160 break;
161 }
162 }
163 }
164 while (!is_prime);
165
166 printf ("#define FIRST_OMITTED_PRIME %u\n", p);
167 }
168
169 ATTRIBUTE_MALLOC
170 static void *
xalloc(size_t s)171 xalloc (size_t s)
172 {
173 void *p = malloc (s);
174 if (p)
175 return p;
176
177 fprintf (stderr, "Virtual memory exhausted.\n");
178 exit (EXIT_FAILURE);
179 }
180
181 int
main(int argc,char ** argv)182 main (int argc, char **argv)
183 {
184 int limit;
185
186 char *sieve;
187 size_t size, i;
188
189 struct prime *prime_list;
190 unsigned nprimes;
191
192 if (argc != 2)
193 {
194 fprintf (stderr, "Usage: %s LIMIT\n"
195 "Produces a list of odd primes <= LIMIT\n", argv[0]);
196 return EXIT_FAILURE;
197 }
198 limit = atoi (argv[1]);
199 if (limit < 3)
200 return EXIT_SUCCESS;
201
202 /* Make limit odd */
203 if ( !(limit & 1))
204 limit--;
205
206 size = (limit - 1) / 2;
207 /* sieve[i] represents 3+2*i */
208 sieve = xalloc (size);
209 memset (sieve, 1, size);
210
211 prime_list = xalloc (size * sizeof (*prime_list));
212 nprimes = 0;
213
214 for (i = 0; i < size;)
215 {
216 unsigned p = 3 + 2 * i;
217 unsigned j;
218
219 process_prime (&prime_list[nprimes++], p);
220
221 for (j = (p * p - 3) / 2; j < size; j += p)
222 sieve[j] = 0;
223
224 while (++i < size && sieve[i] == 0)
225 ;
226 }
227
228 output_primes (prime_list, nprimes);
229
230 free (sieve);
231 free (prime_list);
232
233 if (ferror (stdout) + fclose (stdout))
234 {
235 fprintf (stderr, "write error: %s\n", strerror (errno));
236 return EXIT_FAILURE;
237 }
238
239 return EXIT_SUCCESS;
240 }
241