| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
############################################################################# |
|
2
|
|
|
|
|
|
|
# Math/Big/Factors.pm -- factor big numbers into prime factors |
|
3
|
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package Math::Big::Factors; |
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
require 5.006002; # requires this Perl version or later |
|
7
|
|
|
|
|
|
|
|
|
8
|
2
|
|
|
2
|
|
67532
|
use strict; |
|
|
2
|
|
|
|
|
8
|
|
|
|
2
|
|
|
|
|
63
|
|
|
9
|
2
|
|
|
2
|
|
11
|
use warnings; |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
83
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
2
|
|
|
2
|
|
11
|
use Math::BigInt; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
11
|
|
|
12
|
2
|
|
|
2
|
|
1192
|
use Math::BigFloat; |
|
|
2
|
|
|
|
|
30460
|
|
|
|
2
|
|
|
|
|
9
|
|
|
13
|
2
|
|
|
2
|
|
1151
|
use Math::Big; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
90
|
|
|
14
|
2
|
|
|
2
|
|
13
|
use Exporter; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
1768
|
|
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
our $VERSION = '1.15'; |
|
17
|
|
|
|
|
|
|
our @ISA = qw( Exporter ); |
|
18
|
|
|
|
|
|
|
our @EXPORT_OK = qw( wheel factors_wheel |
|
19
|
|
|
|
|
|
|
); |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
sub wheel |
|
22
|
|
|
|
|
|
|
{ |
|
23
|
|
|
|
|
|
|
# calculate a prime-wheel of order $o |
|
24
|
12
|
|
50
|
12
|
1
|
1230
|
my $o = abs(shift || 1); # >= 1 |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# some primitive wheels as shortcut: |
|
27
|
12
|
100
|
|
|
|
32
|
return [ Math::BigInt->new(2), Math::BigInt->new(1) ] if $o == 1; |
|
28
|
|
|
|
|
|
|
|
|
29
|
9
|
|
|
|
|
41
|
my @primes = Math::Big::primes($o*5); # initial primes, get some more |
|
30
|
|
|
|
|
|
|
|
|
31
|
9
|
|
|
|
|
326
|
my $mul = Math::BigInt->new(1); my @wheel; |
|
|
9
|
|
|
|
|
322
|
|
|
32
|
9
|
|
|
|
|
24
|
for (my $i = 0; $i < $o; $i++) |
|
33
|
|
|
|
|
|
|
{ |
|
34
|
|
|
|
|
|
|
#print "$primes[$i]\n"; |
|
35
|
27
|
|
|
|
|
63
|
$mul *= $primes[$i]; push @wheel,$primes[$i]; |
|
|
27
|
|
|
|
|
1528
|
|
|
36
|
|
|
|
|
|
|
} |
|
37
|
|
|
|
|
|
|
#print "Mul $mul\n"; |
|
38
|
9
|
|
|
|
|
16
|
my $last = $wheel[-1]; # get biggest initial |
|
39
|
|
|
|
|
|
|
#print "last is $last\n"; |
|
40
|
|
|
|
|
|
|
# now sieve any number that is a multiply of one of the inital ones |
|
41
|
9
|
|
|
|
|
31
|
@primes = (); # undef => leftover |
|
42
|
9
|
|
|
|
|
17
|
foreach (@wheel) |
|
43
|
|
|
|
|
|
|
{ |
|
44
|
27
|
100
|
|
|
|
1766
|
next if $_ == 2; # dont mark these, we skip 'em |
|
45
|
18
|
|
|
|
|
1832
|
my $i = $_; my $add = $i; |
|
|
18
|
|
|
|
|
26
|
|
|
46
|
18
|
|
|
|
|
41
|
while ($i < $mul) |
|
47
|
|
|
|
|
|
|
{ |
|
48
|
462
|
|
|
|
|
37719
|
$primes[$i] = 1; $i += $add; |
|
|
462
|
|
|
|
|
10452
|
|
|
49
|
|
|
|
|
|
|
} |
|
50
|
|
|
|
|
|
|
} |
|
51
|
9
|
|
|
|
|
863
|
push @wheel, Math::BigInt->new(1); |
|
52
|
9
|
|
|
|
|
350
|
my $i = $last; |
|
53
|
9
|
|
|
|
|
22
|
while ($i < $mul) |
|
54
|
|
|
|
|
|
|
{ |
|
55
|
351
|
100
|
|
|
|
57935
|
push @wheel,$i if !defined $primes[$i]; $i += 2; # skip even ones |
|
|
351
|
|
|
|
|
8571
|
|
|
56
|
|
|
|
|
|
|
} |
|
57
|
9
|
|
|
|
|
1690
|
\@wheel; |
|
58
|
|
|
|
|
|
|
} |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
sub _transform_wheel |
|
61
|
|
|
|
|
|
|
{ |
|
62
|
|
|
|
|
|
|
# from a given prime-wheel, calculate a increment table that can be used |
|
63
|
|
|
|
|
|
|
# to step trough numbers |
|
64
|
|
|
|
|
|
|
# input: ref to array with prime wheel |
|
65
|
|
|
|
|
|
|
# output: ($restart,$ref_to_add_table); |
|
66
|
|
|
|
|
|
|
|
|
67
|
8
|
|
|
8
|
|
16
|
my (@wheel); |
|
68
|
8
|
|
|
|
|
13
|
my $add = shift; shift @$add; # remove the first 2 from wheel |
|
|
8
|
|
|
|
|
14
|
|
|
69
|
|
|
|
|
|
|
|
|
70
|
8
|
100
|
|
|
|
29
|
if (@$add == 1) # order 1 |
|
71
|
|
|
|
|
|
|
{ |
|
72
|
2
|
|
|
|
|
7
|
my $two = Math::BigInt->new(2); |
|
73
|
|
|
|
|
|
|
# (2,2) or (2,2,2,2,2,2) etc would do, too |
|
74
|
2
|
|
|
|
|
70
|
@wheel = ($two->copy(),$two->copy(),$two->copy(),$two->copy()); |
|
75
|
2
|
|
|
|
|
138
|
return (1,\@wheel); |
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
# from the list of divisors above create a add-table which we can take to |
|
78
|
|
|
|
|
|
|
# increment from 3 onwards. The tabe consists of two parts, the second part |
|
79
|
|
|
|
|
|
|
# will be repeatedly used |
|
80
|
6
|
|
|
|
|
13
|
my $last = -1; my $mod = 2; my $i = 0; |
|
|
6
|
|
|
|
|
9
|
|
|
|
6
|
|
|
|
|
10
|
|
|
81
|
|
|
|
|
|
|
# create the increment part for the initial primes (3,5, or 3,5,7 etc) |
|
82
|
6
|
|
|
|
|
16
|
while ($add->[$i] != 1) |
|
83
|
|
|
|
|
|
|
{ |
|
84
|
12
|
|
|
|
|
1258
|
$mod *= $add->[$i]; |
|
85
|
12
|
100
|
|
|
|
1268
|
push @wheel, $add->[$i] - $last if $last != -1; # skip the first |
|
86
|
|
|
|
|
|
|
#print $wheel[-1],"\n" if $last != -1; |
|
87
|
12
|
|
|
|
|
1303
|
$last = $add->[$i]; $i++; |
|
|
12
|
|
|
|
|
34
|
|
|
88
|
|
|
|
|
|
|
} |
|
89
|
|
|
|
|
|
|
#print "mod $mod\n"; |
|
90
|
6
|
|
|
|
|
601
|
my $border = $i-1; # account for ++ |
|
91
|
6
|
|
|
|
|
11
|
my $length = scalar @$add-$i; |
|
92
|
6
|
|
|
|
|
11
|
my $ws = $border+$length; # remember this |
|
93
|
|
|
|
|
|
|
#print "border: $border length $length $mod\n"; |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# now we add two arrays in a row, both are equal except the first element |
|
96
|
|
|
|
|
|
|
# which is in case A a step from the last inital prime to the second in list |
|
97
|
|
|
|
|
|
|
# and in case B a step from '1' to the second in list |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
#print "add[border+1]: ",$add->[$border+1]," add[border] $add->[$border]\n"; |
|
100
|
6
|
|
|
|
|
22
|
$wheel[$border] = $add->[$border+2]-$add->[$border]; |
|
101
|
6
|
|
|
|
|
714
|
$wheel[$border+$length] = $add->[$border+2]-1; |
|
102
|
|
|
|
|
|
|
# and last add a wrap-around around $mod |
|
103
|
|
|
|
|
|
|
#print "last: ",$add->[-1],"\n"; |
|
104
|
6
|
|
|
|
|
1134
|
$wheel[$border+$length-1] = 1+$mod-$add->[-1]; |
|
105
|
6
|
|
|
|
|
1557
|
$wheel[$border+$length*2-1] = $wheel[$border+$length-1]; |
|
106
|
|
|
|
|
|
|
|
|
107
|
6
|
|
|
|
|
13
|
$i = $border + 1; |
|
108
|
|
|
|
|
|
|
# now fill in the rest |
|
109
|
6
|
|
|
|
|
19
|
while ($i < $length+$border-1) |
|
110
|
|
|
|
|
|
|
{ |
|
111
|
104
|
|
|
|
|
232
|
$wheel[$i] = $add->[$i+2]-$add->[$i+1]; |
|
112
|
104
|
|
|
|
|
11954
|
$wheel[$i+$length] = $wheel[$i]; |
|
113
|
104
|
|
|
|
|
218
|
$i++; |
|
114
|
|
|
|
|
|
|
} |
|
115
|
6
|
|
|
|
|
26
|
($ws,\@wheel); |
|
116
|
|
|
|
|
|
|
} |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub factors_wheel |
|
119
|
|
|
|
|
|
|
{ |
|
120
|
24
|
|
|
24
|
1
|
7092
|
my $n = shift; |
|
121
|
24
|
|
50
|
|
|
75
|
my $o = abs(shift || 1); |
|
122
|
|
|
|
|
|
|
|
|
123
|
24
|
50
|
|
|
|
101
|
$n = Math::BigInt->new($n) unless ref $n; |
|
124
|
24
|
|
|
|
|
1355
|
my $two = Math::BigInt->new(2); |
|
125
|
24
|
|
|
|
|
832
|
my $three = Math::BigInt->new(3); |
|
126
|
|
|
|
|
|
|
|
|
127
|
24
|
|
|
|
|
819
|
my @factors = (); |
|
128
|
24
|
|
|
|
|
61
|
my $x = $n->copy(); |
|
129
|
|
|
|
|
|
|
|
|
130
|
24
|
100
|
|
|
|
571
|
return ($x) if $x < 4; |
|
131
|
8
|
|
|
|
|
836
|
my ($i,$y,$w,$div,$rem); |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
#print "Using a wheel of order $o, length "; |
|
134
|
8
|
|
|
|
|
21
|
my $wheel = wheel($o); |
|
135
|
|
|
|
|
|
|
#print scalar @$wheel,":\n"; |
|
136
|
8
|
|
|
|
|
156
|
my ($ws,$add) = _transform_wheel($wheel); undef $wheel; |
|
|
8
|
|
|
|
|
63
|
|
|
137
|
8
|
|
|
|
|
19
|
my $we = scalar @$add - 1; |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
# reduce to odd number (after that, no odd left-over divisior will ocur) |
|
140
|
8
|
|
66
|
|
|
28
|
while (($x->is_even) && (!$x->is_zero)) |
|
141
|
|
|
|
|
|
|
{ |
|
142
|
4
|
|
|
|
|
107
|
push @factors, $two->copy(); |
|
143
|
|
|
|
|
|
|
#print "factoring $x (",$x->length(),")\n"; |
|
144
|
|
|
|
|
|
|
#print "2\n"; |
|
145
|
4
|
|
|
|
|
84
|
$x /= $two; |
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
# 8 => 6 => 3, 7, 6 => 3, 5, 4 => 2 => 1, 3, 2 => 1, are all prime |
|
148
|
|
|
|
|
|
|
# so the first number interesting for us is 9 |
|
149
|
|
|
|
|
|
|
#my $op = 0; |
|
150
|
|
|
|
|
|
|
OUTER: |
|
151
|
8
|
|
|
|
|
721
|
while ($x > 8) |
|
152
|
|
|
|
|
|
|
{ |
|
153
|
|
|
|
|
|
|
#print "factoring $x (",$x->length(),")\n"; |
|
154
|
8
|
|
|
|
|
895
|
$i = $three; $w = 0; |
|
|
8
|
|
|
|
|
13
|
|
|
155
|
8
|
|
|
|
|
21
|
while ($i < $x) # should be sqrt() |
|
156
|
|
|
|
|
|
|
{ |
|
157
|
|
|
|
|
|
|
# $steps++; |
|
158
|
|
|
|
|
|
|
# $op = 0, print "$i\r" if $op++ == 1024; |
|
159
|
8
|
|
|
|
|
236
|
$y = $x->copy(); |
|
160
|
8
|
|
|
|
|
169
|
($div,$rem) = $y->bdiv($i); |
|
161
|
8
|
50
|
|
|
|
1508
|
if ($rem == 0) |
|
162
|
|
|
|
|
|
|
{ |
|
163
|
|
|
|
|
|
|
#print "$i\n"; |
|
164
|
8
|
|
|
|
|
1392
|
push @factors,$i; |
|
165
|
8
|
|
|
|
|
19
|
$x = $div; next OUTER; |
|
|
8
|
|
|
|
|
30
|
|
|
166
|
|
|
|
|
|
|
} |
|
167
|
|
|
|
|
|
|
#print "$i + ",$add->[$w]," ($w)\n"; |
|
168
|
|
|
|
|
|
|
#$i += 2; # trial div by odd numbers |
|
169
|
0
|
|
|
|
|
0
|
$i += $add->[$w]; |
|
170
|
|
|
|
|
|
|
#print "restart $w $ws\n" if $w == $we; # wheel of 2,3,5,7... |
|
171
|
0
|
0
|
|
|
|
0
|
$w = $ws if $w++ == $we; # wheel of 2,3,5,7... |
|
172
|
|
|
|
|
|
|
#exit if $i > 100000; |
|
173
|
|
|
|
|
|
|
} |
|
174
|
0
|
|
|
|
|
0
|
last; |
|
175
|
|
|
|
|
|
|
} |
|
176
|
8
|
50
|
33
|
|
|
814
|
push @factors,$x if $x != 1 || $n == 1; |
|
177
|
8
|
|
|
|
|
950
|
@factors; |
|
178
|
|
|
|
|
|
|
} |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
sub _factor |
|
181
|
|
|
|
0
|
|
|
{ |
|
182
|
|
|
|
|
|
|
# later: factor ( n => $n, algorithmn => 'wheel', order => 3 ); |
|
183
|
|
|
|
|
|
|
} |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
1; |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
__END__ |