summaryrefslogtreecommitdiff
path: root/games/factor
diff options
context:
space:
mode:
authorTheo Buehler <tb@cvs.openbsd.org>2016-07-11 18:30:22 +0000
committerTheo Buehler <tb@cvs.openbsd.org>2016-07-11 18:30:22 +0000
commitafa3c79298ffa6cd8a8d8759e02f901def67e760 (patch)
tree7af2bc622a6e3d579ce9670e3cec3ef27c4529be /games/factor
parent995e3f244ce52a0c0091b7627e57e6a0b76296c5 (diff)
Instead of using the floating point square root, use an integer version
of the Newton method from ping.c. Fixes a rounding issue that caused failure to factor numbers close to 2^64, e.g. 18446744030759878681. While there, fix an off by one error that caused 4295360521 to be reported as a prime. Issues reported by Paul Stoeber and Michael Bozon. ok tedu, deraadt
Diffstat (limited to 'games/factor')
-rw-r--r--games/factor/Makefile4
-rw-r--r--games/factor/factor.c57
2 files changed, 39 insertions, 22 deletions
diff --git a/games/factor/Makefile b/games/factor/Makefile
index b38a839511d..261e7a45b19 100644
--- a/games/factor/Makefile
+++ b/games/factor/Makefile
@@ -1,11 +1,9 @@
-# $OpenBSD: Makefile,v 1.5 2016/03/30 06:38:40 jmc Exp $
+# $OpenBSD: Makefile,v 1.6 2016/07/11 18:30:21 tb Exp $
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>
diff --git a/games/factor/factor.c b/games/factor/factor.c
index fc86828ca25..4b00a043207 100644
--- a/games/factor/factor.c
+++ b/games/factor/factor.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: factor.c,v 1.27 2016/03/07 12:07:56 mestre Exp $ */
+/* $OpenBSD: factor.c,v 1.28 2016/07/11 18:30:21 tb Exp $ */
/* $NetBSD: factor.c,v 1.5 1995/03/23 08:28:07 cgd Exp $ */
/*
@@ -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 prime in the prime array */
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 value. */
(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 value. */
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 value. */
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 value. */
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 value. */
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 value. */
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());