File Coverage

blib/lib/Math/NumSeq/Palindromes.pm
Criterion Covered Total %
statement 76 77 98.7
branch 11 12 91.6
condition 2 3 66.6
subroutine 16 16 100.0
pod 3 3 100.0
total 108 111 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   1079 use 5.004;
  1         3  
26 1     1   4 use strict;
  1         1  
  1         24  
27 1     1   2 use List::Util 'max';
  1         2  
  1         72  
28              
29 1     1   3 use vars '$VERSION', '@ISA';
  1         2  
  1         51  
30             $VERSION = 72;
31              
32 1     1   3 use Math::NumSeq;
  1         1  
  1         13  
33 1     1   4 use Math::NumSeq::Base::IterateIth;
  1         2  
  1         38  
34             @ISA = ('Math::NumSeq::Base::IterateIth',
35             'Math::NumSeq');
36             *_is_infinite = \&Math::NumSeq::_is_infinite;
37              
38 1     1   3 use Math::NumSeq::Repdigits;
  1         1  
  1         34  
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   4 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         3  
47 1     1   4 use constant i_start => 1;
  1         1  
  1         34  
48 1     1   3 use constant values_min => 0;
  1         1  
  1         42  
49 1     1   3 use constant characteristic_increasing => 1;
  1         1  
  1         37  
50 1     1   3 use constant characteristic_integer => 1;
  1         1  
  1         32  
51              
52             use Math::NumSeq::Base::Digits
53 1     1   3 'parameter_info_array'; # radix parameter
  1         1  
  1         293  
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 41 my ($self) = @_;
89 9         18 return $oeis_anum[$self->{'radix'}];
90             }
91              
92             #------------------------------------------------------------------------------
93              
94             sub ith {
95 13113     13113 1 9691 my ($self, $i) = @_;
96             ### Palindrome ith(): $i
97              
98 13113 50       15223 if (_is_infinite($i)) { # don't loop forever if $value is +/-infinity
99 0         0 return undef;
100             }
101              
102 13113         11318 my $radix = $self->{'radix'};
103              
104 13113 100       13956 if ($i < 1) {
105 36         48 return 0;
106             }
107 13077         8402 $i -= 2;
108              
109 13077         8035 my $digits = 1;
110 13077         7850 my $limit = $radix-1;
111 13077         7542 my $add = 1;
112 13077         7482 my $ret;
113 13077         7664 for (;;) {
114 30253 100       32484 if ($i < $limit) {
115             ### first, no low ...
116 9699         6201 $i += $add;
117 9699         7719 $ret = int($i / $radix);
118 9699         6501 last;
119             }
120 20554         12259 $i -= $limit;
121 20554 100       21357 if ($i < $limit) {
122             ### second ...
123 3378         1987 $i += $add;
124 3378         2108 $ret = $i;
125 3378         2246 last;
126             }
127 17176         9878 $i -= $limit;
128 17176         9676 $limit *= $radix;
129 17176         9868 $add *= $radix;
130 17176         9963 $digits++;
131             }
132             ### $limit
133             ### $add
134             ### $i
135             ### $digits
136             ### push under: $ret
137 13077         14393 while ($digits--) {
138 30253         19701 $ret = $ret * $radix + ($i % $radix);
139 30253         43757 $i = int($i / $radix);
140             }
141             ### $ret
142 13077         22756 return $ret;
143             }
144              
145             sub pred {
146 12891     12891 1 31768 my ($self, $value) = @_;
147              
148 12891 100 66     15095 if (_is_infinite($value) # don't loop forever if $value is +/-infinity
149             || $value != int($value)) {
150 6153         5878 return 0;
151             }
152              
153 6738         10204 my @digits = _digit_split_lowtohigh($value, $self->{'radix'});
154 6738         9355 for my $i (0 .. int(@digits/2)-1) {
155 8433 100       11204 if ($digits[$i] != $digits[-1-$i]) {
156 5596         6427 return 0;
157             }
158             }
159 1142         1176 return 1;
160             }
161              
162             1;
163             __END__