perl - Trying to use a while loop to ask the user if they want to do that again - perl

(New to perl)
I have a small perl program that calculates factorials. I'd like to use a while loop so that after the user gets a result, they will be asked "Calculate another factorial? Y/N" and have Y run the code again & have N end the program.
Here's my code:
print"Welcome! Would you like to calculate a factorial? Y/N\n";
$decision = <STDIN>;
while $decision == "Y";
{
print"Enter a positive # more than 0: \n";
$num = <STDIN>;
$fact = 1;
while($num>1)
{
$fact = $fact * $num;
$num $num - 1;
}
print $fact\n;
print"Calculate another factorial? Y/N\n";
$decision = <STDIN>;
}
system("pause");
What's giving me trouble is where to put the while loop and how to make the Y/N option work. I'm also unclear about system("pause") and sleep functions. I do know that system("pause") makes my programs work though.

Your program is almost right, just a few issues:
Please get used to always add use strict; and use warnings; to your scripts. They will
(beyond other things) force you to declare all the variables you use (with my $num=…;)
and warn you about common errors (like typos). Some people consider it a bug that
use strict; and use warnings; aren't turned on by default.
When reading a line from STDIN (or some other filehandle) the read line will contain the
trailing newline character "\n". For your comparison to work you must get rid of that using
the chomp function.
There are two different sets of comparison operators in Perl: one for strings and one for numbers.
Numbers are compared with <, >, <=, >=, ==, and !=. For strings you must use
lt (less-than), gt, le (less-or-equal), ge, eq, and ne. If you use one of the number
operators on strings Perl will try to interpret your string as a number, so $decision == "Y"
would check whether $decision is 0. If you had use warnings; Perl would have noticed you.
Use $decision eq "Y" instead.
The outer while loop had a trailing ; just after the comparison which will give you an endless
loop or a no-op (depending on the content of $decision).
You forgot the = in $num = $num - 1;.
You forgot the quotes " around print "$fact\n";
system("pause") only works on Windows where pause is an external command. On Linux (where
I just tested) there is no such command and system("pause") fails with command not found.
I replaced it with sleep(5); which simply waits 5 seconds.
.
#!/usr/bin/env perl
use strict;
use warnings;
print "Welcome! Would you like to calculate a factorial? Y/N\n";
my $decision = <STDIN>;
chomp($decision); # remove trailing "\n" from $decision
while ( $decision eq 'Y' ) {
print "Enter a positive # more than 0: \n";
my $num = <STDIN>;
chomp($num);
my $fact = 1;
while ( $num > 1 ) {
$fact = $fact * $num;
$num = $num - 1;
}
print "$fact\n";
print "Calculate another factorial? Y/N\n";
$decision = <STDIN>;
chomp($decision);
}
print "ok.\n";
sleep(5); # wait 5 seconds

Always add use warnings and use strict to the beginning of your program.
There are a number of typos in your code that would have been caught by this.
#!/usr/bin/perl
use warnings;
use strict;
print "Welcome! Would you like to calculate a factorial? Enter 'Y' or 'N': ";
my $answer = <STDIN>;
chomp($answer);
while($answer =~ /^[Yy]$/){
my $fact = 1;
print"Enter a positive number greater than 0: ";
my $num = <STDIN>;
chomp($num);
my $number_for_printing = $num;
while($num > 0){
$fact = $fact * $num;
$num--;
}
print "The factorial of $number_for_printing is: $fact\n";
print"Calculate another factorial? Enter 'Y' or 'N': ";
$answer = <STDIN>;
chomp($answer);
}
print "Goodbye!\n";

Related

Perl Division Program

I'm learning Perl and have come across this question
Write a Perl program that reads in two numbers and does the following:
It prints Error: can't divide by zero if the second number is 0.
If I enter the second number as zero, I'm getting an error
Illegal division by zero at ./divide.pl line 13, <STDIN> line 2.
I'm using the following code
#!/usr/bin/perl
## Divide by zero program
print("Enter the first number: \n");
$input1 = <STDIN>;
chomp ($input);
print ("Enter the second number: \n");
$input2 = <STDIN>;
chomp ($input2);
$answer = $input1/$input2;
if ($input2 == 0)
{
print("Error: can't divide by zero \n");
}
print("The answer is $answer \n");
You need to perform your check before doing the division. You also need skip doing the division entirely if the check is true.
if ($input2 == 0) {
print("Error: can't divide by zero\n");
} else {
my $answer = $input1/$input2;
print("The answer is $answer\n");
}
By the way, ALWAYS ALWAYS use use strict; use warnings qw( all ); in your programs.
Stolen from Sinan's comment (because sometimes we forget that things we know aren't known): You're seeing that message because Perl 5 (along with many other languages) doesn't handle division by zero. The interpreter tries to do it with no safeguards and having done so, gives up with a die. Your program immediately stops. You never make it to your check.
Much of the practice of programming is checking input when you get them. Instead of checking later, validate them as soon as you receive them. You can also check that both inputs are actually numbers. Scalar::Util comes with Perl and has a looks_like_number subroutine that does that for you:
use Scalar::Util qw(looks_like_number);
print("Enter the first number: ");
chomp( my $numerator = <STDIN> );
die "$numerator doesn't look like a number!\n"
unless looks_like_number($numerator);
print ("Enter the second number: ");
chomp( my $denominator = <STDIN> );
die "$denominator doesn't look like a number!\n"
unless looks_like_number($denominator);
die "Can't divide by zero!\n" if $denominator == 0;
my $answer = $numerator/$denominator;
print "$numerator / $denominator = $answer\n";
Do that for a bit and you start to realize that you've repeated yourself. You could move that to a subroutine. Once abstracted away you can adjust get_number for any sort of validation that you like:
use Scalar::Util qw(looks_like_number);
my $numerator = get_number();
my $denominator = get_number();
die "Can't divide by zero!\n" if $denominator == 0;
my $answer = $numerator/$denominator;
print "$numerator / $denominator = $answer\n";
sub get_number {
print("Enter a number: ");
chomp( my $number = <STDIN> );
die "$number doesn't look like a number!\n"
unless looks_like_number($number);
return $number;
}
And, I like to leave the newline off of prompts so I type my input right after the message:
$ perl zero.pl
Enter a number: 4
Enter a number: 5
4 / 5 = 0.8
$ perl zero.pl
Enter a number: Llama
Llama doesn't look like a number!

