File Coverage

blib/lib/Math/NumSeq/PowerFlip.pm
Criterion Covered Total %
statement 79 85 92.9
branch 12 18 66.6
condition 6 8 75.0
subroutine 18 18 100.0
pod 2 2 100.0
total 117 131 89.3


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::PowerFlip;
19 2     2   12840 use 5.004;
  2         8  
  2         89  
20 2     2   12 use strict;
  2         4  
  2         72  
21              
22 2     2   11 use vars '$VERSION', '@ISA';
  2         4  
  2         152  
23             $VERSION = 71;
24              
25 2     2   687 use Math::NumSeq;
  2         7  
  2         54  
26 2     2   545 use Math::NumSeq::Base::IterateIth;
  2         5  
  2         129  
27             @ISA = ('Math::NumSeq::Base::IterateIth',
28             'Math::NumSeq');
29             *_is_infinite = \&Math::NumSeq::_is_infinite;
30             *_to_bigint = \&Math::NumSeq::_to_bigint;
31              
32 2     2   596 use Math::NumSeq::PrimeFactorCount;;
  2         5  
  2         116  
33             *_prime_factors = \&Math::NumSeq::PrimeFactorCount::_prime_factors;
34              
35             # uncomment this to run the ### lines
36             #use Smart::Comments;
37              
38              
39 2     2   10 use constant name => Math::NumSeq::__('Prime Exponent Flip');
  2         1235  
  2         8  
40 2     2   10 use constant description => Math::NumSeq::__('Flip each prime and its exponent, so for example 3^8 -> 8^3');
  2         4  
  2         6  
41 2     2   9 use constant default_i_start => 1;
  2         4  
  2         68  
42 2     2   8 use constant characteristic_increasing => 0;
  2         3  
  2         88  
43 2     2   9 use constant characteristic_non_decreasing => 0;
  2         3  
  2         68  
44 2     2   10 use constant characteristic_integer => 1;
  2         3  
  2         78  
45 2     2   9 use constant characteristic_smaller => 1;
  2         3  
  2         78  
46 2     2   9 use constant values_min => 1; # at i=1
  2         2  
  2         69  
47              
48              
49             #------------------------------------------------------------------------------
50             # cf A005117 squarefrees have all exponents 1 so value=1
51             # A013929 non-squarefrees have some exponent>1 so value>1
52             # A005361 product of exponents of prime factorization
53              
54 2     2   10 use constant oeis_anum => 'A008477';
  2         3  
  2         82  
55              
56             #------------------------------------------------------------------------------
57              
58 2     2   10 use constant 1.02 _UV_LIMIT => 31**2; # is value=2**31
  2         29  
  2         771  
59              
60             sub ith {
61 1079     1079 1 1458 my ($self, $i) = @_;
62             ### PowerFlip ith(): $i
63              
64 1079 50       2188 if (_is_infinite($i)) {
65 0         0 return $i;
66             }
67 1079         1379 $i = abs($i);
68              
69 1079         2482 my ($good, @primes) = _prime_factors($i);
70 1079 50       2056 return undef unless $good;
71              
72 1079 100       1878 if (! @primes) {
73 9         27 return $i; # 0,1 unchanged
74             }
75              
76 1070         1126 my $value = 1;
77 1070         1038 my $log = 0;
78              
79 1070         1008 for (;;) {
80 3280   100     8880 my $p = shift @primes || last;
81 2210         2116 my $count = 1;
82 2210   100     6907 while (@primes && $primes[0] == $p) {
83 788         882 shift @primes;
84 788         2758 $count++;
85             }
86 2210         3574 $log += $p*log($count);
87 2210 50       3852 if ($log > 31) {
88 0         0 $count = _to_bigint($count);
89             }
90 2210         2980 $value *= $count ** $p;
91             }
92 1070         3502 return $value;
93             }
94              
95             sub pred {
96 8     8 1 45 my ($self, $value) = @_;
97             ### PowerFlip pred(): $value
98              
99             # ! is_square_free()
100              
101 8 50 33     38 unless ($value >= 0 && $value <= 0xFFFF_FFFF) {
102 0         0 return undef;
103             }
104 8 50       19 if ($value != int($value)) {
105 0         0 return 0;
106             }
107 8         11 $value = "$value"; # numize Math::BigInt for speed
108              
109 8 100       19 if ($value < 2) {
110 6         13 return 1;
111             }
112              
113 2         5 my $limit = sqrt($value) + 1;
114              
115 2         7 for (my $p = 2; $p <= $limit; $p += 2-($p==2)) {
116 3 100       12 next if ($value % $p);
117             ### prime factor: $p
118 2         4 $value /= $p;
119              
120 2 50       6 if (($value % $p) == 0) {
121             # found a square factor
122 2         5 return 1;
123             }
124              
125 0           $limit = sqrt($value) + 1;
126             ### divided out: "$p, new limit $limit"
127             }
128              
129             ### final: $value
130             # $value now either 1 or a prime, no square factor found
131              
132 0           return 0;
133             }
134              
135             1;
136             __END__