File Coverage

blib/lib/Math/NumSeq/DedekindPsiCumulative.pm
Criterion Covered Total %
statement 59 59 100.0
branch 5 6 83.3
condition n/a
subroutine 17 17 100.0
pod 3 3 100.0
total 84 85 98.8


line stmt bran cond sub pod time code
1             # Copyright 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::DedekindPsiCumulative;
19 1     1   4189 use 5.004;
  1         4  
  1         41  
20 1     1   6 use strict;
  1         2  
  1         34  
21 1     1   7 use Math::NumSeq::Primes;
  1         2  
  1         32  
22              
23 1     1   6 use vars '$VERSION', '@ISA';
  1         2  
  1         68  
24             $VERSION = 71;
25              
26 1     1   5 use Math::NumSeq;
  1         2  
  1         33  
27             @ISA = ('Math::NumSeq');
28              
29 1     1   7 use Math::NumSeq::PrimeFactorCount;;
  1         2  
  1         49  
30             *_prime_factors = \&Math::NumSeq::PrimeFactorCount::_prime_factors;
31              
32             # uncomment this to run the ### lines
33             #use Smart::Comments;
34              
35              
36             # use constant name => Math::NumSeq::__('Dedekind Psi Cumulative');
37 1     1   5 use constant description => Math::NumSeq::__('Cumulative Dedekind Psi function.');
  1         2  
  1         5  
38 1     1   5 use constant default_i_start => 1;
  1         2  
  1         49  
39 1     1   5 use constant characteristic_integer => 1;
  1         2  
  1         40  
40 1     1   5 use constant characteristic_increasing => 1;
  1         2  
  1         35  
41 1     1   5 use constant values_min => 1;
  1         1  
  1         49  
42              
43             # A001615 dedekind psi
44             # A019268 dedekind psi first of n steps
45             # A019269 number of steps
46             # A173290 dedekind psi cumulative
47             #
48 1     1   5 use constant oeis_anum => 'A173290';
  1         2  
  1         258  
49              
50             sub rewind {
51 3     3 1 597 my ($self) = @_;
52 3         15 $self->{'i'} = $self->i_start;
53 3         12 $self->{'total'} = 0;
54             }
55              
56             sub next {
57 24     24 1 651 my ($self) = @_;
58              
59 24         46 my $i = $self->{'i'}++;
60 24         52 return ($i,
61             $self->{'total'} += _psi($i));
62             }
63              
64             sub _psi {
65 24     24   29 my ($n) = @_;
66             ### _psi(): $n
67 24         62 my ($good, @primes) = _prime_factors($n);
68 24 50       53 return undef unless $good;
69              
70 24         27 my $prev = 0;
71 24         40 foreach my $p (@primes) {
72 38 100       70 if ($p != $prev) {
73 28         39 $n /= $p;
74 28         36 $n *= $p+1;
75 28         55 $prev = $p;
76             }
77             }
78             ### $n
79 24         75 return $n;
80             }
81              
82             # v1.02 for leading underscore
83 1     1   6 use constant 1.02 _PI => 4*atan2(1,1); # similar to Math::Complex pi()
  1         21  
  1         101  
84              
85             # Enrique Pérez Herrero in the OEIS
86             # value = 15*n^2/(2*Pi^2) + O(n*log(n))
87             #
88             # sqrt(value) = sqrt(15/2)/pi * n
89             # n = sqrt(value) * pi/sqrt(15/2)
90             # with pi/sqrt(15/2) ~= 39/34 for the benefit of Math::BigInt which can't
91             # do BigInt*flonum
92             #
93             # very close even neglecting n*log(n)
94             #
95             sub value_to_i_estimate {
96 21     21 1 757 my ($self, $value) = @_;
97 21 100       45 if ($value <= 1) { return 1; }
  8         20  
98 13         118 return int (sqrt(int($value)) * 39/34);
99             }
100              
101             1;
102             __END__