patternMinor
Finding product palindromes
Viewed 0 times
palindromesproductfinding
Problem
I am new to perl and want some help in tuning this script if possible cause it takes time if I increased my array. also if I
Here is an example of what I want to achieve:
The number 886 is like 8*86 = 688, if we reverse it 886 which is the original number.
Also the same for 920781, 9*20781 = 187029, reverse 920781,
etc...
use warnings I get a lot of warnings which I'm unable to handle. I'm using perl (v5.24.0) built for darwin-thread-multi-2level.Here is an example of what I want to achieve:
The number 886 is like 8*86 = 688, if we reverse it 886 which is the original number.
Also the same for 920781, 9*20781 = 187029, reverse 920781,
etc...
my $start_run = time();
use strict;
foreach (1..1000000000) {
if ($_==reverse(substr($_, 0, 1) * substr($_, 1)))
{ print $_."\n" ;}
if ($_==reverse(substr($_, 0, 2) * substr($_, 2)))
{ print $_."\n" ;}
if ($_==reverse(substr($_, 0, 3) * substr($_, 3)))
{ print $_."\n" ;}
if ($_==reverse(substr($_, 0, 4) * substr($_, 4)))
{ print $_."\n" ;}
if ($_==reverse(substr($_, 0, 5) * substr($_, 5)))
{ print $_."\n" ;}
if ($_==reverse(substr($_, 0, 6) * substr($_, 6)))
{ print $_."\n" ;}
if ($_==reverse(substr($_, 0, 7) * substr($_, 7)))
{ print $_."\n" ;}
}
my $end_run = time();
my $run_time = $end_run - $start_run;
print "Time taken: ".$run_time." sec\n";Solution
I want some help in tuning this script if possible cause it takes time
if I increased my array
Yes, the script can be tuned. I will discuss optimizing you script at the end of this post.
The
also if I use warnings I get a lot of warnings which I'm unable to
handle
Yes correct, you will get many warnings in case you add the statement
-
Why use strict and warnings?
-
Why not use strict and warnings in Perl?
In short, the
This happens because in the first iteration of the
the first substring will be
but if you turn on warnings (use the
you will get the warning
The next warning you get will be
this happens because
if the substring is beyond either end of the string. In this case,
The next warning you will get is:
This happens also at line 6, where you have
Here the first substring will be
The problem with the code
From the above discussion, it should be clear that the problem with the code that causes the warnings are that it does not use
Fortunately, these problems can be solved easily using nested
Here, I have defined a variable
The inner
Programming style
In Perl there is more than one way to do it (TMTOWTDI). The language was designed with this idea in mind, in that it "doesn't try to tell the programmer how to program". Still, in my experience (I started programming Perl 3 years ago) there are certain programming style guidelines that have been adopted by the community. I have seen these programming styles in practice reading source code of CPAN modules and looking at answers at the Perl tag at stackoverflow.com. Some of these guidelines are described in perlstyle, in Chapter 21 of Programming Perl and in the book Perl Best Practices.
-
Put all use statements at the top of your program. Since all
The above code works fine, even if
likely confuse humans. You can read more about compile time versus run time in Chapter 16 of the book Programming Perl.
Perl pragmas are a subclass of Perl modules that can have a lexical scope. Since these pragmas only stay in effect within the scope in which they are
if I increased my array
Yes, the script can be tuned. I will discuss optimizing you script at the end of this post.
The
warnings pragmaalso if I use warnings I get a lot of warnings which I'm unable to
handle
Yes correct, you will get many warnings in case you add the statement
use warnings. Using the warnings pragma is highly recommended, see for example:-
Why use strict and warnings?
-
Why not use strict and warnings in Perl?
In short, the
warnings pragma help you find bugs in your code. If you add the use warnings to the top of your program, the first warning you get isArgument "" isn't numeric in multiplication (*)This happens because in the first iteration of the
for loop, $_ will be equal to 1, and at line 4 of your program where you mulitply the substrings:substr($_, 0, 1) * substr($_, 1))the first substring will be
"1" and the second will be the empty string "". When you try multiply with the empty string (and warnings are disabled) it will be converted silently to a zero, see perldata. To demonstrate:$ perl -E 'say 1 + ""'
1but if you turn on warnings (use the
-w flag):$ perl -wE 'say 1 + ""'
Argument "" isn't numeric in addition (+) at -e line 1.
1you will get the warning
Argument "" isn't numeric.The next warning you get will be
substr outside of stringthis happens because
substr returns an undefined valueif the substring is beyond either end of the string. In this case,
substr will also produce a warning (if you have enabled warnings with use warnings). The reason why you get the warning is that $_ is equal to "1" and at line 6 of your script you try call substr $_, 2. To demonstrate:$ perl -wE '$_="1"; my $s = substr $_, 2'
substr outside of string at -e line 1.The next warning you will get is:
Use of uninitialized value in multiplication (*)This happens also at line 6, where you have
substr($_, 0, 2) * substr($_, 2)Here the first substring will be
"1" ( since $_ is equal to "1" in the first iteration of the for loop), whereas the second substring will be undefined, as discussed above. Now if you try multiply 1 * undef you will get 0, and a warning (if you have enabled warnings). To demonstrate:$ perl -wE 'say 1 * undef'
Use of uninitialized value in multiplication (*) at -e line 1.
0The problem with the code
From the above discussion, it should be clear that the problem with the code that causes the warnings are that it does not use
substr correctly when the numbers ( i.e $_ in the for loop ) are less than 8 digits long. If the numbers are more than 8 digits long another problem arises. In this case, the problem is of logical nature in that the program will fail to check all possible palindromes. For example, for a 9 digit number there is no checkif ($_ == reverse(substr($_, 0, 8) * substr($_, 8))) { ... }Fortunately, these problems can be solved easily using nested
for loops:for (1 .. $max_integer) {
for my $length ( 1 .. ((length $_) - 1) ) {
say if $_ == reverse (substr ($_, 0, $length) * substr ($_, $length) );
}
}Here, I have defined a variable
$max_integer which should be set to the highest integer to check for. For your case, it should be set to 1 billion:my $max_integer = 1_000_000_000;The inner
for loop takes care of all the if statements in your original code.Programming style
In Perl there is more than one way to do it (TMTOWTDI). The language was designed with this idea in mind, in that it "doesn't try to tell the programmer how to program". Still, in my experience (I started programming Perl 3 years ago) there are certain programming style guidelines that have been adopted by the community. I have seen these programming styles in practice reading source code of CPAN modules and looking at answers at the Perl tag at stackoverflow.com. Some of these guidelines are described in perlstyle, in Chapter 21 of Programming Perl and in the book Perl Best Practices.
-
Put all use statements at the top of your program. Since all
use statements occur at compile time, it often does not matter for the Perl interpreter where in the source file you place them1. To demonstrate:$ perl -E 'say getcwd(); use Cwd'The above code works fine, even if
use Cwd comes after its exported function getcwd is called in the code. However, the above code will likely confuse humans. You can read more about compile time versus run time in Chapter 16 of the book Programming Perl.
Perl pragmas are a subclass of Perl modules that can have a lexical scope. Since these pragmas only stay in effect within the scope in which they are
used, their position in the code is important also to the Perl interpreter. However, these pragmas are typically used at the package scope ( to enable them in Code Snippets
Argument "" isn't numeric in multiplication (*)substr($_, 0, 1) * substr($_, 1))$ perl -E 'say 1 + ""'
1$ perl -wE 'say 1 + ""'
Argument "" isn't numeric in addition (+) at -e line 1.
1substr outside of stringContext
StackExchange Code Review Q#133916, answer score: 7
Revisions (0)
No revisions yet.