catfish1116 has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to sum a group of numbers from user input and am getting errors

say "Please input numbers to be summed. Crtl-D to stop"; my $user_total = &total(<STDIN>); chomp($user_total); #print "The total of inputted numbers is $user_total \n"; sub total { state $sum = 0; state $number; foreach my $number (@_) { $sum += $number; } return $sum; } ~ Please input numbers to be summed. Crtl-D to stop 12 12 Argument "12 12\n" isn't numeric in addition (+) at ./Chapter_Exer1A l +ine 17, <STDIN> line 1.

I can get this to work if I'm just reading from a hard coded list, but getting user input is not working for me. TIA Catfish

Replies are listed 'Best First'.
Re: Summing numbers
by davido (Cardinal) on Nov 19, 2018 at 22:05 UTC

    Your code is not designed to accept more than one number per line.

    It's also got a number of other design flaws, but that's the specific one biting you here.


    Dave

Re: Summing numbers
by 1nickt (Canon) on Nov 19, 2018 at 22:03 UTC

    Hi, you need to gather the input into a variable first, and then see if there is more than one number per line entered, something like this (adds a little error checking too):

    use strict; use warnings; use feature 'say'; use Scalar::Util 'looks_like_number'; say "Please input numbers to be summed. Crtl-D to stop"; my $user_input; while ( <STDIN> ) { $user_input .= $_; } total( $user_input ); sub total { my $in = shift or die 'No numbers provided!'; my $user_total = 0; for my $line ( split "/n", $in ) { chomp $line; for my $num ( split /\W+/, $line ) { die "$num doesn't look like a number!" if not looks_like_n +umber( $num ); $user_total += $num; } } say "Total: $user_total"; } __END__
    Output:
    $ perl 1226028.pl Please input numbers to be summed. Crtl-D to stop 12 12 Total: 24 $

    Hope this helps!


    The way forward always starts with a minimal test.
Re: Summing numbers
by AnomalousMonk (Archbishop) on Nov 20, 2018 at 00:09 UTC

    Another way:

    c:\@Work\Perl\monks>perl -wMstrict -le "use List::Util qw(sum); use Regexp::Common; ;; my $user_total = total(<STDIN>); ;; print qq{The total of user-input integers is $user_total}; ;; sub total { ;; my $n = $RE{num}{real}; ;; die qq{user input <<@_>> unuseable} unless @_ == map m{ \A \s* $n (?: \s+ $n)* \s* \z }xms, @_; ;; return sum map m{ $n }xmsg, @_; } " 123 4. .5 0.0 .0 0. -.7 -11 ^Z The total of user-input integers is 115.8
    (On Windoze: Must use ctrl-Z to terminate input.) (Good luck with your homework.)

    Update: Here's yet another and, I think, better way. A single join is almost certainly going to be more efficient than two map-s; I don't know what I was thinking! (Minimally tested.)

    sub total { my $u_i = join '', @_; my $n = $RE{num}{real}; ;; die 'user input >>', @_, '<< unuseable' unless $u_i =~ m{ \A \s* $n (?: \s+ $n)* \s* \z }xms; ;; return sum $u_i =~ m{ $n }xmsg; }


    Give a man a fish:  <%-{-{-{-<

Re: Summing numbers -- oneliner
by Discipulus (Canon) on Nov 20, 2018 at 10:39 UTC
    Hello catfish1116

    you already got good answers: a question: why you use state ? I personally never used it and I wonder if is the right thing to do in your example.

    Anyway I offer you a oneliner (bewere of windows doublequotes!) use CTRL-Z on an empty line to end STDIN input. use CTRL-D on linux:

    perl -e "$sum += $_ while $_ = <STDIN> and chomp; print qq(total: $sum +\n)" 1 2 3 4 ^Z total: 10

    You also find useful the evil form of eval like in perl -e "push @sum,$_ while $_ = <STDIN> and chomp; print qq(total: ),(eval join '+',@sum),qq(\n)"

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Summing numbers
by BillKSmith (Monsignor) on Nov 20, 2018 at 15:35 UTC
    Nothing is actually wrong with your code. Enter numbers one per line.
    $type 1226028.pl use feature qw(say state); say "Please input numbers to be summed. Crtl-D to stop"; my $user_total = &total(<STDIN>); chomp($user_total); print "The total of inputted numbers is $user_total \n"; sub total { state $sum = 0; state $number; foreach my $number (@_) { $sum += $number; } return $sum; } $perl 1226028.pl Please input numbers to be summed. Crtl-D to stop 12 12 ^Z The total of inputted numbers is 24
    Note: I added 'feature' statement and used CTRL-Z rather than CTRL-D
    Bill