File Coverage

blib/lib/Math/NumSeq/MobiusFunction.pm
Criterion Covered Total %
statement 68 69 98.5
branch 16 18 88.8
condition 5 8 62.5
subroutine 16 16 100.0
pod 2 2 100.0
total 107 113 94.6


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   7218 use 5.004;
  2         5  
20 2     2   7 use strict;
  2         2  
  2         52  
21 2     2   6 use List::Util 'min','max';
  2         3  
  2         143  
22              
23 2     2   8 use vars '$VERSION','@ISA';
  2         1  
  2         98  
24             $VERSION = 72;
25              
26 2     2   350 use Math::NumSeq;
  2         3  
  2         39  
27 2     2   315 use Math::NumSeq::Base::IterateIth;
  2         2  
  2         76  
28             @ISA = ('Math::NumSeq::Base::IterateIth',
29             'Math::NumSeq');
30             *_is_infinite = \&Math::NumSeq::_is_infinite;
31              
32 2     2   337 use Math::NumSeq::Fibonacci;
  2         3  
  2         87  
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   9 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         2  
  2         6  
41 2     2   7 use constant characteristic_increasing => 0;
  2         2  
  2         70  
42 2     2   7 use constant characteristic_integer => 1;
  2         3  
  2         67  
43 2     2   7 use constant values_min => -1;
  2         1  
  2         67  
44 2     2   7 use constant values_max => 1;
  2         2  
  2         61  
45 2     2   6 use constant default_i_start => 1;
  2         1  
  2         66  
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   6 use constant oeis_anum => 'A008683'; # mobius -1,0,1 starting i=1
  2         2  
  2         433  
54              
55              
56             #------------------------------------------------------------------------------
57              
58             sub ith {
59 114     114 1 102 my ($self, $i) = @_;
60             ### MobiusFunction ith(): $i
61              
62 114         68 my $ret = 0;
63              
64 114 100 66     150 if (_is_infinite($i) || $i < 0) {
65 3         4 return undef;
66             }
67              
68 111 100       158 if (($i % 2) == 0) {
69 58         40 $i /= 2;
70 58 100       74 if (($i % 2) == 0) {
71 25         40 return 0; # square factor
72             }
73 33         26 $ret = 1;
74             }
75              
76 86 50       103 if ($i <= 0xFFFF_FFFF) {
77 86         62 $i = "$i"; # numize Math::BigInt for speed
78             }
79              
80 86         98 my $sqrt = int(sqrt($i));
81 86   50     122 my $limit = min ($sqrt,
82             10_000 / (_blog2_estimate($i) || 1));
83             ### $sqrt
84             ### $limit
85              
86 86         129 for (my $p = 3; $p <= $limit; $p += 2) {
87 34 100       56 if (($i % $p) == 0) {
88 14         11 $i /= $p;
89 14 100       16 if (($i % $p) == 0) {
90             ### square factor, zero ...
91 8         13 return 0;
92             }
93 6         5 $ret ^= 1;
94 6         4 $sqrt = int(sqrt($i)); # new smaller limit
95 6         12 $limit = min ($sqrt, $limit);
96             ### factor: "$p new ret $ret new limit $limit"
97             }
98             }
99 78 50       88 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       97 if ($i != 1) {
105 62         42 $ret ^= 1;
106             }
107 78 100       154 return ($ret ? -1 : 1);
108             }
109              
110             sub pred {
111 6     6 1 20 my ($self, $value) = @_;
112 6   66     23 return ($value == 0 || $value == 1 || $value == -1);
113             }
114              
115             1;
116             __END__