diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-04-09 21:18:43 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-04-09 21:18:43 +0200 |
commit | ee7f75d94f2a70d61a71eca9416d51a3268859d7 (patch) | |
tree | e6273417231ae83178cf8d5050d02bc59ff195d9 | |
parent | 87ae0fe095686b169ab1aeeb25c8ac3f5be30feb (diff) | |
download | busybox-w32-ee7f75d94f2a70d61a71eca9416d51a3268859d7.tar.gz busybox-w32-ee7f75d94f2a70d61a71eca9416d51a3268859d7.tar.bz2 busybox-w32-ee7f75d94f2a70d61a71eca9416d51a3268859d7.zip |
factor: new applet
thus far only able to factor up to ULLONG_MAX
function old new delta
factor_main - 378 +378
packed_usage 31427 31502 +75
applet_names 2590 2597 +7
applet_main 1500 1504 +4
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 3/0 up/down: 464/0) Total: 464 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | coreutils/factor.c | 112 | ||||
-rwxr-xr-x | testsuite/factor.tests | 48 |
2 files changed, 160 insertions, 0 deletions
diff --git a/coreutils/factor.c b/coreutils/factor.c new file mode 100644 index 000000000..0f838a735 --- /dev/null +++ b/coreutils/factor.c | |||
@@ -0,0 +1,112 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Denys Vlasenko <vda.linux@googlemail.com> | ||
3 | * | ||
4 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
5 | */ | ||
6 | //config:config FACTOR | ||
7 | //config: bool "factor" | ||
8 | //config: default y | ||
9 | //config: help | ||
10 | //config: factor factorizes integers | ||
11 | |||
12 | //applet:IF_FACTOR(APPLET(factor, BB_DIR_USR_BIN, BB_SUID_DROP)) | ||
13 | |||
14 | //kbuild:lib-$(CONFIG_FACTOR) += factor.o | ||
15 | |||
16 | //usage:#define factor_trivial_usage | ||
17 | //usage: "NUMBER..." | ||
18 | //usage:#define factor_full_usage "\n\n" | ||
19 | //usage: "Print prime factors" | ||
20 | |||
21 | #include "libbb.h" | ||
22 | |||
23 | #if ULLONG_MAX == (UINT_MAX * UINT_MAX + 2 * UINT_MAX) | ||
24 | /* "unsigned" is half as wide as ullong */ | ||
25 | typedef unsigned half_t; | ||
26 | #define HALF_FMT "" | ||
27 | #elif ULLONG_MAX == (ULONG_MAX * ULONG_MAX + 2 * ULONG_MAX) | ||
28 | /* long is half as wide as ullong */ | ||
29 | typedef unsigned long half_t; | ||
30 | #define HALF_FMT "l" | ||
31 | #else | ||
32 | #error Cant find an integer type which is half as wide as ullong | ||
33 | #endif | ||
34 | |||
35 | static void factorize(const char *numstr) | ||
36 | { | ||
37 | unsigned long long N, factor2; | ||
38 | half_t factor; | ||
39 | unsigned count3; | ||
40 | |||
41 | /* Coreutils compat */ | ||
42 | numstr = skip_whitespace(numstr); | ||
43 | if (*numstr == '+') | ||
44 | numstr++; | ||
45 | |||
46 | N = bb_strtoull(numstr, NULL, 10); | ||
47 | if (errno) | ||
48 | bb_show_usage(); | ||
49 | |||
50 | printf("%llu:", N); | ||
51 | |||
52 | if (N < 4) | ||
53 | goto end; | ||
54 | while (!(N & 1)) { | ||
55 | printf(" 2"); | ||
56 | N >>= 1; | ||
57 | } | ||
58 | |||
59 | count3 = 3; | ||
60 | factor = 3; | ||
61 | factor2 = 3 * 3; | ||
62 | for (;;) { | ||
63 | unsigned long long nfactor2; | ||
64 | |||
65 | while ((N % factor) == 0) { | ||
66 | N = N / factor; | ||
67 | printf(" %u"HALF_FMT"", factor); | ||
68 | } | ||
69 | next_factor: | ||
70 | /* (f + 2)^2 = f^2 + 4*f + 4 = f^2 + 4*(f+1) */ | ||
71 | nfactor2 = factor2 + 4 * (factor + 1); | ||
72 | if (nfactor2 < factor2) /* overflow? */ | ||
73 | break; | ||
74 | factor2 = nfactor2; | ||
75 | if (factor2 > N) | ||
76 | break; | ||
77 | factor += 2; | ||
78 | /* Rudimentary wheel sieving: skip multiples of 3: | ||
79 | * Every third odd number is divisible by three and thus isn't a prime: | ||
80 | * 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37... | ||
81 | * ^ ^ ^ ^ ^ ^ ^ _ ^ ^ _ ^ (^primes) | ||
82 | */ | ||
83 | --count3; | ||
84 | if (count3 == 0) { | ||
85 | count3 = 3; | ||
86 | goto next_factor; | ||
87 | } | ||
88 | } | ||
89 | end: | ||
90 | if (N > 1) | ||
91 | printf(" %llu", N); | ||
92 | bb_putchar('\n'); | ||
93 | } | ||
94 | |||
95 | int factor_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
96 | int factor_main(int argc UNUSED_PARAM, char **argv) | ||
97 | { | ||
98 | //// coreutils has undocumented option ---debug (three dashes) | ||
99 | //getopt32(argv, ""); | ||
100 | //argv += optind; | ||
101 | argv++; | ||
102 | |||
103 | if (!*argv) | ||
104 | //TODO: read from stdin | ||
105 | bb_show_usage(); | ||
106 | |||
107 | do { | ||
108 | factorize(*argv); | ||
109 | } while (*++argv); | ||
110 | |||
111 | fflush_stdout_and_exit(EXIT_SUCCESS); | ||
112 | } | ||
diff --git a/testsuite/factor.tests b/testsuite/factor.tests new file mode 100755 index 000000000..2cf4a54ce --- /dev/null +++ b/testsuite/factor.tests | |||
@@ -0,0 +1,48 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | # Copyright 2017 by Denys Vlasenko <vda.linux@googlemail.com> | ||
4 | # Licensed under GPLv2, see file LICENSE in this source tree. | ||
5 | |||
6 | . ./testing.sh | ||
7 | |||
8 | # testing "test name" "command" "expected result" "file input" "stdin" | ||
9 | # file input will be file called "input" | ||
10 | # test can create a file "actual" instead of writing to stdout | ||
11 | |||
12 | testing "factor ' 0'" \ | ||
13 | "factor ' 0'" \ | ||
14 | "0:\n" \ | ||
15 | "" "" | ||
16 | testing "factor +1" \ | ||
17 | "factor +1" \ | ||
18 | "1:\n" \ | ||
19 | "" "" | ||
20 | testing "factor ' +2'" \ | ||
21 | "factor ' +2'" \ | ||
22 | "2: 2\n" \ | ||
23 | "" "" | ||
24 | |||
25 | testing "factor 1024" \ | ||
26 | "factor 1024" \ | ||
27 | "1024: 2 2 2 2 2 2 2 2 2 2\n" \ | ||
28 | "" "" | ||
29 | |||
30 | testing "factor 2^61-1" \ | ||
31 | "factor 2305843009213693951" \ | ||
32 | "2305843009213693951: 2305843009213693951\n" \ | ||
33 | "" "" | ||
34 | testing "factor 2^62-1" \ | ||
35 | "factor 4611686018427387903" \ | ||
36 | "4611686018427387903: 3 715827883 2147483647\n" \ | ||
37 | "" "" | ||
38 | testing "factor 2^64-1" \ | ||
39 | "factor 18446744073709551615" \ | ||
40 | "18446744073709551615: 3 5 17 257 641 65537 6700417\n" \ | ||
41 | "" "" | ||
42 | # This is a 60-bit number (0x888 86ff db34 4692): first few primes multiplied together: | ||
43 | testing "factor \$((2*3*5*7*11*13*17*19*23*29*31*37*41*43*47))" \ | ||
44 | "factor \$((2*3*5*7*11*13*17*19*23*29*31*37*41*43*47))" \ | ||
45 | "614889782588491410: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47\n" \ | ||
46 | "" "" | ||
47 | |||
48 | exit $FAILCOUNT | ||