Last fall there was a thread containing some examples of composite numbers that were not factored properly by factor(6):
https://marc.info/?t=144155842300002&r=1&w=2 Some suggestions were made and some (incomplete) diffs were posted, but no action was taken. Below is a diff that uses Newton's method from ping.c, as suggested by Otto, and which fixes both bugs that were apparent in the thread: 1. The bigger problem is rounding: stop = (ubig)sqrt((double)val); is zero if val is close to 2^64. The reason is that the square root will be rounded up to 2^32 so that the cast with ubig (u_int32_t) results in zero. 2. The other problem is an off-by-one in the loop condition in pr_bigfact(): for val = 4295360521 = 65539 * 65539, both start and stop are equal to 65539 and hence the loop while (start < stop) { ... } is never entered so that 4295360521 is falsely reported as a prime. Both problems are only relevant if val has no prime factors smaller than 65539. Finally, as mentioned by naddy, another option would be to think about the FreeBSD way and make use of libcrypto's BN functions. Index: Makefile =================================================================== RCS file: /var/cvs/src/games/factor/Makefile,v retrieving revision 1.5 diff -u -p -r1.5 Makefile --- Makefile 30 Mar 2016 06:38:40 -0000 1.5 +++ Makefile 11 Jul 2016 12:04:27 -0000 @@ -4,8 +4,6 @@ PROG= factor SRCS= factor.c pattern.c pr_tbl.c CFLAGS+=-I${.CURDIR}/../primes MAN= factor.6 -DPADD= ${LIBM} -LDADD= -lm .PATH: ${.CURDIR}/../primes .include <bsd.prog.mk> Index: factor.c =================================================================== RCS file: /var/cvs/src/games/factor/factor.c,v retrieving revision 1.27 diff -u -p -r1.27 factor.c --- factor.c 7 Mar 2016 12:07:56 -0000 1.27 +++ factor.c 11 Jul 2016 15:43:35 -0000 @@ -55,7 +55,6 @@ #include <ctype.h> #include <err.h> #include <errno.h> -#include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -66,7 +65,7 @@ /* * prime[i] is the (i+1)th prime. * - * We are able to sieve 2^32-1 because this byte table yields all primes + * We are able to sieve 2^32-1 because this byte table yields all primes * up to 65537 and 65537^2 > 2^32-1. */ extern const ubig prime[]; @@ -74,9 +73,10 @@ extern const ubig *pr_limit; /* largest extern const char pattern[]; extern const int pattern_size; -void pr_fact(u_int64_t); /* print factors of a value */ -void pr_bigfact(u_int64_t); -__dead void usage(void); +static void pr_fact(u_int64_t); /* print factors of a value */ +static void pr_bigfact(u_int64_t); +static u_int32_t usqrt(u_int64_t); +static void __dead usage(void); int main(int argc, char *argv[]) @@ -152,7 +152,7 @@ main(int argc, char *argv[]) * * Prime factors are printed with leading spaces. */ -void +static void pr_fact(u_int64_t val) /* Factor this value. */ { const ubig *fact; /* The factor found. */ @@ -196,15 +196,16 @@ pr_fact(u_int64_t val) /* Factor this v (void)putchar('\n'); } - -/* At this point, our number may have factors greater than those in primes[]; +/* + * At this point, our number may have factors greater than those in primes[]; * however, we can generate primes up to 32 bits (see primes(6)), which is * sufficient to factor a 64-bit quad. */ -void +static void pr_bigfact(u_int64_t val) /* Factor this value. */ { - ubig start, stop, factor; + u_int64_t start, stop; + ubig factor; char *q; const ubig *p; ubig fact_lim, mod; @@ -212,7 +213,7 @@ pr_bigfact(u_int64_t val) /* Factor this char table[TABSIZE]; /* Eratosthenes sieve of odd numbers */ start = *pr_limit + 2; - stop = (ubig)sqrt((double)val); + stop = usqrt(val) + 1; if ((stop & 0x1) == 0) stop++; /* @@ -230,7 +231,8 @@ pr_bigfact(u_int64_t val) /* Factor this memcpy(table, &pattern[factor], pattern_size-factor); /* main block pattern copies */ for (fact_lim = pattern_size - factor; - fact_lim + pattern_size <= TABSIZE; fact_lim += pattern_size) { + fact_lim + pattern_size <= TABSIZE; + fact_lim += pattern_size) { memcpy(&table[fact_lim], pattern, pattern_size); } /* final block pattern copy */ @@ -238,11 +240,10 @@ pr_bigfact(u_int64_t val) /* Factor this if (stop-start > TABSIZE+TABSIZE) { tab_lim = &table[TABSIZE]; /* sieve it all */ - fact_lim = (int)sqrt( - (double)(start)+TABSIZE+TABSIZE+1.0); + fact_lim = usqrt(start + TABSIZE + TABSIZE + 1); } else { tab_lim = &table[(stop - start)/2]; /* partial sieve */ - fact_lim = (int)sqrt((double)(stop) + 1.0); + fact_lim = usqrt(stop + 1); } /* sieve for factors >= 17 */ factor = 17; /* 17 is first prime to use */ @@ -267,11 +268,11 @@ pr_bigfact(u_int64_t val) /* Factor this if (*q) { if (val % start == 0) { do { - (void)printf(" %lu", (unsigned long) start); + printf(" %llu", start); val /= start; } while ((val % start) == 0); (void)fflush(stdout); - stop = (ubig)sqrt((double)val); + stop = usqrt(val) + 1; if ((stop & 0x1) == 0) stop++; } @@ -282,8 +283,26 @@ pr_bigfact(u_int64_t val) /* Factor this printf(" %llu", val); } +/* Code taken from ping.c */ +static u_int32_t +usqrt(u_int64_t n) +{ + u_int64_t y, x = 1; + + if (n == 0 || n == 1) + return n; + + do { /* newton was a stinker */ + y = x; + x = n / x; + x += y; + x /= 2; + } while (((y < x) && (x - y) > 1) || (y - x) > 1); + + return (u_int32_t)x; +} -void +static void __dead usage(void) { (void)fprintf(stderr, "usage: %s [number ...]\n", getprogname());