File Coverage

blib/lib/Math/NumSeq/DedekindPsiCumulative.pm
Criterion Covered Total %
statement 58 58 100.0
branch 5 6 83.3
condition n/a
subroutine 17 17 100.0
pod 3 3 100.0
total 83 84 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   1507 use 5.004;
  1         3  
20 1     1   4 use strict;
  1         2  
  1         24  
21 1     1   4 use Math::NumSeq::Primes;
  1         1  
  1         21  
22              
23 1     1   3 use vars '$VERSION', '@ISA';
  1         1  
  1         59  
24             $VERSION = 72;
25              
26 1     1   4 use Math::NumSeq;
  1         1  
  1         26  
27             @ISA = ('Math::NumSeq');
28              
29 1     1   4 use Math::NumSeq::PrimeFactorCount;;
  1         1  
  1         38  
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   3 use constant description => Math::NumSeq::__('Cumulative Dedekind Psi function.');
  1         1  
  1         4  
38 1     1   3 use constant default_i_start => 1;
  1         2  
  1         36  
39 1     1   4 use constant characteristic_integer => 1;
  1         1  
  1         31  
40 1     1   3 use constant characteristic_increasing => 1;
  1         1  
  1         35  
41 1     1   2 use constant values_min => 1;
  1         1  
  1         32  
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   3 use constant oeis_anum => 'A173290';
  1         1  
  1         250  
49              
50             sub rewind {
51 3     3 1 370 my ($self) = @_;
52 3         11 $self->{'i'} = $self->i_start;
53 3         7 $self->{'total'} = 0;
54             }
55              
56             sub next {
57 24     24 1 381 my ($self) = @_;
58              
59 24         20 my $i = $self->{'i'}++;
60             return ($i,
61 24         24 $self->{'total'} += _psi($i));
62             }
63              
64             sub _psi {
65 24     24   15 my ($n) = @_;
66             ### _psi(): $n
67 24         32 my ($good, @primes) = _prime_factors($n);
68 24 50       27 return undef unless $good;
69              
70 24         18 my $prev = 0;
71 24         21 foreach my $p (@primes) {
72 38 100       44 if ($p != $prev) {
73 28         19 $n /= $p;
74 28         22 $n *= $p+1;
75 28         23 $prev = $p;
76             }
77             }
78             ### $n
79 24         35 return $n;
80             }
81              
82             # v1.02 for leading underscore
83 1     1   4 use constant 1.02 _PI => 4*atan2(1,1); # similar to Math::Complex pi()
  1         13  
  1         86  
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 501 my ($self, $value) = @_;
97 21 100       26 if ($value <= 1) { return 1; }
  8         7  
98 13         70 return int (sqrt(int($value)) * 39/34);
99             }
100              
101             1;
102             __END__