http://qs1969.pair.com?node_id=109986

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

<html> <body>

I have been working on a program to work out the angles/sides of triangles using Sine/CoSine rules for a project I've benn working on. However my code has reached about 5 pages to print out, this seems a little long for my tastes. Could someone give me a hand refining it a bit please :) And yes I know that I didn't use strict; but I didn't have the time and it wasn't really worth it with all the subroutines.

Note: the code gives errors when run as somethings are no implemented properly yet....

The Evil But Fickle Dr Lambado
Give up being witty, most people don't understand the obvious.

#!/usr/bin/perl -w #define pi... $pi = 3.141; # This part basically defines which rule you want to use.... print "Welcome to the Lawrence's maths coursework, trig sepcial! \n"; print "What rule do you want to use? (cos/SIN) "; chomp($whatrule = <STDIN>); if ( $whatrule eq "cos") { &sub_cos; }elsif ($whatrule eq "sin") { &sub_sin; }else{ &sub_haiku; print "$haiku"; } # What to do if the rule is CoSine sub sub_cos { my ($whatfind0) = @_; print "What do you want to find? "; chomp($whatfind0 = <STDIN>); if ( $whatfind0 eq "a") { &sub_a_cos; }elsif ( $whatfind0 eq "b") { &sub_b_cos; }elsif ($whatfind0 eq "c") { &sub_c_cos; }else{ &sub_haiku; print $haiku; } $whatfind = $whatfind0; } # What to do if the rule is Sin sub sub_sin { my ($whatfind0) = @_; print "What do you want to find? "; chomp($whatfind0 = <STDIN>); if ( $whatfind0 eq "a") { &sub_a_sin; }elsif ( $whatfind0 eq "b") { &sub_b_sin; }elsif ($whatfind0 eq "c") { &sub_c_sin; }else{ &sub_haiku; print $haiku; } $whatfind = $whatfind0; } # A subroutine to find a when the rule is cos..... sub sub_a_cos { my ($b,$c,$A,$cosA,$asq,$noradA) = @_; print "What is b? "; chomp($b = <STDIN>); print "What is c? "; chomp($c = <STDIN>); print "What is A? "; chomp($A = <STDIN>); $cosA = &cos($A); $noradA = $cosA*180/$pi; $asq = ($b*$b+$c*$c-2*$b*$c*$noradA); $answer = sqrt($asq); $reala = "?"; $realb = $b; $realc = $c; $realA = $A; $realB = "?"; $realC = "?"; &work; } # A subroutine to find b when the rule is cos..... sub sub_b_cos { my ($a,$c,$B,$bsq,$cosB,$noradB) = @_; print "What is a? "; chomp($a = <STDIN>); print "What is c? "; chomp($c = <STDIN>); print "What is B? "; chomp($B = <STDIN>); $cosB = &cos($B); $noradB = $cosB*180/$pi; $bsq = ($a*$a+$c*$c-2*$a*$c*$noradB); $answer = sqrt($bsq); $reala = $a; $realb = "?"; $realc = $c; $realA = "?"; $realB = $B; $realC = "?"; &work; } # A subroutine to find c when the rule is cos..... sub sub_c_cos { my ($a,$b,$C,$csq,$cosC,$cunrad) = @_; print "What is a? "; chomp($a = <STDIN>); print "What is b? "; chomp($c = <STDIN>); print "What is C? "; chomp($B = <STDIN>); $cosC = &cos($C); $cunrad = $cosC*180/$pi; $csq = ($a*$a+$b+$b-2*$a*$b*$cunrad); $answer = sqrt($csq); $reala = $a; $realb = $b; $realc = "?"; $realA = "?"; $realB = "?"; $realC = $C; &work; } # A subroutine to find a when the rule is sin..... sub sub_a_sin { my ($b,$B,$A,$C,$c,$whathave,$aans,$sinA,$sinB,$sinC,$Aunrad,$Bunrad,$ +Cunrad) = @_; print "What do you have? [AbB/AcC] "; chomp($whathave = <STDIN>); if ($whathave eq "AbB") { print "What is A?"; chomp($A = <STDIN>); print "What is b?"; chomp($b = <STDIN>); print "What is B?"; chomp($B = <STDIN>); $sinA = &sin($A); $Aunrad = $sinA*180/$pi; $sinB = &sin($B); $Bunrad = $sinB*180/$pi; $aans = $b*$Aunrad/$Bunrad; $answer = $aans; $reala = "?"; $realb = $b; $realc = "?"; $realA = $A; $realB = $B; $realC = "?"; $whatfound = a1; }elsif ($whathave eq "AcC") { print "What is A?"; chomp($A = <STDIN>); print "What is c?"; chomp($c = <STDIN>); print "What is C?"; chomp($C = <STDIN>); $sinC = &sin($C); $Cunrad = $sinC*180/$pi; $sinB = &sin($B); $Bunrad = $sinB*180/$pi; $aans = $b*$Cunrad/$Bunrad; $answer = $aans; $reala = "?"; $realb = "?"; $realc = $c; $realA = $A; $realB = "?"; $realC = $C; $whatfound = a2; }else{ print "$haiku\n"; } &work; } # A subroutine to find b when the rule is sin..... # Here too..... sub sub_b_sin { my ($a,$B,$A,$C,$c,$whathave,$bans,$sinA,$sinB,$sinC,$Aunrad,$Bunrad,$ +Cunrad) = @_; print "What do you have? [aBA/cBC] "; chomp ($whathave = <STDIN>); if ($whathave eq "aBA") { print "What is a?"; chomp($a = <STDIN>); print "What is B?"; chomp($B = <STDIN>); print "What is A?"; chomp($A = <STDIN>); $sinB = &sin($B); $Bunrad = $sinB*180/$pi; $sinA = sin($A); $Aunrad = $sinA*180/$pi; $bans = $a*$Bunrad/$Aunrad; $answer = $bans; $reala = $a; $realb = "?"; $realc = "?"; $realA = $A; $realB = $B; $realC = "?"; $whatfound = b1; }elsif ($whathave eq "cBC") { print "What is c?"; chomp($c = <STDIN>); print "What is B?"; chomp($B = <STDIN>); print "What is C?"; chomp($C = <STDIN>); $sinB = sin($B); $Bunrad = $sinB*180/$pi; $sinC = sin($C); $Cunrad = $sinC*180/$pi; $bans = $c*$Bunrad/$Cunrad; $answer = $bans; $reala = "?"; $realb = "?"; $realc = $c; $realA = "?"; $realB = $B; $realC = $C; $whatfound = b2; }else{ &sub_haiku; print "$haiku\n"; } &work; } # A subroutine to find c when the rule is sin..... sub sub_c_sin { my ($a,$b,$B,$A,$C,$whathave,$cans,$sinC,$Cunrad,$sinB,$Bunrad,$sinA,$ +Aunrad) = @_; print "What do you have? [bCB/aCA] "; chomp($whathave = <STDIN>); if ($whathave eq "bCB") { print "What is b?"; chomp($b = <STDIN>); print "What is C?"; chomp($C = <STDIN>); print "What is B?"; chomp($B = <STDIN>); $sinC = sin($C); $Cunrad = $sinC*180/$pi; $sinB = sin($B); $Bunrad = $sinB*180/$pi; $cans = $b*$Cunrad/$Bunrad; $answer = $cans; $reala = "?"; $realb = $b; $realc = "?"; $realA = "?"; $realB = $B; $realC = $C; $whatfound = c1; }elsif ($whathave eq "aCA") { print "What is a?"; chomp($a = <STDIN>); print "What is C?"; chomp($C = <STDIN>); print "What is A?"; chomp($A = <STDIN>); $sinC = sin($C); $Cunrad = $sinC*180/$pi; $sinB = sin($A); $Bunrad = $sinA*180/$pi; $cans = $a*$Cunrad/$Aunrad; $answer = $cans; $reala = $a; $realb = "?"; $realc = "?"; $realA = $A; $realB = "?"; $realC = $C; $whatfound = c2; }else{ &sub_haiku; print "$haiku\n"; } &work; } # A subroutine to decide which working to print..... sub work { if ($whatrule eq "sin") { &sin_work_gen; }elsif ($whatrule eq "cos") { &cos_work_gen; } &to_file; } # A sine working generator..... sub sin_work_gen { if ($whatfind eq "a") { $workgubbins = "<p align = \"center\">a&sup2; = b&sup2; + c&sup2; - (2 +bc CosA)</p>"; }elsif ($whatfind eq "b") { $workgubbins = "<p align = \"center\">b&sup2; = a&sup2; + c&sup2; - (2 +ac CosB)</p>"; }elsif ($whatfind eq "c") { $workgubbins = "<p align = \"center\">c&sup2; = a&sup2; + b&sup2; - (2 +ab CosC)</p>"; }else{ &sub_haiku; print "$haiku\n";} } # A CoSine working generator..... sub cos_work_gen { if ($whatfound eq "a1") { $workgubbins = "<p align = \"center\"><u>a</u> &nbsp; = &nbsp; <u>b</u +><br>SinA&nbsp;&nbsp;&nbsp;SinB<br>SinB x a = b x SinA<br>a = b x <u> +SinA</u><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb +sp;&nbsp;&nbsp;&nbsp;SinB<br></p>"; }elsif ($whatfound eq "a2") { $workgubbins = "<p align = \"center\"><u>a</u> &nbsp; = &nbsp; <u>c</u +><br>SinA&nbsp;&nbsp;&nbsp;SinC<br>SinC x a = c x SinA<br>a = c x <u> +SinA</u><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb +sp;&nbsp;&nbsp;&nbsp;SinC<br></p>"; }elsif ($whatfound eq "b1") { $workgubbins = "<p align = \"center\"><u>b</u> &nbsp; = &nbsp; <u>a</u +><br>SinB&nbsp;&nbsp;&nbsp;SinA<br>b x SinA = a x SinB<br>b = a x <u> +SinB</u><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb +sp;&nbsp;&nbsp;&nbsp;SinA<br></p>"; }elsif ($whatfound eq "b2") { $workgubbins = "<p align = \"center\"><u>b</u> &nbsp; = &nbsp; <u>c</u +><br>SinB&nbsp;&nbsp;&nbsp;SinC<br>b x SinC = c x SinB<br>b = c x <u> +SinB</u><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb +sp;&nbsp;&nbsp;&nbsp;SinC<br></p>"; }elsif ($whatfound eq "c1") { $workgubbins = "<p align = \"center\"><u>c</u> &nbsp; = &nbsp; <u>b</u +><br>SinC&nbsp;&nbsp;&nbsp;SinB<br>c x SinB = b x SinC<br>c = b x <u> +SinC</u><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb +sp;&nbsp;&nbsp;&nbsp;SinB<br></p>"; }elsif ($whatfound eq "c2") { $workgubbins = "<p align = \"center\"><u>c</u> &nbsp; = &nbsp; <u>a</u +><br>SinC&nbsp;&nbsp;&nbsp;SinA<br>c x SinA = a x SinC<br>c = a x <u> +SinC</u><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb +sp;&nbsp;&nbsp;&nbsp;SinA<br></p>"; }else{ &sub_haiku; print "$haiku\n";} } # A subroutine to print the answers to a file..... sub to_file { my ($file_gubbins,$work) = @_; open(FILE, ">answerfile.txt"); $file_gubbins = "<html><body><h1><u><b>Triangle number $tridone</b></u +></h1><br>For this triangle I used $whatrule<br><br><br><br>triangle +pic<br><br><br><ul>A = $realA<br>B = $realB<br>C = $realC<br>a = $rea +la<br>b = $realb<br>c = $realc<br></ul><br>$workgubbins<br><br><br><b +r>So the answer is $answer<br><br></body></html>"; write ($file_gubbins); close (FILE); } # A subroutine to do error message generation sub sub_haiku { my ($h1,$h2,$h3,$h4,$h5,$h6,$h7,$h8,$h9,$h10,$h11,$h12,$h13,$h14,$h15, +$h16,@haikus) = @_; $h1 = "A file that big?\nIt must be very useful.\nBut now it is gone.\ +n"; $h2 = "You seek a Website.\nIt cannot be located.\nCountless more exis +t.\n"; $h3 = "Chaos reigns within.\nStop, reflect, and reboot.\nOrder shall r +eturn.\n"; $h4 = "ABORTED effort.\nClose all that you have worked on.\nYou ask wa +y too much.\n"; $h5 = "Yesterday it worked.\nToday it is not working.\nWindows is like + that.\n"; $h6 = "First snow, then silence.\nThis thousand dollar screen dies\nSo + beautifully\n"; $h7 = "With searching comes loss.\nThe presence of absence.\nJuneSales +.doc not found\n"; $h8 = "The Tao that is seen\nIs not the true Tao.\nUntil you bring fre +sh toner.\n"; $h9 = "Windows NT crashed.\nThe Blue Screen of Death.\nNo one hears yo +ur screams.\n"; $h10 = "Stay the patient course.\nOf little worth is your ire.\nThe ne +twork is down.\n"; $h11 = "A crash reduces\nYour expensive computer\nTo a simple stone.\n +"; $h12 = "Three things are certain:\nDeath, Taxes and Lost Data.\nGuess +which has ocurred.\n"; $h13 = "You step in the stream.\nBut the water has moved on.\nPage Not + Found.\n"; $h14 = "Out of memory.\nWe wish to hold the whole sky\nBut we never wi +ll.\n"; $h15 = "Having been erased,\nThe document you are seeking\nMust now be + re-typed.\n"; $h16 = "Serious error.\nAll shortcuts have disappeared.\nScreen. Mind. + Both are blank.\n"; @haikus = ($h1, $h2, $h3, $h4, $h5, $h6, $h7, $h8, $h9, $h10, $h11, $h +12, $h13, $h14, $h15, $h16); $haiku = $haikus[rand @haikus]; } # sub_haiku is not mine # copyright 2001 azatoth # haikus courtesy of salon.com - thanks dws for source!
</body> </html>

