Perl subroutine not working in loop - perl

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

Related

Sum of Primes always returns 0

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);

how to solve warning message Use of uninitialized value in numeric lt (<) at ./test.pl line 17

The program below works fine, but there is a warning that says:
Use of uninitialized value in numeric lt (<) line 17.
How do I fix the warning?
Any help would be really appreciated !
#!/usr/bin/perl
use strict;
use Carp;
use warnings;
my #array = (1,3,7,9,7,10,11,12,13,14,15,16,27,10,9,18,19,20,21,22,23,24,9,3,4);
my $i = 0;
my $j = 0;
my $k = 0;
my $n = $#array+1;
my $tempj = 0;
while(1){
$j=$i;
while (($array[$i] < $array[$i+1]) && ($i < ($n-1))){
$i++;
}
if(( $i - $j) > $k){
$k = $i-$j;
$tempj=$j;
}
if ($i >= ($n-1)){
print "la position : ",$j," , la langueur: ",$k,"\n";
exit;
}
else{
$j=$i;
while ($array[$i]>$array[$i+1] && $i < ($n-1)){
$i++;
}
if(($i-$j) > $k){
$k = $i-$j;
$tempj=$j;
}
if ($i >= ($n-1)){
print "la position : ",$j," , la langueur",$k,"\n";
exit;
}
}
}
Thank you in advance
Change the order of the conditions to make sure the array access is not out of bounds. This eliminates the warning:
while ( ($i < ($n-1)) && ($array[$i] < $array[$i+1]) ) {

Perl: Finding out if a given number is a prime number

I am trying to write a subroutine that determines whether or not the number passed in is prime, and it's not working correctly. The numbers I'm passing in should not be identified as prime. Is there a logic error, or something about Perl that I'm missing?
sub isPrime {
my ( $n ) = #_;
for ( my $i = 3 ; $i < $n ; $i++ ) {
if ( $n % $i == 0 ) {
return 0;
}
else {
return 1;
}
}
}
At the moment your function is checking just if n is not divisible by 3 because it calls return immediately after the fisrt test.
Try to make the function return 0 within the for loop, and return 1 outside it, or set a flag for the number being prime that is initially true and return its value after the loop.
You should also start your for loop at 2, not at 3, otherwise you aren't testing for even numbers.
Here is my code I wrote in about 40 minutes. Don't hate if it is inefficient, I am still learning perl.
print ("This is a prime number checker!\n");
print ("Enter a number below to check it:\n");
$y = 0;
$num = <>;
for ($i = $num; $i > 0; $i--) {
if ($num % $i == 0) {
$y += 1;
}
}
if ($y > 2) {
print ("$num is not a prime!");
} else {
print ("$num is a prime!");
}

Cannot locate error causing Perl warning: Use of unitialized value in concatenation (.) or string

I'm trying to program a File I/O for the first time and I don't understand why I'm getting this error in my for loop (line 22 or line 3 in sub routine printBestData). An extra pair of eyes would be greatly appreciated! Here's my code:
my (#bestData, #cushingData, #combinedData);
use constant BESTDATAFILEIN => "./ApgarMedicalBest.txt";
use constant CUSHINGDATAFILEIN => "./ApgarMedicalCushing.txt";
use constant DATAFILEOUT => "./MergedApgarMedical.csv";
use constant COLUMNS => 4;
sub readBestData {
my $IN;
my $counter = 0;
my #tempData = ();
#bestData = ();
open ($IN, '<', BESTDATAFILEIN);
while (<$IN>) {
#tempData = split(/,/);
for (my $i = 0; $i < COLUMNS; $i++) {
($bestData[$counter][$i] = $tempData[$i]);
}
$counter++;
}
close $IN;
}
sub printBestData {
my $size = #bestData;
for (my $i = 0; $i < $size; $i++) {
for (my $j = 0; $j < COLUMNS; $j++) {
#Error occurs in this line
print "$bestData[$i][$j] ";
}
print "\n";
}
}
There could be a few reasons:
ApgarMedicalBest.txt contains empty fields, for example 1,2,,4
ApgarMedicalBest.txt contains lines with less than 4 fields (defined in COLUMNS), for example 1,2,4
You could modify readBestData as follows to alleviate both problems:
sub readBestData {
my $IN;
my $counter = 0;
my #tempData = ();
#bestData = ();
open ($IN, '<', BESTDATAFILEIN);
while (<$IN>) {
# Split string and avoid skipping empty fields
#tempData = split(/,/, $_, -1);
# If data contains required number of columns
if(scalar(#tempData) == COLUMNS){
for (my $i = 0; $i < COLUMNS; $i++) {
($bestData[$counter][$i] = $tempData[$i]);
}
}
$counter++;
}
close $IN;
}

For loop help in perl

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.