File Coverage

blib/lib/Math/NumSeq/HappyNumbers.pm
Criterion Covered Total %
statement 50 50 100.0
branch 6 6 100.0
condition 4 6 66.6
subroutine 14 14 100.0
pod 2 2 100.0
total 76 78 97.4


line stmt bran cond sub pod time code
1             # Copyright 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             package Math::NumSeq::HappyNumbers;
19 1     1   3192 use 5.004;
  1         4  
  1         52  
20 1     1   16 use strict;
  1         2  
  1         46  
21 1     1   6 use List::Util 'sum';
  1         2  
  1         100  
22              
23 1     1   7 use vars '$VERSION', '@ISA';
  1         1  
  1         84  
24             $VERSION = 71;
25              
26 1     1   6 use Math::NumSeq;
  1         2  
  1         21  
27 1     1   6 use Math::NumSeq::Base::IteratePred;
  1         2  
  1         67  
28             @ISA = ('Math::NumSeq::Base::IteratePred',
29             'Math::NumSeq');
30             *_is_infinite = \&Math::NumSeq::_is_infinite;
31              
32 1     1   5 use Math::NumSeq::Repdigits;
  1         3  
  1         153  
33             *_digit_split_lowtohigh = \&Math::NumSeq::Repdigits::_digit_split_lowtohigh;
34              
35             # uncomment this to run the ### lines
36             # use Smart::Comments;
37              
38              
39             # use constant name => Math::NumSeq::__('Happy Numbers');
40 1     1   7 use constant description => Math::NumSeq::__('Happy numbers 1,7,10,13,19,23,etc, reaching 1 under iterating sum of squares of digits.');
  1         2  
  1         7  
41 1     1   6 use constant default_i_start => 1;
  1         2  
  1         44  
42 1     1   6 use constant values_min => 1;
  1         2  
  1         68  
43              
44             use Math::NumSeq::Base::Digits
45 1     1   6 'parameter_info_array'; # radix parameter
  1         3  
  1         337  
46              
47             #------------------------------------------------------------------------------
48             # cf A035497 happy primes, happy numbers which are prime
49             # A003621 how many steps to reach 1 or 4
50             # A090425 how many steps for just the happy numbers
51             # A031176 period of final cycle, being 1 or 8 in decimal
52             #
53             # A000216 start 2 the cycle 4,16,37,58,89,145,42,20
54             # A000218 start 3
55             # A080709 start 4
56             # A000221 start 5
57             # A008460 start 6
58             # A008462 start 8
59             # A008463 start 9
60             # A139566 start 15
61             # A122065 start 74169
62             #
63             my @oeis_anum;
64             $oeis_anum[2] = 'A000027'; # 1,2,3,4, everything happy in base 2
65             # OEIS-Other: A000027 radix=2
66              
67             $oeis_anum[4] = 'A000027'; # 1,2,3,4, everything happy in base 4
68             # OEIS-Other: A000027 radix=4
69              
70             $oeis_anum[10] = 'A007770';
71             # OEIS-Catalogue: A007770 radix=10
72              
73             sub oeis_anum {
74 1     1 1 6 my ($self) = @_;
75 1         4 return $oeis_anum[$self->{'radix'}];
76             }
77              
78             #------------------------------------------------------------------------------
79              
80             sub pred {
81 97     97 1 430 my ($self, $value) = @_;
82             ### HappyNumbers pred(): $value
83 97 100 66     630 if ($value <= 0
      66        
84             || $value != int($value)
85             || _is_infinite($value)) {
86 22         59 return 0;
87             }
88 75         186 my $radix = $self->{'radix'};
89 75         90 my %seen;
90 75         90 for (;;) {
91             ### $value
92 732 100       1972 if ($value == 1) {
93 24         107 return 1;
94             }
95 708 100       1701 if ($seen{$value}) {
96 51         425 return 0; # inf loop
97             }
98 657         1355 $seen{$value} = 1;
99 657         1393 $value = _sum_of_squares_of_digits($value,$radix);
100             }
101             }
102             sub _sum_of_squares_of_digits {
103 657     657   4370 my ($n, $radix) = @_;
104 657         3327 return sum (map {$_ * $_} _digit_split_lowtohigh($n,$radix));
  1285         3369  
105             }
106              
107             1;
108             __END__