Replies are listed 'Best First'.
Re: Trig in Perl
by neophyte (Curate) on Sep 04, 2001 at 12:17 UTC
    You could make your life a lot easier:
    CPAN is your friend - look at Math::Trig for your needs of Trig.
    It gives you PI sin, cos, tan and all arcus funcions. It has helped me a lot :)

    neophyte Niederrhein.pm

(redmist) Re: Trig in Perl
by redmist (Deacon) on Sep 04, 2001 at 11:54 UTC

    There are many style issues (indentation, variable naming schemes) that I would change, but the thing that would probably help you most would be to use Perl's built-in trigonometry operators: cos, sin, atan2, etc. Also, you might want to get rid of sub_haiku(), opting for Carp or warn and die. Also use constant PI => 3.14159 would be a more proper way to define pi that $pi = 3.141.

    Beyond that, I don't know what to tell you. Through experience (as long as you care about doing things elegantly and efficiently), you will learn how to shorten code and make it look (and be) cleaner and sexier.

    redmist
    Purple Monkey Dishwasher

      Also, you might want to get rid of sub_haiku(), opting for Carp or warn and die.
      Or use Damian Conways's Coy to die with style and haiku ;-)

      -- Hofmator

        <html><body>

        Thanks for that, I'll try them out as I had not heard of them before :)

        Dr Lambado

        </body></html>
