File Coverage

blib/lib/Math/GrahamFunction/SqFacts.pm
Criterion Covered Total %
statement 78 80 97.5
branch 14 16 87.5
condition 7 7 100.0
subroutine 18 18 100.0
pod 8 8 100.0
total 125 129 96.9


line stmt bran cond sub pod time code
1             package Math::GrahamFunction::SqFacts;
2             $Math::GrahamFunction::SqFacts::VERSION = '0.02003';
3 2     2   14 use strict;
  2         5  
  2         61  
4 2     2   12 use warnings;
  2         5  
  2         56  
5              
6              
7 2     2   9 use parent qw(Math::GrahamFunction::Object);
  2         4  
  2         21  
8              
9 2     2   124 use List::Util ();
  2         5  
  2         1471  
10             __PACKAGE__->mk_accessors(qw(n factors));
11              
12             sub _initialize
13             {
14 1771     1771   2546 my $self = shift;
15 1771         2601 my $args = shift;
16              
17 1771 100       3709 if ( $args->{n} )
    50          
18             {
19 844         2230 $self->n( $args->{n} );
20              
21 844         8497 $self->_calc_sq_factors();
22             }
23             elsif ( $args->{factors} )
24             {
25 927         1870 $self->factors( $args->{factors} );
26             }
27             else
28             {
29 0         0 die "factors or n must be supplied.";
30             }
31              
32 1771         10623 return 0;
33             }
34              
35              
36             sub clone
37             {
38 182     182 1 995 my $self = shift;
39 182         270 return __PACKAGE__->new( { 'factors' => [ @{ $self->factors() } ] } );
  182         357  
40             }
41              
42             sub _calc_sq_factors
43             {
44 844     844   1302 my $self = shift;
45              
46 844         1656 $self->factors( $self->_get_sq_facts( $self->n() ) );
47              
48 844         8070 return 0;
49             }
50              
51             my %gsf_cache = ( 1 => [] );
52              
53             sub _get_sq_facts
54             {
55 973     973   7920 my $self = shift;
56 973         1401 my $n = shift;
57              
58 973 100       2665 if ( exists( $gsf_cache{$n} ) )
59             {
60 844         2524 return $gsf_cache{$n};
61             }
62              
63 129   100     424 my $start_from = shift || 2;
64              
65 129         218 for ( my $p = $start_from ; ; ++$p )
66             {
67 1720 100       2997 if ( $n % $p == 0 )
68             {
69             # This function is recursive to make better use of the Memoization
70             # feature.
71 129         354 my $division_factors = $self->_get_sq_facts( ( $n / $p ), $p );
72 129 100 100     477 if ( @$division_factors && ( $division_factors->[0] == $p ) )
73             {
74             return ( $gsf_cache{$n} =
75 29         92 [ @{$division_factors}[ 1 .. $#$division_factors ] ] );
  29         170  
76             }
77             else
78             {
79 100         555 return ( $gsf_cache{$n} = [ $p, @$division_factors ] );
80             }
81             }
82             }
83             }
84              
85             # Removed because it is too slow - we now use our own custom memoization (
86             # or perhaps it is just called caching)
87             # memoize('get_squaring_factors', 'NORMALIZER' => sub { return $_[0]; });
88              
89             # This function multiplies the squaring factors of $n and $m to receive
90             # the squaring factors of ($n*$m)
91              
92             # OOP-Wise, it should be a multi-method, but since we don't inherit this
93             # object it's all-right.
94              
95              
96             sub mult_by
97             {
98 2042     2042 1 30959 my $n_ref = shift;
99 2042         2890 my $m_ref = shift;
100              
101 2042         2788 my @n = @{ $n_ref->factors() };
  2042         3618  
102 2042         18930 my @m = eval { @{ $m_ref->factors() }; };
  2042         2787  
  2042         3827  
103 2042 50       20178 if ($@)
104             {
105 0         0 print "Hello\n";
106             }
107              
108 2042         2881 my @ret = ();
109              
110 2042   100     6546 while ( scalar(@n) && scalar(@m) )
111             {
112 4255 100       8754 if ( $n[0] == $m[0] )
    100          
113             {
114 1836         2590 shift(@n);
115 1836         4358 shift(@m);
116             }
117             elsif ( $n[0] < $m[0] )
118             {
119 1315         4162 push @ret, shift(@n);
120             }
121             else
122             {
123 1104         3691 push @ret, shift(@m);
124             }
125             }
126 2042         3663 push @ret, @n, @m;
127              
128 2042         5493 $n_ref->factors( \@ret );
129              
130             # 0 for success
131 2042         21766 return 0;
132             }
133              
134              
135             sub mult
136             {
137 90     90 1 1471 my $n = shift;
138 90         134 my $m = shift;
139              
140 90         190 my $result = $n->clone();
141 90         247 $result->mult_by($m);
142 90         185 return $result;
143             }
144              
145              
146             sub is_square
147             {
148 1364     1364 1 12111 my $self = shift;
149 1364         2012 return ( scalar( @{ $self->factors() } ) == 0 );
  1364         2447  
150             }
151              
152              
153             sub exists
154             {
155 1949     1949 1 17236 my ( $self, $factor ) = @_;
156              
157 1949     2940   5505 return defined( List::Util::first { $_ == $factor } @{ $self->factors() } );
  2940         25645  
  1949         3804  
158             }
159              
160              
161             sub last
162             {
163 90     90 1 810 my $self = shift;
164              
165 90         193 return $self->factors()->[-1];
166             }
167              
168 2     2   16 use vars qw($a $b);
  2         5  
  2         312  
169              
170              
171             sub product
172             {
173 90     90 1 136 my $self = shift;
174              
175 90     43   273 return ( List::Util::reduce { $a * $b } @{ $self->factors() } );
  43         454  
  90         194  
176             }
177              
178              
179             sub first
180             {
181 600     600 1 5343 my $self = shift;
182              
183 600         1111 return $self->factors()->[0];
184             }
185              
186              
187             1;
188              
189             __END__