File Coverage

blib/lib/Math/NumSeq/MobiusFunction.pm
Criterion Covered Total %
statement 69 70 98.5
branch 16 18 88.8
condition 5 8 62.5
subroutine 16 16 100.0
pod 2 2 100.0
total 108 114 94.7


line stmt bran cond sub pod time code
1             # Copyright 2010, 2011, 2012, 2013, 2014 Kevin Ryde
2              
3             # This file is part of Math-NumSeq.
4             #
5             # Math-NumSeq is free software; you can redistribute it and/or modify
6             # it under the terms of the GNU General Public License as published by the
7             # Free Software Foundation; either version 3, or (at your option) any later
8             # version.
9             #
10             # Math-NumSeq is distributed in the hope that it will be useful, but
11             # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12             # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13             # for more details.
14             #
15             # You should have received a copy of the GNU General Public License along
16             # with Math-NumSeq. If not, see .
17              
18             package Math::NumSeq::MobiusFunction;
19 2     2   14467 use 5.004;
  2         9  
  2         97  
20 2     2   12 use strict;
  2         5  
  2         79  
21 2     2   12 use List::Util 'min','max';
  2         4  
  2         235  
22              
23 2     2   13 use vars '$VERSION','@ISA';
  2         5  
  2         140  
24             $VERSION = 71;
25              
26 2     2   613 use Math::NumSeq;
  2         6  
  2         51  
27 2     2   556 use Math::NumSeq::Base::IterateIth;
  2         4  
  2         106  
28             @ISA = ('Math::NumSeq::Base::IterateIth',
29             'Math::NumSeq');
30             *_is_infinite = \&Math::NumSeq::_is_infinite;
31              
32 2     2   925 use Math::NumSeq::Fibonacci;
  2         6  
  2         111  
33             *_blog2_estimate = \&Math::NumSeq::Fibonacci::_blog2_estimate;
34              
35             # uncomment this to run the ### lines
36             #use Smart::Comments;
37              
38              
39             # use constant name => Math::NumSeq::__('Mobius Function');
40 2     2   12 use constant description => Math::NumSeq::__('The Mobius function, being 1 for an even number of prime factors, -1 for an odd number, or 0 if any repeated factors (ie. not square-free).');
  2         3  
  2         9  
41 2     2   11 use constant characteristic_increasing => 0;
  2         12  
  2         94  
42 2     2   12 use constant characteristic_integer => 1;
  2         4  
  2         123  
43 2     2   12 use constant values_min => -1;
  2         4  
  2         91  
44 2     2   10 use constant values_max => 1;
  2         5  
  2         91  
45 2     2   18 use constant default_i_start => 1;
  2         4  
  2         99  
46              
47             #------------------------------------------------------------------------------
48             # cf A030059 the -1 positions, being odd number of distinct primes
49             # A030229 the 1 positions, being even number of distinct primes
50             # A013929 the 0 positions, being square factor, ie. the non-square-frees
51             # A005117 square free numbers, mobius -1 or +1
52             #
53 2     2   10 use constant oeis_anum => 'A008683'; # mobius -1,0,1 starting i=1
  2         5  
  2         703  
54              
55              
56             #------------------------------------------------------------------------------
57              
58             sub ith {
59 114     114 1 210 my ($self, $i) = @_;
60             ### MobiusFunction ith(): $i
61              
62 114         152 my $ret = 0;
63              
64 114 100 66     244 if (_is_infinite($i) || $i < 0) {
65 3         8 return undef;
66             }
67              
68 111 100       274 if (($i % 2) == 0) {
69 58         66 $i /= 2;
70 58 100       118 if (($i % 2) == 0) {
71 25         81 return 0; # square factor
72             }
73 33         49 $ret = 1;
74             }
75              
76 86 50       152 if ($i <= 0xFFFF_FFFF) {
77 86         120 $i = "$i"; # numize Math::BigInt for speed
78             }
79              
80 86         154 my $sqrt = int(sqrt($i));
81 86   50     218 my $limit = min ($sqrt,
82             10_000 / (_blog2_estimate($i) || 1));
83             ### $sqrt
84             ### $limit
85              
86 86         421 for (my $p = 3; $p <= $limit; $p += 2) {
87 34 100       97 if (($i % $p) == 0) {
88 14         16 $i /= $p;
89 14 100       28 if (($i % $p) == 0) {
90             ### square factor, zero ...
91 8         29 return 0;
92             }
93 6         7 $ret ^= 1;
94 6         11 $sqrt = int(sqrt($i)); # new smaller limit
95 6         20 $limit = min ($sqrt, $limit);
96             ### factor: "$p new ret $ret new limit $limit"
97             }
98             }
99 78 50       146 if ($sqrt > $limit) {
100             ### not all factors found up to limit ...
101             # ENHANCE-ME: prime_factors() here if <2^32
102 0         0 return undef;
103             }
104 78 100       4719 if ($i != 1) {
105 62         76 $ret ^= 1;
106             }
107 78 100       282 return ($ret ? -1 : 1);
108             }
109              
110             sub pred {
111 6     6 1 36 my ($self, $value) = @_;
112 6   66     34 return ($value == 0 || $value == 1 || $value == -1);
113             }
114              
115             1;
116             __END__