Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

I'm trying to get a numeric array

by fatmac (Acolyte)
on Sep 03, 2012 at 10:53 UTC ( [id://991395]=perlquestion: print w/replies, xml ) Need Help??

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

Hi Monks, I'm a total newbie to perl, please be gentle on me. :-) (I'm reading Learning Perl at the moment.) I'm trying to fill an array with numeric data to use in my program, but 'warnings' say:
Argument "42 32 22" isn't numeric in multiplication (*) at ./multigear +.pl line 19, <STDIN> line 3. Argument "11 13 15 17 19 21" isn't numeric in division (/) at ./multig +ear.pl line 19, <STDIN> line 3. Use of uninitialized value in division (/) at ./multigear.pl line 20, +<STDIN> line 3. Illegal division by zero at ./multigear.pl line 20, <STDIN> line 3.
Below is my program, (which I will try to build & use nested loops in, when I can get it functioning).
#!/usr/bin/perl use strict; use warnings; print "\nMulti Gear Calculator\n\n"; print "Enter Wheelsize (inches): "; my $wheel = <STDIN>; #my $wheel = 26.5; chomp$wheel; print "Enter Chainwheel Teeth: "; my @chwhs = (<STDIN>); ###my $line; ###while($line = <STDIN>) { chomp $line; last unless $line =~ /\d/; pu +sh @chwhs, $line } #my @chwhs = qw (42 32 22); chomp@chwhs; print "Enter Cog Teeth: "; my @cogs = (<STDIN>); #my @cogs = qw (11 13 15 17 19 21 24 28 32); chomp@cogs; my $gear1 = $wheel*$chwhs[0]/$cogs[0]; my $gear2 = $wheel*$chwhs[0]/$cogs[1]; my $gear3 = $wheel*$chwhs[0]/$cogs[2]; my $gear4 = $wheel*$chwhs[0]/$cogs[3]; my $gear5 = $wheel*$chwhs[0]/$cogs[4]; my $gear6 = $wheel*$chwhs[0]/$cogs[5]; my $gear7 = $wheel*$chwhs[0]/$cogs[6]; my $gear8 = $wheel*$chwhs[0]/$cogs[7]; my $gear9 = $wheel*$chwhs[0]/$cogs[8]; my $gear10 = $wheel*$chwhs[1]/$cogs[0]; my $gear11 = $wheel*$chwhs[1]/$cogs[1]; my $gear12 = $wheel*$chwhs[1]/$cogs[2]; my $gear13 = $wheel*$chwhs[1]/$cogs[3]; my $gear14 = $wheel*$chwhs[1]/$cogs[4]; my $gear15 = $wheel*$chwhs[1]/$cogs[5]; my $gear16 = $wheel*$chwhs[1]/$cogs[6]; my $gear17 = $wheel*$chwhs[1]/$cogs[7]; my $gear18 = $wheel*$chwhs[1]/$cogs[8]; my $gear19 = $wheel*$chwhs[2]/$cogs[0]; my $gear20 = $wheel*$chwhs[2]/$cogs[1]; my $gear21 = $wheel*$chwhs[2]/$cogs[2]; my $gear22 = $wheel*$chwhs[2]/$cogs[3]; my $gear23 = $wheel*$chwhs[2]/$cogs[4]; my $gear24 = $wheel*$chwhs[2]/$cogs[5]; my $gear25 = $wheel*$chwhs[2]/$cogs[6]; my $gear26 = $wheel*$chwhs[2]/$cogs[7]; my $gear27 = $wheel*$chwhs[2]/$cogs[8]; my @gear1 = ($gear1, $gear2, $gear3, $gear4, $gear5, $gear6, $gear7, $ +gear8, $gear9); my @gear2 = ($gear10, $gear11, $gear12, $gear13, $gear14, $gear15, $ge +ar16, $gear17, $gear18); my @gear3 = ($gear19, $gear20, $gear21, $gear22, $gear23, $gear24, $ge +ar25, $gear26, $gear27); print "\nYour gears are:\n\n"; print "\nYour gears are:\n\n"; print "Wheelsize: $wheel\n"; print "Chainwheels: @chwhs\n"; print "Sprockets: @cogs\n\n"; print "@gear1\n\n"; print "@gear2\n\n"; print "@gear3\n\n";
This program should calculate cycle gear ratios from input entered from the keyboard. I have tried different ways to get the data, to no avail. Using data coded into the program, everything works fine. Can someone please point out my mistake(s).

Replies are listed 'Best First'.
Re: I'm trying to get a numeric array
by Gangabass (Vicar) on Sep 03, 2012 at 11:22 UTC
    You need to replace:
    my @chwhs = (<STDIN>);
    with:
    my $chwhs = <STDIN>; chomp $chwhs; my @chwhs = split /\s+/, $chwhs;
    Same thing for the @cogs. You're reading a line from standard input and you need to tell perl that this line contain several space separated values.
      Thankyou very much Gangabass for your reply, I shall put your code into my program, & go try with that.
        Your solution worked perfectly, thankyou.
Re: I'm trying to get a numeric array
by philiprbrenan (Monk) on Sep 03, 2012 at 11:54 UTC

    Please consider using for loops to simplify your array assignment logic to reduce the possibility of mistakes. pp() is very useful for checking that everything has worked as expected.

    use feature ":5.14"; use warnings FATAL => qw(all); use strict; use Data::Dump qw(dump pp); my $wheel = 2100; my @chwhs = qw (23 26 27); # test data my @cogs = qw (11 13 15 17 19 21 24 28 32); # test data my $gear; for my $c(0..2) {$gear->[$c][$_] = $wheel*$chwhs[$c]/$cogs[$_] for 0..8; } pp($gear);

    Produces

    [ [ "4390.90909090909", "3715.38461538462", 3220, "2841.17647058824", "2542.10526315789", 2300, "2012.5", 1725, "1509.375", ], [ "4963.63636363636", 4200, 3640, "3211.76470588235", "2873.68421052632", 2600, 2275, 1950, "1706.25", ], [ "5154.54545454546", "4361.53846153846", 3780, "3335.29411764706", "2984.21052631579", 2700, "2362.5", 2025, "1771.875", ], ]
      Thankyou very much for your reply philiprbrenan, I shall try that after Gangabass's code, (in a copy of my code).
Re: I'm trying to get a numeric array
by Athanasius (Archbishop) on Sep 03, 2012 at 14:11 UTC

    Hello, fatmac, and welcome to the Monastery!

    As you’ve no doubt found, typing in test data from the console quickly becomes tedious when you’re developing a script. What you need is a way to input data from the script itself but using the same syntax you would use for reading from the console (or from a separate data file). In Perl, that way is provided by the DATA filehandle, which reads input from the bottom of the script file beginning immediately after a line consisting of the __DATA__ token. The following script (which incorporates much of the advice of Gangabass and philiprbrenan, above) illustrates the use of DATA:

    #! perl use strict; use warnings; my $fh = \*DATA; # For user input, change to: \*STDIN print "\nMulti Gear Calculator\n\n"; print "Enter Wheelsize (inches): "; my $wheel = <$fh>; print $wheel; chomp $wheel; print "Enter Chainwheel Teeth: "; my $chwhs = <$fh>; print $chwhs; my @chwhs = split /\s+/, $chwhs; print "Enter Cog Teeth: "; my $cogs = <$fh>; print $cogs; my @cogs = split /\s+/, $cogs; my @gears; for (0 .. 8) { $gears[$_ + 1] = $wheel * $chwhs[0] / $cogs[$_]; $gears[$_ + 10] = $wheel * $chwhs[1] / $cogs[$_]; $gears[$_ + 19] = $wheel * $chwhs[2] / $cogs[$_]; } print "\nYour gears are:\n\n"; print 'Wheelsize: ', $wheel, "\n"; print 'Chainwheels: ', join(' ', @chwhs), "\n"; print 'Sprockets: ', join(' ', @cogs), "\n\n"; for (1 .. 27) { printf "%6.2f ", $gears[$_]; print "\n\n" if $_ % 9 == 0; } __DATA__ 26.5 42 32 22 11 13 15 17 19 21 24 28 32

    When you’re finished testing, and want to use the script to input data from the console, simply change the line

    my $fh = \*DATA;

    to

    my $fh = \*STDIN;

    and you’re there!

    Hope that helps,

    Athanasius <°(((><contra mundum

      Thankyou very much for your reply Athanasius, that is very interesting, & I have made a note for future reference. I shall try that out in a copy of my program.
Re: I'm trying to get a numeric array
by ww (Archbishop) on Sep 03, 2012 at 16:33 UTC
    Gangabass has correctly identified your failure to split the second input string (chwhs); you need to do likewise with the third (cogs).

    But you also have to correct your calculations section to deal with the division by zero problem: you have nine tooth-counts (elements) in @chwhs but, as written, you use only three, $chwhs[0], $chwhs[1] and $chwhs[2] while attempting to use 9 elements of @cogs which has only three elements, 42, 32 and 22.

    Without too much diddling your code, you can fix that problem, thusly:

    #!/usr/bin/perl use 5.014; # 9913950mod print "\nMulti Gear Calculator\n\n"; print "\ Enter Wheelsize (inches): "; my $wheel = <STDIN>; chomp $wheel; print "\n Enter nine numeric values for Chainwheel Teeth: "; # 11 13 1 +5 17 19 21 24 28 32 my $chwhs = <STDIN>; chomp $chwhs; my @chwhs = split (/\s+/, $chwhs); chomp @chwhs; print "\n Enter three numeric values for Cog Teeth: "; # 42 33 22 my $cogs = <STDIN>; chomp $cogs; say "\t $cogs \n\n"; # DEMO: SEE co +mment in output my @cogwheels = split (/\s+/, $cogs); chomp @cogwheels; my $gear1 = $wheel * $chwhs[0]/$cogwheels[0]; my $gear2 = $wheel * $chwhs[1]/$cogwheels[0]; my $gear3 = $wheel * $chwhs[2]/$cogwheels[0]; my $gear4 = $wheel * $chwhs[3]/$cogwheels[0]; my $gear5 = $wheel * $chwhs[4]/$cogwheels[0]; my $gear6 = $wheel * $chwhs[5]/$cogwheels[0]; my $gear7 = $wheel * $chwhs[6]/$cogwheels[0]; my $gear8 = $wheel * $chwhs[7]/$cogwheels[0]; my $gear9 = $wheel * $chwhs[8]/$cogwheels[0]; my $gear10 = $wheel * $chwhs[0]/$cogwheels[1]; my $gear11 = $wheel * $chwhs[1]/$cogwheels[1]; my $gear12 = $wheel * $chwhs[2]/$cogwheels[1]; my $gear13 = $wheel * $chwhs[3]/$cogwheels[1]; my $gear14 = $wheel * $chwhs[5]/$cogwheels[1]; my $gear15 = $wheel * $chwhs[4]/$cogwheels[1]; my $gear16 = $wheel * $chwhs[5]/$cogwheels[1]; my $gear17 = $wheel * $chwhs[6]/$cogwheels[1]; my $gear18 = $wheel * $chwhs[7]/$cogwheels[1]; my $gear19 = $wheel * $chwhs[0]/$cogwheels[2]; my $gear20 = $wheel * $chwhs[1]/$cogwheels[2]; my $gear21 = $wheel * $chwhs[2]/$cogwheels[2]; my $gear22 = $wheel * $chwhs[3]/$cogwheels[2]; my $gear23 = $wheel * $chwhs[4]/$cogwheels[2]; my $gear24 = $wheel * $chwhs[5]/$cogwheels[2]; my $gear25 = $wheel * $chwhs[6]/$cogwheels[2]; my $gear26 = $wheel * $chwhs[7]/$cogwheels[2]; my $gear27 = $wheel * $chwhs[8]/$cogwheels[2]; my @gear1 = ($gear1, $gear2, $gear3, $gear4, $gear5, $gear6, $gear7, $ +gear8, $gear9); my @gear2 = ($gear10, $gear11, $gear12, $gear13, $gear14, $gear15, $ge +ar16, $gear17, $gear18); my @gear3 = ($gear19, $gear20, $gear21, $gear22, $gear23, $gear24, $ge +ar25, $gear26, $gear27); my $rounded; # re-used throughout the output funcs below print "\n Your gear ratios are: \n"; print "\n Sprocket 1: "; for (@gear1) { $rounded = sprintf("%.3f", $_); print $rounded . " | "; } print "\n Sprocket 2: "; for (@gear2) { $rounded = sprintf("%.3f", $_); print $rounded . " | "; } print "\n Sprocket 3: "; for (@gear3) { $rounded = sprintf("%.3f", $_); print $rounded . " | "; } print "\nWheelsize: $wheel \n"; print "Chainwheels: @chwhs \n"; print "Cogteeth: @cogwheels \n\n"; =head execution (annotate): C:\>991395OPmod.pl Multi Gear Calculator Enter Wheelsize (inches): 26.5 Enter nine numeric values for Chainwheel Teeth: 11 13 15 17 19 21 24 +28 32 Enter three numeric values for Cog Teeth: 42 32 22 42 32 22 # Perl sees the three values from <STDIN> as a SING +LE, non-numeric string # that's why we need to split them, to get three nu +meric values Your gear ratios are: Sprocket 1: 6.940 | 8.202 | 9.464 | 10.726 | 11.988 | 13.250 | 15.143 + | 17.667 | 20.190 | Sprocket 2: 9.109 | 10.766 | 12.422 | 14.078 | 17.391 | 15.734 | 17.3 +91 | 19.875 | 23.188 | Sprocket 3: 13.250 | 15.659 | 18.068 | 20.477 | 22.886 | 25.295 | 28. +909 | 33.727 | 38.545 | Wheelsize: 26.5 Chainwheels: 11 13 15 17 19 21 24 28 32 Cogteeth: 42 32 22 =cut

    philiprbrenan incorporates that necessity, but -- unfortunately for the clarity of his example -- ...

    1. employs syntax which seems to me far to advanced for easy comprehension by a "total newbie to perl ...(who's) reading Learning Perl "
    2. uses a wheel size of "2100" which is 175 feet (assuming English measure; if it's millimeters, 82.67717 inches or a tad under 7 feet... which is still, IMO, a bit too large)
    3. reverses the tooth-count names (in effect, putting 8 different sprockets at the pedals and only 3 at the rear (which defies conventional design)

    Modifying his code to use your data and design,

    #!/usr/bin/perl use 5.014; use warnings FATAL => qw(all); use strict; use Data::Dump qw(dump pp); # 9913950PB my $wheel = 26.5; my @chwhs = qw (11 13 15 17 19 21 24 28 32); # test data my @cogs = qw (42 32 22); # test data my $gear; for my $c(0..8) { $gear->[$c][$_] = $wheel * $chwhs[$c]/$cogs[$_] for 0..2; } pp($gear);

    one obtains output -- formatted differently -- but similar to the above:

    [ [6.94047619047619, 9.109375, 13.25], [8.20238095238095, 10.765625, 15.6590909090909] [9.46428571428571, 12.421875, 18.0681818181818] [10.7261904761905, 14.078125, 20.4772727272727] [11.9880952380952, 15.734375, 22.8863636363636] [13.25, 17.390625, 25.2954545454545], [15.1428571428571, 19.875, 28.9090909090909], [17.6666666666667, 23.1875, 33.7272727272727], [20.1904761904762, 26.5, 38.5454545454545], ]

    update: Note, however, that philiprbrenan's code DOES exhibit the virtue of succinctness while Athanasius' use of a data section and the easy mod from  my $fh = \*DATA; to  my $fh = \*STDIN; has great merit -- especially for a newcomer who may have to interate test runs, ad nauseum.

    and... interspersed updates to fix my formatting in this overlong observation... BUT, I'm still not sure why the ratio values are interspersed rather than sequential across their entire span from gear1 to gear27.

      Thankyou for your reply, but there are only 3 chainwheels & there are 9 cogs. I am taking note of your rounding code section, as that will be a further neccessary enhancement, as will checking how many chainwheel & cogs have been entered. I appreciate all answers to my first question on here, & will be trying all suggestions. Once again, thankyou to all who answered.
Re: I'm trying to get a numeric array
by GrandFather (Saint) on Sep 03, 2012 at 22:06 UTC
    "which I will try to build & use nested loops in, when I can get it functioning"

    Exactly the wrong way around! Think structure (overall program structure and data structure) first, then details. By the time you've written the details it is far too late to go back and rethink the structures.

    For complicated projects it's often said "write the first version to throw away". It's only when the first version has been written that you have an idea of how you perhaps should have written it. Getting a better first cut is mostly a matter of experience.

    A major red flag (code smell/stink) is variable names with index numbers in them. Whenever you find yourself doing that, change to using an array. For your current task however that just isn't an issue because you don't need to store the intermediate values at all. Consider:

    #!/usr/bin/perl use strict; use warnings; my $wheel = 26.5; my @chainWheels = qw (42 32 22); my @cogs = qw (11 13 15 17 19 21 24 28 32); print "Wheelsize: $wheel\n"; print "Chainwheels: @chainWheels\n"; print "Sprockets: @cogs\n\n"; for my $chainSel (1 .. @chainWheels) { my $wheelMul = $wheel * $chainWheels[$chainSel - 1]; print "Chain wheel: $chainSel ratios: \n"; for my $cogSel (1 .. @cogs) { printf "%d: %5.2f ", $cogSel, $wheelMul / $cogs[$cogSel - 1]; } print "\n"; }

    Prints:

    Wheelsize: 26.5 Chainwheels: 42 32 22 Sprockets: 11 13 15 17 19 21 24 28 32 Chain wheel: 1 ratios: 1: 101.18 2: 85.62 3: 74.20 4: 65.47 5: 58.58 6: 53.00 7: 46.38 8: 39. +75 9: 34.78 Chain wheel: 2 ratios: 1: 77.09 2: 65.23 3: 56.53 4: 49.88 5: 44.63 6: 40.38 7: 35.33 8: 30.2 +9 9: 26.50 Chain wheel: 3 ratios: 1: 53.00 2: 44.85 3: 38.87 4: 34.29 5: 30.68 6: 27.76 7: 24.29 8: 20.8 +2 9: 18.22
    True laziness is hard work
      Thankyou very much for your reply GrandFather; nested loops was to be my next challenge, & you have provided me with an excellent example.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://991395]
Approved by marto
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (6)
As of 2024-03-19 10:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found