Re (tilly) 1: Trig in Perl
by tilly (Archbishop) on Sep 04, 2001 at 16:27 UTC
    I don't understand this attitude.

    You know that we are going to advise you to use strict.pm. But you don't because you don't think you had time, and you don't think that it is really worth it with all of your code. Yet you think that we should take out the time to analyze and fix your code for you.

    That is exactly backwards.

    The times to not use strict.pm are when you are writing so little code that you don't need its assistance, or for short blocks where you don't want what it does for very specific reasons. Otherwise avoiding it leads to your taking more time. Furthermore the more code you write, the worse it is.

    Beyond that my advice is standard. Indent properly. Think about your problem, try to find common logic so that you don't have to have large sections of similar code. (For instance don't have 3 sets of subroutines depending on which angle you are working on, instead relabel.) Avoid global variables. Etc.

      <html> <body>

      Just a few little points, this is not meant as flamebait, take it as you like, it's just some little things that I've noticed in the past 3 months of programming with perl....
      There seems to be something going on in the perl community (here, #perl, #perlhelp, and c.l.p) about the use strict; pragma. Fair enough if you want to do it if you want to distribute you code to be modified among others this is necessary, I see a use for it. And I take your point about if I want people to help with my code I should have used strict, fair enough. But isn't perl's slogan "There's more than one way to do it"? It seems silly to use it when I only had a half-dozen global variables.
      As for the indent thing, what do you mean? I have never read anything about this before. If you're not mad at me about the above a link would be nice so I can format the code :)
      One side note, I haven't actually read much about perl, I don't know that much, I learnt quite a lot just from reading the perldoc pages and working it out. Apart from that all I read is about a 6th of the Camel Book which I invested in a few weeks ago. The point I'm trying to make is I would apreciate you not going down my neck about not using a sepcific pragma :)
      Apart from that, thanks for the help :))

      Dr Lambado
      Btw, one day I will work out how to use strict; and then I will post code, but if I get this reception everytime I post I won't bother


      </body></html>
        About strict. What I was reacting to was your saying you knew about it but couldn't be bothered to use it. If you know about it, know that it is supposed to help, don't use it because you "can't be bothered", and then want help, that is irritating. If you don't know about it, different story. If you don't know how to use it, we should solve that.

        Had you said you hadn't figured out how to use it, a dozen people would have given you clear instructions. Had you not mentioned it, people would assume you didn't know about it and tell you about it.

        Let me tell you about strict.pm. All that you do is this. In the first 5 lines of the program put:

        use strict; use vars qw( );
        Then proceed to write your program, declaring variables with my as you did. The small number of global variables you have you put into the list you are feeding vars. Like this:
        use vars qw( $thing @list %lookup );
        Now as you develop Perl will be able to spot many typos for you.

        When should you do this? Well not based on the number of globals in your program (many of mine have no globals at all). Instead it depends on how many lines of code you might accidentally create a global with a typo. A decent rule of thumb is 20 lines. If your program goes over 20 lines, put strict in.

        Now why are people so quick to say this? Well TIMTOWTDI, but not all ways are created equal. Through long experience, most of us have learned that fact...

        Now about indents. The idea is simple. The indentation on each line should indicate scope. Every time you open a new function, if statement, etc, indent farther. That way just glancing at your code will show the intended logical structure. This makes code much easier to scan, analyze, and makes it possible to figure out many typos. To get an idea what it should look like you can download perltidy and run it on your code.

        Trust me. It makes a huge difference.

        The value of consistent formatting is not specific to Perl. It applies in all programming languages. An excellent place to learn about programming details like this is the often recommended Code Complete by Steve McConnell. Its examples tend to be in C and Pascal, but the advice is timeless.

        But isn't perl's slogan "There's more than one way to do it"?

        Indeed it is. You recognized that your way wasn't the best way, and you asked for advice. If you recognize that lots of people really know how to program Perl well, that those same people recommend strict, and if you ask those people for advice, why in the world wouldn't you take their advice?

        Suppose you misspelled just one of your variables in the middle of sub_b_sin(). How would you catch that? With strict, it's easy.

        You're getting free advice from people who had to learn Perl the hard way, often before there were such niceties as the Monastery and comp.lang.perl.misc. If you complain about it, expect the price to rise.

        I'll cut short this lecture and help you with the indenting issue. Have a read through perldoc perlstyle. Then take a look at perltidy. It's a wonderful program that nicely formats source code. With a little experience, you'll find that good indentation really contributes to the readability of a program.

        Good luck.

        There's nothing to "work out". It's very easy. Just add:
        use strict; use warnings;
        as the first lines in your program. That's it. Now sit back as it finds all your typo's for you, and warns about fishy things happening as it runs! Isn't that great? Isn't that what you were asking us for in the first place?

        I think you get the wrong idea of our "attitude" because you don't know what "strict" is for. Your initial comment about "not worth it because of all the subs" also makes me thing that.

        As for your formatting question, the concept is pretty basic: subordinate things are indented farther than its controlling logic or framing structures. Anything else is details and subject to personal taste. Just be consistant, and follow that guiding principle, and you'll be fine.

        Yes, you will get the reception "use strict, then ask again after fixing everything it finds for you" if you post code that doesn't. Every time.

        Good luck, and keep trying.

        —John

        Yes, TIMTOWDI, but do not forget: perl's concept of freedom is to give you enough rope to hang yourself.

        Look, many experienced members of our community can see that you are going to hang yourself, and they ask you friendly is this is your real intention, or just misunderstanding. And what are you doing? Your answer is: "No time to free my neck out of loop, too busy make loop fit and tightening it"...;-) ... Should we stop you? We are trying...;-)

        I am rather experienced programmer in other languages -- not in perl though... :( When I learned that perl by default will autodefine variables for me (before I learned about use strict I was scared, and I actively looked for -w and use strict from my first day of reading Camel book, because I know too well how easy is to misspell variable name. You are not afraid yet - because you did not spent hours staring at code looking for an error, and then another hour banging your head aginst wall how stupid you were to make this stupid mistake. No problem, they are coming your way...;-)

        pmas
        To make errors is human. But to make million errors per second, you need a computer.

Re: Trig in Perl
by Zaxo (Archbishop) on Sep 04, 2001 at 12:35 UTC

    A better pi yet: use constant PI => 4 * atan2 1, 1;(from Camel 3)

    After Compline,
    Zaxo

Re: Trig in Perl
by astaines (Curate) on Sep 04, 2001 at 13:21 UTC

    I used to see code like this a lot - this is more or less how many people wrote Fortran. There are *lots* of variables being passed to most of the subroutines - COMMON blocks. There are many many lines each doing some simple arithmetical manipulation. The main control of program flow seems to be through a couple of globals - whatfound and whatfound0.

    I could never fix, understand or maintain code in this style, and I used to rewrite it as it was ultimately less painful.

    It is faster to write code like this, for something that will only be done once. If it's going to be done twice, you should reconsider your basic design. Also if it doesn't currently work properly, as you suggest, a rewrite on more organised lines is probably the fastest way of fixing it.

    -- Anthony Staines
      Actually, those variables are not being passed! He seems to declare all his local vars as a parameter list, but @_ doesn't contain all that. It's usually empty, in fact.

Re: Trig in Perl
by rchiav (Deacon) on Sep 04, 2001 at 16:32 UTC
    And yes I know that I didn't use strict; but I didn't have the time and it wasn't really worth it with all the subroutines.

    Oh, but by using strict, you would have saved yourself time! Strict is your friend and not your enemy. If I could give you one thing to refine this, it would be to use strict;. Just by using it, you'd have to refine your own code in a better way. That, and proper formatting. Personally, I stopped reading this half way through because it's just too ugly to read.

    Be considerate of those you're seeking help from and format your code. You're going to get more help if you show some respect for those you're seeking wisdom from.

    Hope this helps..
    Rich

Re: Trig in Perl
by John M. Dlugosz (Monsignor) on Sep 04, 2001 at 20:59 UTC