File Coverage

blib/lib/Math/NumSeq/Palindromes.pm
Criterion Covered Total %
statement 77 78 98.7
branch 11 12 91.6
condition 2 3 66.6
subroutine 16 16 100.0
pod 3 3 100.0
total 109 112 97.3


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              
19             # cf A206913 next binary palindrome <= n value_floor
20             # A206914 next binary palindrome >= n value_ceil
21             # A206920 sum first n binary palindromes
22              
23              
24             package Math::NumSeq::Palindromes;
25 1     1   3095 use 5.004;
  1         4  
  1         55  
26 1     1   8 use strict;
  1         2  
  1         41  
27 1     1   6 use List::Util 'max';
  1         2  
  1         87  
28              
29 1     1   6 use vars '$VERSION', '@ISA';
  1         2  
  1         82  
30             $VERSION = 71;
31              
32 1     1   6 use Math::NumSeq;
  1         2  
  1         22  
33 1     1   6 use Math::NumSeq::Base::IterateIth;
  1         2  
  1         56  
34             @ISA = ('Math::NumSeq::Base::IterateIth',
35             'Math::NumSeq');
36             *_is_infinite = \&Math::NumSeq::_is_infinite;
37              
38 1     1   6 use Math::NumSeq::Repdigits;
  1         3  
  1         52  
39             *_digit_split_lowtohigh = \&Math::NumSeq::Repdigits::_digit_split_lowtohigh;
40              
41             # uncomment this to run the ### lines
42             #use Smart::Comments;
43              
44              
45             # use constant name => Math::NumSeq::__('Palindromes');
46 1     1   6 use constant description => Math::NumSeq::__('Numbers which are "palindromes" reading the same backwards or forwards, like 153351. Default is decimal, or select a radix.');
  1         2  
  1         7  
47 1     1   5 use constant i_start => 1;
  1         3  
  1         39  
48 1     1   5 use constant values_min => 0;
  1         3  
  1         54  
49 1     1   6 use constant characteristic_increasing => 1;
  1         2  
  1         49  
50 1     1   6 use constant characteristic_integer => 1;
  1         2  
  1         40  
51              
52             use Math::NumSeq::Base::Digits
53 1     1   12 'parameter_info_array'; # radix parameter
  1         3  
  1         426  
54              
55              
56             #------------------------------------------------------------------------------
57             # cf A002385 - prime palindromes
58             # A029732 - prime palindromes in base 16, written in base 10
59             # A110784 - palindrom and digits in ascending order
60             # A029731 - palindromes in both decimal and hexadecimal
61             # A029733 - n where n^2 hex palindrome
62             # A029734 - squares which are hex palindromes
63             # A016038 - not palindrome in any base, up to n-2
64             # A057891 - not a binary palindrome, including if trailing 0-bits stripped
65              
66             my @oeis_anum = (
67             # OEIS-Catalogue array begin
68             undef, # 0
69             undef, # 1
70             'A006995', # radix=2
71             'A014190', # radix=3
72             'A014192', # radix=4
73             'A029952', # radix=5
74             'A029953', # radix=6
75             'A029954', # radix=7
76             'A029803', # radix=8
77             'A029955', # radix=9
78             'A002113', #
79             'A029956', # radix=11
80             'A029957', # radix=12
81             'A029958', # radix=13
82             'A029959', # radix=14
83             'A029960', # radix=15
84             'A029730', # radix=16
85             # OEIS-Catalogue array end
86             );
87             sub oeis_anum {
88 9     9 1 50 my ($self) = @_;
89 9         33 return $oeis_anum[$self->{'radix'}];
90             }
91              
92             #------------------------------------------------------------------------------
93              
94             sub ith {
95 13113     13113 1 20712 my ($self, $i) = @_;
96             ### Palindrome ith(): $i
97              
98 13113 50       30849 if (_is_infinite($i)) { # don't loop forever if $value is +/-infinity
99 0         0 return undef;
100             }
101              
102 13113         26716 my $radix = $self->{'radix'};
103              
104 13113 100       25171 if ($i < 1) {
105 36         87 return 0;
106             }
107 13077         18412 $i -= 2;
108              
109 13077         15282 my $digits = 1;
110 13077         16724 my $limit = $radix-1;
111 13077         15489 my $add = 1;
112 13077         26570 my $ret;
113 13077         29564 for (;;) {
114 30253 100       56371 if ($i < $limit) {
115             ### first, no low ...
116 9699         10887 $i += $add;
117 9699         13768 $ret = int($i / $radix);
118 9699         12813 last;
119             }
120 20554         26006 $i -= $limit;
121 20554 100       43469 if ($i < $limit) {
122             ### second ...
123 3378         5108 $i += $add;
124 3378         4524 $ret = $i;
125 3378         4520 last;
126             }
127 17176         25306 $i -= $limit;
128 17176         21116 $limit *= $radix;
129 17176         17688 $add *= $radix;
130 17176         21064 $digits++;
131             }
132             ### $limit
133             ### $add
134             ### $i
135             ### $digits
136             ### push under: $ret
137 13077         26662 while ($digits--) {
138 30253         37569 $ret = $ret * $radix + ($i % $radix);
139 30253         67297 $i = int($i / $radix);
140             }
141             ### $ret
142 13077         58413 return $ret;
143             }
144              
145             sub pred {
146 12891     12891 1 72092 my ($self, $value) = @_;
147              
148 12891 100 66     29245 if (_is_infinite($value) # don't loop forever if $value is +/-infinity
149             || $value != int($value)) {
150 6153         13527 return 0;
151             }
152              
153 6738         22411 my @digits = _digit_split_lowtohigh($value, $self->{'radix'});
154 6738         18319 for my $i (0 .. int(@digits/2)-1) {
155 8433 100       21389 if ($digits[$i] != $digits[-1-$i]) {
156 5596         13953 return 0;
157             }
158             }
159 1142         4413 return 1;
160             }
161              
162             1;
163             __END__