Annotation of src/games/factor/factor.c, Revision 1.18
1.18 ! lukem 1: /* $NetBSD: factor.c,v 1.17 2007/12/15 19:44:40 perry Exp $ */
1.5 cgd 2:
1.1 cgd 3: /*
1.5 cgd 4: * Copyright (c) 1989, 1993
5: * The Regents of the University of California. All rights reserved.
1.1 cgd 6: *
7: * This code is derived from software contributed to Berkeley by
8: * Landon Curt Noll.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
1.14 agc 18: * 3. Neither the name of the University nor the names of its contributors
1.1 cgd 19: * may be used to endorse or promote products derived from this software
20: * without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32: * SUCH DAMAGE.
33: */
34:
1.7 lukem 35: #include <sys/cdefs.h>
1.1 cgd 36: #ifndef lint
1.18 ! lukem 37: __COPYRIGHT("@(#) Copyright (c) 1989, 1993\
! 38: The Regents of the University of California. All rights reserved.");
1.1 cgd 39: #endif /* not lint */
40:
41: #ifndef lint
1.5 cgd 42: #if 0
1.6 tls 43: static char sccsid[] = "@(#)factor.c 8.4 (Berkeley) 5/4/95";
1.5 cgd 44: #else
1.18 ! lukem 45: __RCSID("$NetBSD: factor.c,v 1.17 2007/12/15 19:44:40 perry Exp $");
1.5 cgd 46: #endif
1.1 cgd 47: #endif /* not lint */
48:
49: /*
50: * factor - factor a number into primes
51: *
52: * By: Landon Curt Noll chongo@toad.com, ...!{sun,tolsoft}!hoptoad!chongo
53: *
54: * chongo <for a good prime call: 391581 * 2^216193 - 1> /\oo/\
55: *
56: * usage:
57: * factor [number] ...
58: *
59: * The form of the output is:
60: *
61: * number: factor1 factor1 factor2 factor3 factor3 factor3 ...
62: *
1.16 rillig 63: * where factor1 <= factor2 <= factor3 <= ...
1.1 cgd 64: *
65: * If no args are given, the list of numbers are read from stdin.
66: */
67:
1.10 simonb 68: #include <ctype.h>
1.5 cgd 69: #include <err.h>
70: #include <errno.h>
71: #include <limits.h>
1.1 cgd 72: #include <stdio.h>
1.5 cgd 73: #include <stdlib.h>
1.6 tls 74: #include <unistd.h>
1.5 cgd 75:
1.11 itojun 76: #ifdef HAVE_OPENSSL
1.10 simonb 77: #include <openssl/bn.h>
1.11 itojun 78: #else
79: typedef long BIGNUM;
80: typedef u_long BN_ULONG;
1.13 simonb 81: int BN_dec2bn(BIGNUM **a, const char *str);
82: #define BN_new() ((BIGNUM *)calloc(sizeof(BIGNUM), 1))
83: #define BN_is_zero(v) (*(v) == 0)
84: #define BN_is_one(v) (*(v) == 1)
1.12 simonb 85: #define BN_new() ((BIGNUM *)calloc(sizeof(BIGNUM), 1))
86: #define BN_is_zero(v) (*(v) == 0)
87: #define BN_is_one(v) (*(v) == 1)
1.11 itojun 88: #define BN_mod_word(a, b) (*(a) % (b))
89: #endif
1.10 simonb 90:
1.1 cgd 91: #include "primes.h"
92:
93: /*
94: * prime[i] is the (i-1)th prime.
95: *
1.10 simonb 96: * We are able to sieve 2^32-1 because this byte table yields all primes
1.1 cgd 97: * up to 65537 and 65537^2 > 2^32-1.
98: */
1.9 jsm 99: extern const ubig prime[];
100: extern const ubig *pr_limit; /* largest prime in the prime array */
1.1 cgd 101:
1.10 simonb 102: #define PRIME_CHECKS 5
103:
1.12 simonb 104: #ifdef HAVE_OPENSSL
105: BN_CTX *ctx; /* just use a global context */
106: #endif
107:
1.10 simonb 108: int main(int, char *[]);
1.12 simonb 109: void pr_fact(BIGNUM *); /* print factors of a value */
1.10 simonb 110: void BN_print_dec_fp(FILE *, const BIGNUM *);
1.17 perry 111: void usage(void) __dead;
1.11 itojun 112: #ifdef HAVE_OPENSSL
1.12 simonb 113: void pollard_pminus1(BIGNUM *); /* print factors for big numbers */
1.11 itojun 114: #else
115: char *BN_bn2dec(const BIGNUM *);
116: BN_ULONG BN_div_word(BIGNUM *, BN_ULONG);
1.13 simonb 117: #endif
118:
119:
120: #ifndef HAVE_OPENSSL
121: int
122: BN_dec2bn(BIGNUM **a, const char *str)
123: {
124: char *p;
125:
126: errno = 0;
127: **a = strtoul(str, &p, 10);
128: if (errno)
129: err(1, "%s", str);
130: return (*p == '\n' || *p == '\0');
131: }
1.11 itojun 132: #endif
1.1 cgd 133:
1.5 cgd 134: int
1.10 simonb 135: main(int argc, char *argv[])
1.1 cgd 136: {
1.10 simonb 137: BIGNUM *val;
1.5 cgd 138: int ch;
1.10 simonb 139: char *p, buf[LINE_MAX]; /* > max number of digits. */
140:
1.12 simonb 141: #ifdef HAVE_OPENSSL
142: ctx = BN_CTX_new();
143: #endif
1.10 simonb 144: val = BN_new();
145: if (val == NULL)
146: errx(1, "can't initialise bignum");
1.5 cgd 147:
1.7 lukem 148: while ((ch = getopt(argc, argv, "")) != -1)
1.5 cgd 149: switch (ch) {
150: case '?':
151: default:
152: usage();
153: }
154: argc -= optind;
155: argv += optind;
156:
157: /* No args supplied, read numbers from stdin. */
158: if (argc == 0)
159: for (;;) {
160: if (fgets(buf, sizeof(buf), stdin) == NULL) {
161: if (ferror(stdin))
162: err(1, "stdin");
163: exit (0);
164: }
165: for (p = buf; isblank(*p); ++p);
166: if (*p == '\n' || *p == '\0')
167: continue;
168: if (*p == '-')
169: errx(1, "negative numbers aren't permitted.");
1.10 simonb 170: if (BN_dec2bn(&val, buf) == 0)
171: errx(1, "%s: illegal numeric format.", argv[0]);
1.5 cgd 172: pr_fact(val);
173: }
174: /* Factor the arguments. */
175: else
176: for (; *argv != NULL; ++argv) {
177: if (argv[0][0] == '-')
178: errx(1, "negative numbers aren't permitted.");
1.10 simonb 179: if (BN_dec2bn(&val, argv[0]) == 0)
1.5 cgd 180: errx(1, "%s: illegal numeric format.", argv[0]);
181: pr_fact(val);
1.1 cgd 182: }
183: exit(0);
184: }
185:
186: /*
187: * pr_fact - print the factors of a number
188: *
189: * If the number is 0 or 1, then print the number and return.
190: * If the number is < 0, print -1, negate the number and continue
191: * processing.
192: *
193: * Print the factors of the number, from the lowest to the highest.
194: * A factor will be printed numtiple times if it divides the value
195: * multiple times.
196: *
197: * Factors are printed with leading tabs.
198: */
199: void
1.10 simonb 200: pr_fact(BIGNUM *val)
1.1 cgd 201: {
1.9 jsm 202: const ubig *fact; /* The factor found. */
1.1 cgd 203:
1.5 cgd 204: /* Firewall - catch 0 and 1. */
1.10 simonb 205: if (BN_is_zero(val)) /* Historical practice; 0 just exits. */
1.1 cgd 206: exit(0);
1.10 simonb 207: if (BN_is_one(val)) {
208: printf("1: 1\n");
1.1 cgd 209: return;
210: }
211:
1.5 cgd 212: /* Factor value. */
1.10 simonb 213:
214: BN_print_dec_fp(stdout, val);
215: putchar(':');
216: for (fact = &prime[0]; !BN_is_one(val); ++fact) {
1.5 cgd 217: /* Look for the smallest factor. */
1.1 cgd 218: do {
1.10 simonb 219: if (BN_mod_word(val, (BN_ULONG)*fact) == 0)
1.1 cgd 220: break;
221: } while (++fact <= pr_limit);
222:
1.5 cgd 223: /* Watch for primes larger than the table. */
1.1 cgd 224: if (fact > pr_limit) {
1.11 itojun 225: #ifdef HAVE_OPENSSL
1.12 simonb 226: BIGNUM *bnfact;
227:
228: bnfact = BN_new();
229: BN_set_word(bnfact, *(fact - 1));
230: BN_sqr(bnfact, bnfact, ctx);
1.15 jsm 231: if (BN_cmp(bnfact, val) > 0
232: || BN_is_prime(val, PRIME_CHECKS, NULL, NULL,
233: NULL) == 1) {
1.12 simonb 234: putchar(' ');
235: BN_print_dec_fp(stdout, val);
236: } else
237: pollard_pminus1(val);
1.11 itojun 238: #else
1.12 simonb 239: printf(" %s", BN_bn2dec(val));
1.11 itojun 240: #endif
1.5 cgd 241: break;
1.1 cgd 242: }
243:
1.5 cgd 244: /* Divide factor out until none are left. */
1.1 cgd 245: do {
1.10 simonb 246: printf(" %lu", *fact);
247: BN_div_word(val, (BN_ULONG)*fact);
248: } while (BN_mod_word(val, (BN_ULONG)*fact) == 0);
1.5 cgd 249:
250: /* Let the user know we're doing something. */
1.10 simonb 251: fflush(stdout);
1.1 cgd 252: }
1.10 simonb 253: putchar('\n');
254: }
255:
256: /*
257: * Sigh.. No _decimal_ output to file functions in BN.
258: */
259: void
260: BN_print_dec_fp(FILE *fp, const BIGNUM *num)
261: {
262: char *buf;
263:
264: buf = BN_bn2dec(num);
265: if (buf == NULL)
266: return; /* XXX do anything here? */
267: fprintf(fp, buf);
268: free(buf);
1.5 cgd 269: }
270:
271: void
1.10 simonb 272: usage(void)
1.5 cgd 273: {
1.10 simonb 274: fprintf(stderr, "usage: factor [value ...]\n");
1.5 cgd 275: exit (0);
1.10 simonb 276: }
277:
278:
279:
280:
1.11 itojun 281: #ifdef HAVE_OPENSSL
1.15 jsm 282: /* pollard p-1, algorithm from Jim Gillogly, May 2000 */
1.10 simonb 283:
284: void
285: pollard_pminus1(BIGNUM *val)
286: {
1.15 jsm 287: BIGNUM *base, *rbase, *num, *i, *x;
1.10 simonb 288:
289: base = BN_new();
1.15 jsm 290: rbase = BN_new();
1.10 simonb 291: num = BN_new();
292: i = BN_new();
293: x = BN_new();
294:
1.15 jsm 295: BN_set_word(rbase, 1);
296: newbase:
297: BN_add_word(rbase, 1);
1.10 simonb 298: BN_set_word(i, 2);
1.15 jsm 299: BN_copy(base, rbase);
1.10 simonb 300:
301: for (;;) {
302: BN_mod_exp(base, base, i, val, ctx);
1.15 jsm 303: if (BN_is_one(base))
304: goto newbase;
1.10 simonb 305:
306: BN_copy(x, base);
307: BN_sub_word(x, 1);
308: BN_gcd(x, x, val, ctx);
309:
310: if (!BN_is_one(x)) {
311: if (BN_is_prime(x, PRIME_CHECKS, NULL, NULL,
312: NULL) == 1) {
313: putchar(' ');
314: BN_print_dec_fp(stdout, x);
315: } else
316: pollard_pminus1(x);
317: fflush(stdout);
318:
319: BN_div(num, NULL, val, x, ctx);
320: if (BN_is_one(num))
321: return;
322: if (BN_is_prime(num, PRIME_CHECKS, NULL, NULL,
323: NULL) == 1) {
324: putchar(' ');
325: BN_print_dec_fp(stdout, num);
326: fflush(stdout);
327: return;
328: }
329: BN_copy(val, num);
330: }
331: BN_add_word(i, 1);
332: }
1.1 cgd 333: }
1.11 itojun 334: #else
335: char *
336: BN_bn2dec(const BIGNUM *val)
337: {
338: char *buf;
339:
340: buf = malloc(100);
341: if (!buf)
342: return buf;
343: snprintf(buf, 100, "%ld", (long)*val);
344: return buf;
345: }
346:
347: BN_ULONG
348: BN_div_word(BIGNUM *a, BN_ULONG b)
349: {
350: BN_ULONG mod;
351:
352: mod = *a % b;
353: *a /= b;
354: return mod;
355: }
356: #endif
CVSweb <webmaster@jp.NetBSD.org>