I have a code in Perl which takes in a number and adds up all the prime numbers up to that number. I keep on getting the value 0 which means it is not updating my $sum variable, but I don't know what else to do.
sub checkPrime {
my($numb) = #_;
$primeCheck = "prime\n";
if ($numb == 1) {
$primeCheck = "notPrime\n";
}
for ($i = 2; $i < $numb; $i++) {
$mod = $numb % $i;
if ($mod == 0) {
$primeCheck = "notPrime\n"
}
}
return $primeCheck;
}
sub sumOfPrimes {
my($input) = #_;
$sum = 0;
for ($i = 2; $i <= $input; $i++) {
if (checkPrime($i) eq "prime") {
$sum = $sum + $i;
}
}
return $sum;
}
print sumOfPrimes(10);
You are not comparing the correct string. You include a newline character (\n) when you set the value, but not when you compare it. Change:
if (checkPrime($i) eq "prime")
to:
if (checkPrime($i) eq "prime\n")
That is the simplest change, but you probably don't need to have \n in there at all.
To sum prime numbers you need to identify if the number is a prime number. Let's create a function which returns 1 if the number is prime and 0 otherwise.
sub isPrime {
my $n = shift;
return 0 unless $n > 1;
for( my $i = 2; $i < $n; $i++ ) {
return 0 if $n % $i == 0;
}
return 1;
}
Now go through the list of numbers and sum only those which is prime
$sum += $num if isPrime($num);
Trying to implement matrix inversion in Perl myself, I found An Efficient and Simple Algorithm for Matrix Inversion (only two pages of the article).
After my attempt to implement it in Perl, I see that it does not work.
I had spend a lot of time trying to find out what's wrong, so I concluded that
either the algorithm is not correct
I misinterpreted the algorithm
my implementation is not correct
Before presenting the code, here's a debug session with an example from Wikipedia: Inverse Matrix:
DB<229> $m=[[2,5],[1,3]]
DB<230> x invert($m)
pe[0] == 2
(pivot row 0) 2x2:
2.000 2.500
1.000 3.000
(pivot column 0) 2x2:
2.000 2.500
-0.500 3.000
(rest 0) 2x2:
2.000 2.500
-0.500 1.750
(pivot 0) 2x2:
0.500 2.500
-0.500 1.750
pe[1] == 1.75
(pivot row 1) 2x2:
0.500 2.500
-0.286 1.750
(pivot column 1) 2x2:
0.500 -1.429
-0.286 1.750
(rest 1) 2x2:
0.908 -1.429
-0.286 1.750
(pivot 1) 2x2:
0.908 -1.429
-0.286 0.571
0 1
1 3.5
DB<231>
So here's the code I wrote:
#!/usr/bin/perl -w
use 5.026;
use strict;
# invert matrix
# An Efficient and Simple Algorithm for Matrix Inversion
# Ahmad Farooq, King Khalid University, Saudi Arabia
# Khan Hamid, National University of Computer and Emerging Sciences (NUCES),
# Pakistan
sub invert($)
{
my $m = shift; # matrix is an array of rows
my ($pp, $det);
my ($rp, $pe);
my $n = scalar(#$m);
for ($pp = 0, $det = 1.0; $pp < $n; ++$pp) {
$rp = $m->[$pp]; # pivot row
$pe = $rp->[$pp]; # pivot element
print "pe[$pp] == $pe\n";
last if ($pe == 0); # Epsilon test?
$det *= $pe;
# calculate pivot row
for (my $j = 0; $j < $n; ++$j) {
next if ($j == $pp);
$rp->[$j] /= $pe;
}
pm($m, "pivot row $pp");
# calculate pivot column
for (my $i = 0; $i < $n; ++$i) {
next if ($i == $pp);
$m->[$i]->[$pp] /= -$pe;
}
pm($m, "pivot column $pp");
for (my $j = 0; $j < $n; ++$j) {
next if ($j == $pp);
for (my ($i, $rj) = (0, $m->[$j]); $i < $n; ++$i) {
next if ($i == $pp);
$rj->[$i] += $rp->[$j] * $m->[$i]->[$pp];
}
}
pm($m, "rest $pp");
$rp->[$pp] = 1.0 / $pe;
pm($m, "pivot $pp");
}
return ($pe != 0.0, $det);
}
The pm() function is just a "print matrix" for debugging purposes:
# print matrix
sub pm($;$)
{
my ($m, $label) = #_;
my $n = scalar(#$m);
print "($label) " if ($label);
print "${n}x${n}:\n";
for (my $i = 0; $i < $n; ++$i) {
for (my $j = 0; $j < $n; ++$j) {
if (defined(my $v = $m->[$i]->[$j])) {
printf('%8.3f', $v);
} else {
print ' ???????';
}
}
print "\n";
}
}
Any insights?
Hint for Reproduction (added 2019-08-28)
I had thought it was obvious, but just in case:
If you want to reproduce the output shown in the debug session, maybe just add these two lines at the end of the code:
my $m=[[2,5],[1,3]]; # matrix to invert
print join(', ', invert($m)), "\n"; # invert $m, printing result
Note (added 2019-09-02):
The algorithm fails for the 3x3 matrix given in the Wikipedia article ($m = [[1, 2, 0], [2, 4, 1], [2, 1, 0]]), so real implementations should head towards the improved algorithm (that can select pivot elements outside the diagonal).
When in doubt, write tests.
First, put your code into a module (lib/My/Matrix.pm or whatever you want to call it):
package My::Matrix; # this must match the file name
use strict;
use warnings;
use Exporter qw(import);
our #EXPORT_OK = qw( invert pm );
# your code here ...
1; # at end of module
There is a lot of documentation regarding writing modules, not sure if perldoc perlmod is a good starting point.
Now write a test - documentation is here (t/001-invert.t):
#!perl
use strict;
use warnings;
use Test::More;
use Matrix qw(invert);
ok_invert( [[1,0], [0,1]], [[1,0], [0,1]], "unit matrix" );
# insert more matrices here
done_testing;
sub ok_invert {
my ($input, $output, $msg) = #_;
invert( $output );
is_deeply $input, $output, $msg
or diag "got: ", explain $input, "expected: ", explain $output;
};
Run the test as perl -Ilib t/001-invert.t or prove -Ilib t if you want to run multiple tests.
You can now add simple corner cases to the test until the problem is isolated.
Of course, finding the correct inverse matrix by hand is tedious, so you may want to use multiplication instead. So the next steps to improve your code would be:
make sure invert does not modify its input and returns the inverted matrix instead;
Sidenote. It's generally a good idea to make sure a function returns the desired value and does not modify its arguments. It's not always possible but when it is, it saves a ton of debugging time.
implement multiplication;
implement is_unit_matrix check;
rewrite the test function as follows (the next snippet was not tested):
sub ok_invert {
my ($input, $msg) = #_;
my ($invert, $det) = invert( $input );
ok is_unit_matrix( multiply( $invert, $input ) ), $msg
or diag explain $invert, " is not the inverse of ", explain $input;
}
Hope this helps.
The pseudocode in the original paper is not correct.
Steps I have done so far:
inserted the pseudocode into the Perl source
used the naming of the pseudocode
test cases
tested the test cases
tested with Math::Matrix as a reference
reviewed (many times)
At least I read the note in paper:
Note that in step 7 of the following algorithm a'[i, p]
on the LHS means that the latest value of the pivot row
is to be used in the calculations.
This note is not really precise. After additional attempts I gave up, wanted to post my findings here, and read the answer of Håkon Hægland. Yes, his solution works and he earns the honor.
If the steps in the pseudocode are reordered it passes my 3 tests:
Step 1
Step 2
Step 3
Step 4
Step 6
Step 7
Step 5
Step 8
Step 9
Step 10
Here is the version with pseudocode included and using the original naming:
sub invert_corr($) {
my $A = shift; # matrix is an array of rows
my $n = scalar(#$A);
# Step 1: Let p = 0, d = 1;
my $p = 0;
my $det;
# Step 2: p <= p +1
for (my $pi = 0,$det = 1.0; $pi < $n; ++$pi) {
$p = $pi;
# Step 3: If a[p,p] == 0 then cannot calculate inverse, go to step 10.
if ($A->[$p]->[$p] == 0) { last; }
# Step 4: d <= d x a[p, p]
$det = $det * $A->[$p]->[$p];
# Step 6: Calculate the new elements of the pivot column by:
# a_new[i,p] <= -(a[i,p] / a[p,p]) where i = 1 .. n, i != p
STEP6: for (my $i = 0; $i < $n; ++$i) {
if ($i == $p) { next STEP6; }
$A->[$i]->[$p] = -($A->[$i]->[$p] / $A->[$p]->[$p]);
}
# Step 7: Calculate the rest of the new elements by:
# a_new[i,j] <= a[i,j] + a[p,j] x a_new[i,p]
# where i = 1 .. n, j = 1 .. n, & i,j != p
OUTER7: for (my $i = 0; $i < $n; ++$i) {
if ($i == $p) { next OUTER7; }
INNER7: for (my $j = 0; $j < $n; ++$j) {
if ($j == $p) { next INNER7; }
# Note that in step 7 of the following algorithm a'[i, p]
# on the LHS means that the latest value of the pivot row
# is to be used in the calculations.
$A->[$i]->[$j] = $A->[$i]->[$j] + $A->[$p]->[$j] * $A->[$i]->[$p];
}
}
# Step 5: Calculate the new elements of the pivot row by:
# a_new[p,j] <= a[p,j] / a[p,p] where j = 1 .. n, j != p
STEP5: for (my $j = 0; $j < $n; ++$j) {
# next if ($j == $p);
if ($j == $p) { next STEP5; }
$A->[$p]->[$j] = $A->[$p]->[$j] / $A->[$p]->[$p];
}
# Step 8: Calculate the new value of the current pivot location:
# a_new[p,p] <= 1 / a_new[p,p]
$A->[$p]->[$p] = 1.0 / $A->[$p]->[$p];
# Step 9: If p < n go to step 2 (n the dimension of the matrix A).
}
# Step 10: Stop. If inverse exists, A contains the inverse and d is the determinant.
if ($A->[$p]->[$p] != 0.0) {
return ($A->[$p]->[$p] != 0.0, $det, $A);
}
return ($A->[$p]->[$p] != 0.0);
}
The complete code including tests is available on github, maybe useful for debugging.
According to the referred to paper, step #7 should be computed with the old pivot row values, so the following seems to work for me:
sub invert($)
{
my $m = shift; # matrix is an array of rows
my ($pp, $det);
my ($rp, $pe);
my $n = scalar(#$m);
for ($pp = 0, $det = 1.0; $pp < $n; ++$pp) {
$rp = $m->[$pp]; # pivot row
$pe = $rp->[$pp]; # pivot element
last if ($pe == 0); # Epsilon test?
$det *= $pe;
# calculate pivot column
for (my $i = 0; $i < $n; ++$i) {
next if ($i == $pp);
$m->[$i][$pp] /= -$pe;
}
for (my $j = 0; $j < $n; ++$j) { # row index
next if ($j == $pp);
for (my ($i, $rj) = (0, $m->[$j]); $i < $n; ++$i) {
next if ($i == $pp);
$rj->[$i] += $rp->[$i] * $m->[$j]->[$pp];
}
}
# calculate pivot row
for (my $j = 0; $j < $n; ++$j) {
next if ($j == $pp);
$rp->[$j] /= $pe;
}
$rp->[$pp] = 1.0 / $pe;
}
return ($pe != 0.0, $det);
}
Fix required to match result in Wikipedia:
--- newinvert.pl~ 2019-08-29 21:22:16.135160055 +0200
+++ newinvert.pl 2019-08-29 21:32:10.995144732 +0200
## -20,7 +20,7 ##
next if ($j == $pp);
for (my ($i, $rj) = (0, $m->[$j]); $i < $n; ++$i) {
next if ($i == $pp);
- $rj->[$i] += $rp->[$i] * $m->[$j]->[$pp];
+ $rj->[$i] += $rp->[$j] * $m->[$i]->[$pp];
}
}
# calculate pivot row
Sample session (inluding my pm()):
> perl -d printmatrix.pl
Loading DB routines from perl5db.pl version 1.51
Editor support available.
Enter h or 'h h' for help, or 'man perldebug' for more help.
main::(printmatrix.pl:20): 1;
DB<1> require "./newinvert.pl" # this is ungly, forgive!
./newinvert.pl did not return a true value at (eval 6)[/usr/lib/perl5/5.26.1/perl5db.pl:738] line 2.
DB<2> $m=[[2,5],[1,3]]
DB<4> pm($m)
2x2:
2.000 5.000
1.000 3.000
DB<5> x invert($m)
0 1
1 1
DB<6> pm($m)
2x2:
3.000 -5.000
-1.000 2.000
Result of regression tests:
# https://github.com/wollmers/matrix-inverse-Farooq/blob/master/matrix_inversion_new.pl
$ perl matrix_inversion_new.pl
[...]
(invert_hakon 01_wiki input $A) 2x2:
2.000 5.000
1.000 3.000
(invert_hakon 01_wiki result $C) 2x2:
3.000 -5.000
-1.000 2.000
ok 10 - 01_wiki invert_hakon Ainv
ok 11 - 01_wiki invert_hakon det: 1
(invert_hakon 02_wiki input $A) 2x2:
2.000 3.000
1.000 2.000
(invert_hakon 02_wiki result $C) 2x2:
2.000 -3.000
-1.000 2.000
ok 12 - 02_wiki invert_hakon Ainv
ok 13 - 02_wiki invert_hakon det: 1
(invert_hakon 03_author_1 input $A) 3x3:
1.000 1.000 3.000
1.000 3.000 -3.000
-2.000 -4.000 -4.000
(invert_hakon 03_author_1 result $C) 3x3:
3.000 1.000 1.500
-1.250 -0.250 -0.750
-0.250 -0.250 -0.250
ok 14 - 03_author_1 invert_hakon Ainv
ok 15 - 03_author_1 invert_hakon det: -8
[...]
One of the problems when implementing a mathematical formula like (actually from Step 5)
in a loop is: When will the "new" a' become the "old" a?
Before the next step, before the next assignment, or before the next loop iteration?
In a mathematical sense a' and a are different variables all the time, but in procedural programming languages the memory address for a is reused at some time.
So the assignments from Step 5 need to be delayed after Step 7 (), it seems.
As a computer scientist I had always felt that mathematical algorithms are described in a somewhat imprecise way. Maybe that's exactly the reason why programming languages were invented ;-)
I tried writing a simple code to find whether a number can be expressed as the sum of primes or not, in Perl. The sample code is as shown:
sub funcIsPrime {
my $num = $_[0];
my $isPrime = 1;
for($i= 2; $i <= $num/2; $i++){
if($num%$i == 0){
$isPrime = 0;
last;
}
}
return $isPrime;
}
#my $num = <>;
my $num = 20;
for($i = 2; $i <= $num/2; $i++){
print "$i\t";
my $j = $num-$i;
print "$j\n";
if(funcIsPrime($i) and funcIsPrime($j)){ # Line x
print "$num = $i + $j\n";
}
}
The function call statements in Line x do not execute. The same line when put outside the loop works fine. What can be the possible solution? Please help. Thank you.
The main issue is missing my in variable declarations. Perl won't let you run the program if you include use warnings; and use strict;:
Global symbol "$i" requires explicit package name (did you forget to declare "my $i"?) at test.pl line 22.
Execution of test.pl aborted due to compilation errors.
Here's simplified working code (you can search for factors up to the square root of n, by the way, although this isn't a perfect or efficient prime test by any means):
use strict;
use warnings;
sub isPrime {
my $num = $_[0];
for (my $i = int sqrt $num; $i > 1; $i--) {
if ($num % $i == 0) {
return 0;
}
}
return 1;
}
my $num = 20;
for (my $i = 2; $i <= $num / 2; $i++) {
my $j = $num - $i;
if (isPrime($i) && isPrime($j)) {
print "$num = $i + $j\n";
}
}
Output
20 = 3 + 17
20 = 7 + 13
I am writing perl script and I have little question regarding for loop limit.
Let say I have two arrays, arr1 has serial numbers and arr2 is two dimensional array, the first dimension is the serial number [same as arr1] and the second dimension is the contents of that serial number , Now I want to apply the for loop for this two dimension array but I am confused at the limit . Till now I have this code
Example : I have Three serial numbers , 1 ,2 ,3 . Serial 1 has 2 contents 1,5 . Serial 2 has 1 content i.e 1. Serial 3 has two contents 1,1.
#arr1 = (1,2,3)
$arr2[0][0] = 1
$arr2[0][1] = 5
$arr2[1][0] = 1
$arr2[2][1] = 1
$arr2[2][2] = 1
Note: As you can see the contents of arr2 has arr1 elements in 1st columns and the contents in the second columns.
for (my $i = 0; $i <= $#arr1; $i++) {
print( "The First Serial number has:" );
for (my $j = 0; $j <= $#arr2; $j++) {
print( "$arr2[$i][$j]\n" );
}
}
Thanks, Sorry for the bad explaination
Why don't do this like that :
#!/usr/bin/perl
use strict;
my #arr;
$arr[0][0] = 1;
$arr[0][1] = 5;
$arr[1][0] = 1;
$arr[2][1] = 1;
$arr[2][2] = 1;
my ($i, $j);
foreach $i (#arr) {
foreach $j (#{$i}) {
print $j."\n" if($j);
}
}
1;
__END__
Fixed code:
use strict;
use warnings;
my #arr1 = (1,2,3);
my #arr2;
$arr2[0][0] = 1;
$arr2[0][1] = 5;
$arr2[1][0] = 1;
$arr2[2][0] = 1; # original code had
$arr2[2][1] = 1; # these indexes wrong
for (my $i = 0; $i <= $#arr1; $i++) {
print( "Serial number $arr1[$i] has:" );
for (my $j = 0; $j <= $#{ $arr2[$i] }; $j++) {
print( "$arr2[$i][$j]\n" );
}
}
Note the use of $#{ arrayref }; see http://perlmonks.org/?node=References+quick+reference
you can put #arr2 like this and it would be much easier for you to understand #arr2
use strict;
use warnings;
my #arr1 = (1, 2, 3);
my #arr2 = ([1, 5], [1], [1, 1]);
for my $first(#arr1) {
for my $second (#{$arr2[$first-1]}) {
print $second."\n";
}
}
Here is a version without the first array.
for (my $i = 0; $i<= $#arr; $i++)
{
print "INDEX $i\n";
for (my $j = 0; $j <= $#{$arr[$i]}; $j++)
{
print "${arr[$i][$j]}\n";
}
}
The point here is that a two dimensional array is in fact an array of arrays (well actually array references, but that does not change anything here). So in the inner loop, you should check against the size of the array that is stored in $arr[$i].
Try this.
my #arr2;
$arr2[0][0] = 1;
$arr2[0][1] = 5;
$arr2[1][0] = 1;
$arr2[2][0] = 1;
$arr2[2][1] = 1;
foreach $inside_array (#arr2){
foreach $ele (#$inside_array){
print $ele,"\n";
}
}
Its always better to use foreach instead of for/while, this will eliminate any possibility of bugs. Especially with judging proper condition to exit the loop.
For clarification, if I had a list of 8 elements, i would want to randomly pick 2. If I had a list of 20 elements, I would want to randomly pick 5. I would also like to assure (though not needed) that two elements don't touch, i.e. if possible not the 3 and then 4 element. Rather, 3 and 5 would be nicer.
The simplest solution:
Shuffle the list
select the 1st quarter.
Example implementation:
use List::Util qw/shuffle/;
my #nums = 1..20;
my #pick = (shuffle #nums)[0 .. 0.25 * $#nums];
say "#pick";
Example output: 10 2 18 3 19.
Your additional restriction “no neighboring numbers” actually makes this less random, and should be avoided if you want actual randomness. To avoid that two neighboring elements are included in the output, I would iteratively splice unwanted elements out of the list:
my #nums = 1..20;
my $size = 0.25 * #nums;
my #pick;
while (#pick < $size) {
my $i = int rand #nums;
push #pick, my $num = $nums[$i];
# check and remove neighbours
my $len = 1;
$len++ if $i < $#nums and $num + 1 == $nums[$i + 1];
$len++, $i-- if 0 < $i and $num - 1 == $nums[$i - 1];
splice #nums, $i, $len;
}
say "#pick";
use strict;
use warnings;
sub randsel {
my ($fact, $i, #r) = (1.0, 0);
while (#r * 4 < #_) {
if (not grep { $_ == $i } #r) {
$fact = 1.0;
# make $fact = 0.0 if you really don't want
# consecutive elements
$fact = 0.1 if grep { abs($i - $_) == 1 } #r;
push(#r, $i) if (rand() < 0.25 * $fact);
}
$i = ($i + 1) % #_;
}
return map { $_[$_] } sort { $a <=> $b } #r;
}
my #l;
$l[$_] = $_ for (0..19);
print join(" ", randsel(#l)), "\n";