Name multiple variables using STDIN

I'm trying to use to read in user input to a programme as follows:
#!/usr/bin/perl -w
use strict;
if ($#ARGV == 0) {
print "What condition are you sorting?\t";
chomp(my $condition = <STDIN>);
# Use $condition in further blocks of code...
}
This is working. However When I can't work out how to enter 2 (or more) values to be used in a similar fashion. E.g
if ($#ARGV == 1) {
print "What conditions are you comparing?\t";
chomp(my $condition1 = <STDIN>);
chomp(my $condition2 = <STDIN>);
Allows me to input twice, but the formatting is distorted:
What conditions are you comparing? <condition1>
<condition2>
You can enter conditions separated by comma or white space to preserve formatting,
chomp(my $input = <STDIN>);
my ($condition1, $condition2) = split /[\s,]+/, $input;

Perl program to calculate the sum of the numbers that the user enters

My script needs to get a series of numbers input by the user and find the average of them. I would like to use the line 'end-of-file' to show that the user is done inputting code. Any help would be appreciated. Below is what I have so far. I think I am really close, but I am missing something.
Code:
#! /usr/bin/perl
use 5.010;
print "Enter the scores and type end-of-file when done";
chomp(#scores = <STDIN>);
foreach (#scores) {
push_average(total(#scores));
}
sub total {
my $sum;
foreach (#_) {
$sum += $_;
}
sum;
}
sub average {
if (#_ == 0) {return}
my $count = #_;
my $sum = total(#_);
$sum/$count;
}
sub push_average {
my $average = average(#_);
my #list;
push #list, $average;
return #list;
}
You are quite close. Adding use strict; use warnings at the top of every Perl script will alert you of errors that might go unnoticed otherwise.
A few hints:
You forgot the sigil of $sum in the last statement of total. Currently, you return a string "sum" (without strict vars), or possibly call a sub called sum.
You don't need the foreach in the main part, rather do
my #averages = push_average(#scores);
The total is already calculated inside push_average
You probably want to print out the resulting average:
my $avg = $averages[0];
say "The average of these numbers is $avg";
The push_average is silly; you return a new array of one element. You could return that one element just as well.
Suggested script:
use strict; use warnings; use 5.010;
use List::Util qw/sum/; # very useful module
# say is like print, but appends a newline. Available with 5.10+
say "Please enter your numbers, finish with Ctrl+D";
my #nums = <STDIN>;
chomp #nums;
# The // is the defined-or operator
# interpolating undef into a string causes a warning.
# Instead, we give an expressive message:
my $avg = average(#nums) // "undefined";
say "The average was $avg";
sub average { #_ ? sum(#_) / #_ : undef } # return undef value if called without args
reads up to the newline. You've got a few choices here. You can ask the user to input the numbers separated by spaces and then split it into your #choices array. Or you can keep asking them to enter a number or just hit enter to finish.
Answer 1)
print "Enter scores separated by a space and press enter when done";
chomp($input = <STDIN>);
#choices = split(' ', $input);
Answer 2)
#chomp = ();
do {
print "Enter a score and then press enter. If done, just press enter.";
chomp($temp = <STDIN>);
if($trim ne '') {
push(#choices, $temp);
}
} until ($temp eq '');

simple perl addition program going wrong?

Hi i am a novice perl learner this simple perl program
$inputline= <STDIN>;
print "first input";
print( $inputline);
$inputline=<STDIN>;
print "second input";
print($inputline);
$sum= $inputline+$inputline;
print"sum 1stinput and 2ndinput";
print($sum);
output
perl count.pl
3
4
first input3
second input4
sum 1stinput and 2ndinput : 8
why is the output 8 instead of being 7?
Because you add $inputline to itself when it is 4.
If you want to sum the two inputs, you either have to do it with two variables, or do the addition before the variable changes. E.g.:
my $input1 = <>;
my $input2 = <>;
my $sum = $input1 + $input2;
print "Sum: $sum";
Or
my $input = <>;
my $sum = $input;
$input = <>;
$sum += $input;
print "Sum: $sum";
You could do something simpler, such as:
perl -nlwe '$sum += $_; print "Sum: $sum";'
Which is basically the equivalent of:
use strict;
use warnings; # always use these
my $sum;
while (<>) { # your input
$sum += $_;
print "Sum: $sum\n";
}
Use Ctrl-C or Ctrl-D to break out of the loop (Ctrl-Z in windows).
You're using the variable $intputline twice. The second time you refer to it, it overwrites the previous value. You need to use unique variable names for each variable:
$inputline1= <STDIN>;
print "first input";
print( $inputline1);
$inputline2=<STDIN>;
print "second input";
print($inputline2);
$sum= $inputline1+$inputline2;
print"sum 1stinput and 2ndinput";
print($sum);
How can Perl (or anyone else) distinguish $inputline from $inputline? Choose a different name for the second variable.
Always and without fail include the following pragmas at the top of your scripts:
use strict;
use warnings;
Use lexically-scoped variables ("my"):
my $inputline= <STDIN>;
print "first input";
print( $inputline);
my $inputline=<STDIN>;
...
Running this would raise the following exception:
"my" variable $inputline masks earlier declaration in same scope at ...
Using these pragmas and "my" can help you to avoid this and many other potentially problematic areas in your scripts.
Hope this helps!

Statistics in Perl Script

I have the following question:
I want to create a perl script that reads from a text file (file with several columns of numbers) and calculate some statistics (mean, median, sd, variance). I already built one script, but as I am not in love yet with perl, I can't fix the problems of syntax on it...
Here is my perl script..
#!/usr/bin/perl -w
use strict;
open(FILEHANDLE, data.txt);
while (<FILEHANDLE>) {
shift #ARGV;
my #array = split(\t,$_);
}
close(FILEHANDLE);
###### mean, sum and size
$N = $sum = 0;
$array[$x-1];
$N++;
$sum += $array[$x-1];
###### minimum and the maximum
($min = 0, $max = 0);
$max = $array[$x-1] if ($max < $array[$x-1]), (my#sorted = sort { $a <=> $b } #samples) {
print join(" ",#sorted);
}
##### median
if ($N % 2==1) {
print "$median = $sorted[int($N/2)]\n"; ## check this out
};
else ($median = ($sorted[$N/2] + $sorted[($N/2)-1]) / 2)) {
print "$median\n"; # check this out
};
##### quantiles 1º and 3º
if $qt1 = $sorted[$r25-1] {
print "\n"; # check this out
};
else $qt1 = $fr*($sorted[$ir] - $sorted[$ir-1]) + $sorted[$ir-1] {
print "\n"; # check this out
};
##### variance
for (my $i=0;
$i<scalar(#samples);
$i++)
{
$Var += ($samples[$i]-$mean)**2;
$Var = $Var/($N-1);
};
###### standard error
($Std = sqrt($Var)/ sqrt($N));
############################################################
print "$min\n";
print "$max\n";
print "$mean\n";
print "$median\n";
print "$qt1\n";
print "$var\n";
print "$std\n";
exit(0);
I want to get it working. Please help. THANKS IN ADVANCE!
Errors in your code:
open(FILEHANDLE, data.txt);
data.txt needs to be quoted. You are not checking the return value of the open, e.g. ... or die $!. You should use a lexical filehandle and three argument open, e.g. open my $fh, '<', "data.txt" or die $!.
shift #ARGV;
This does nothing except remove the first value from you argument list, which is then promptly discarded.
my #array = split(\t,$_);
You are using \t as a bareword, it should be a regex, /\t/. Your #array is declared inside a lexical scope of the while loop, and will be undefined outside this block.
$N = $sum = 0;
Both variables are not declared, which will cause the script to die when you use strict (which is a very good idea). Use my $N to solve that. Also, $N is not a very good variable name.
$array[$x-1];
This will do nothing. $x is not declared (see above), and also undefined. The whole statement does nothing, it is like having a line 3;. I believe you will get an error such as Useless use of variable in void context.
$N++;
This increments $N to 1, which is a useless thing to do, since you only a few lines above initialized it to 0.
Well.. the list goes on. I suggest you start smaller, use strict and warnings since they are very good tools, and work out the errors one by one. A very good idea would be to make subroutines of your calculations, e.g.:
sub sum {
# code here
return $sum;
}
Go to perldoc.perl.org and read the documentation. Especially useful would be the syntax related ones and perlfunc.
Also, you should be aware that this functionality can be found in modules, which you can find at CPAN.
Your main problem is you have not declared your variables such as $N, $max, etc.
You need to introduce all new variables with my the first time you reference them. Just like you did with $array and $i. So for example
$N = $sum = 0;
Should become
my( $N, $sum ) = ( 0, 0 );