File Coverage

blib/lib/Math/NumSeq/HappyNumbers.pm
Criterion Covered Total %
statement 49 49 100.0
branch 6 6 100.0
condition 4 6 66.6
subroutine 14 14 100.0
pod 2 2 100.0
total 75 77 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   1063 use 5.004;
  1         9  
20 1     1   4 use strict;
  1         2  
  1         24  
21 1     1   3 use List::Util 'sum';
  1         1  
  1         71  
22              
23 1     1   6 use vars '$VERSION', '@ISA';
  1         2  
  1         61  
24             $VERSION = 72;
25              
26 1     1   4 use Math::NumSeq;
  1         1  
  1         17  
27 1     1   3 use Math::NumSeq::Base::IteratePred;
  1         2  
  1         35  
28             @ISA = ('Math::NumSeq::Base::IteratePred',
29             'Math::NumSeq');
30             *_is_infinite = \&Math::NumSeq::_is_infinite;
31              
32 1     1   3 use Math::NumSeq::Repdigits;
  1         1  
  1         34  
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   3 use constant description => Math::NumSeq::__('Happy numbers 1,7,10,13,19,23,etc, reaching 1 under iterating sum of squares of digits.');
  1         1  
  1         3  
41 1     1   4 use constant default_i_start => 1;
  1         0  
  1         34  
42 1     1   3 use constant values_min => 1;
  1         2  
  1         38  
43              
44             use Math::NumSeq::Base::Digits
45 1     1   5 'parameter_info_array'; # radix parameter
  1         2  
  1         218  
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 3 my ($self) = @_;
75 1         2 return $oeis_anum[$self->{'radix'}];
76             }
77              
78             #------------------------------------------------------------------------------
79              
80             sub pred {
81 97     97 1 203 my ($self, $value) = @_;
82             ### HappyNumbers pred(): $value
83 97 100 66     360 if ($value <= 0
      66        
84             || $value != int($value)
85             || _is_infinite($value)) {
86 22         24 return 0;
87             }
88 75         81 my $radix = $self->{'radix'};
89 75         45 my %seen;
90 75         44 for (;;) {
91             ### $value
92 732 100       853 if ($value == 1) {
93 24         50 return 1;
94             }
95 708 100       848 if ($seen{$value}) {
96 51         161 return 0; # inf loop
97             }
98 657         531 $seen{$value} = 1;
99 657         603 $value = _sum_of_squares_of_digits($value,$radix);
100             }
101             }
102             sub _sum_of_squares_of_digits {
103 657     657   508 my ($n, $radix) = @_;
104 657         794 return sum (map {$_ * $_} _digit_split_lowtohigh($n,$radix));
  1285         1510  
105             }
106              
107             1;
108             __END__