Hello, fellow programmers of the cloth. I need some help. The wife of a good friend of mine is taking a trigonometry class. I thought that I'd whip up a quickie perl script that would perform the Law of Sines so she could quickly check her answers. After a bit of playing, I ended up with this:
use Math::NumberCruncher; sub asin { my $sine = shift; return undef unless ( $sine >= -1 && $sine <= 1 ); return atan2( $sine, sqrt( 1-$sine * $sine ) ); } sub LawOfSines { my ( $A, $a, $B, $b, $C, $c, $format ) = @_; return undef unless ( $A && $a ) || ( $B && $b ) || ( $C && $c ); return undef unless defined $a or defined $b or defined $c; return undef unless defined $A or defined $B or defined $C; my %angles = (); my %sides = (); my @angles = undef; my ( $var, $other, $sum ) = undef; if ( $format eq "d" ) { if ( $A ) { $angles{A} = $A; $A = sprintf( "%.10f", Math::NumberCruncher::deg2rad( $A ) + ); } if ( $B ) { $angles{B} = $B; $B = sprintf( "%.10f", Math::NumberCruncher::deg2rad( $B ) + ); } if ( $C ) { $angles{C} = $C; $C = sprintf( "%.10f", Math::NumberCruncher::deg2rad( $C ) + ); } } else { if ( $A ) { $angles{A} = sprintf( "%.10f", Math::NumberCruncher::rad2d +eg( $A ) ); } if ( $B ) { $angles{B} = sprintf( "%.10f", Math::NumberCruncher::rad2d +eg( $B ) ); } if ( $C ) { $angles{C} = sprintf( "%.10f", Math::NumberCruncher::rad2d +eg( $C ) ); } } unless ( $A > 0 && $B > 0 && $C > 0 ) { if ( $A > 0 && $B > 0 ) { $var = "C" } if ( $A > 0 && $C > 0 ) { $var = "B" } if ( $B > 0 && $C > 0 ) { $var = "A" } if ( $var eq "C" ) { $sum = $angles{B} + $angles{A}; $other = 180 - $sum; $angles{$var} = $other; $C = sprintf( "%.10f", Math::NumberCruncher::deg2rad( $oth +er ) ); } elsif ( $var eq "B" ) { $sum = $angles{A} + $angles{C}; $other = 180 - $sum; $angles{$var} = $other; $B = sprintf( "%.10f", Math::NumberCruncher::deg2rad( $oth +er ) ); } elsif ( $var eq "A" ) { $sum = $angles{B} + $angles{C}; $other = 180 - $sum; $angles{$var} = $other; $A = sprintf( "%.10f", Math::NumberCruncher::deg2rad( $oth +er ) ); } undef $var; } if ( $a ) { $sides{a} = $a; } if ( $b ) { $sides{b} = $b; } if ( $c ) { $sides{c} = $c; } if ( $A > 0 && $a ) { my $x = $a / sin( $A ); if ( $b && $B == 0 ) { my $sin_B = ( 1/$x ) * $b; $B = asin( $sin_B ); $angles{B} = sprintf( "%.10f", Math::NumberCruncher::rad2d +eg( $B ) ); } elsif ( !$b && $B > 0 ) { $b = sprintf( "%.3f", ( $x * sin( $B ) ) ); $sides{b} = $b; } unless ( $A > 0 && $B > 0 && $C > 0 ) { if ( $A > 0 && $B > 0 ) { $var = "C" } if ( $A > 0 && $C > 0 ) { $var = "B" } if ( $B > 0 && $C > 0 ) { $var = "A" } if ( $var eq "C" ) { $sum = $angles{B} + $angles{A}; $other = 180 - $sum; $angles{$var} = $other; $C = sprintf( "%.10f", Math::NumberCruncher::deg2rad( +$other ) ); } elsif ( $var eq "B" ) { $sum = $angles{A} + $angles{C}; $other = 180 - $sum; $angles{$var} = $other; $B = sprintf( "%.10f", Math::NumberCruncher::deg2rad( +$other ) ); } elsif ( $var eq "A" ) { $sum = $angles{B} + $angles{C}; $other = 180 - $sum; $angles{$var} = $other; $A = sprintf( "%.10f", Math::NumberCruncher::deg2rad( +$other ) ); } undef $var; } if ( $c && $C == 0 ) { my $sin_C = ( 1/$x ) * $c; $C = asin( $sin_C ); $angles{C} = sprintf( "%.10f", Math::NumberCruncher::rad2d +eg( $C ) ); } elsif ( !$c && $C > 0 ) { $c = sprintf( "%.3f", ( $x * sin( $C ) ) ); $sides{c} = $c; } } elsif ( $B > 0 && $b ) { my $x = $b / sin( $B ); if ( $a && $A == 0 ) { my $sin_A = ( 1/$x ) * $a; $A = asin( $sin_A ); $angles{A} = sprintf( "%.10f", Math::NumberCruncher::rad2d +eg( $A ) ); } elsif ( !$a && $A > 0 ) { $a = sprintf( "%.3f", ( $x * sin( $A ) ) ); $sides{a} = $a; } unless ( $A > 0 && $B > 0 && $C > 0 ) { if ( $A > 0 && $B > 0 ) { $var = "C" } if ( $A > 0 && $C > 0 ) { $var = "B" } if ( $B > 0 && $C > 0 ) { $var = "A" } if ( $var eq "C" ) { $sum = $angles{B} + $angles{A}; $other = 180 - $sum; $angles{$var} = $other; $C = sprintf( "%.10f", Math::NumberCruncher::deg2rad( +$other ) ); } elsif ( $var eq "B" ) { $sum = $angles{A} + $angles{C}; $other = 180 - $sum; $angles{$var} = $other; $B = sprintf( "%.10f", Math::NumberCruncher::deg2rad( +$other ) ); } elsif ( $var eq "A" ) { $sum = $angles{B} + $angles{C}; $other = 180 - $sum; $angles{$var} = $other; $A = sprintf( "%.10f", Math::NumberCruncher::deg2rad( +$other ) ); } undef $var; } if ( $c && $C == 0 ) { my $sin_C = ( 1/$x ) * $c; $C = asin( $sin_C ); $angles{C} = sprintf( "%.10f", Math::NumberCruncher::rad2d +eg( $C ) ); } elsif ( !$c && $C > 0 ) { $c = sprintf( "%.3f", ( $x * sin( $C ) ) ); $sides{c} = $c; } } elsif ( $C > 0 && $c ) { my $x = $c / sin( $C ); if ( $a && $A == 0 ) { my $sin_A = ( 1/$x ) * $a; $A = asin( $sin_A ); $angles{A} = sprintf( "%.10f", Math::NumberCruncher::rad2d +eg( $A ) ); } elsif ( !$a && $A > 0 ) { $a = sprintf( "%.3f", ( $x * sin( $A ) ) ); $sides{a} = $a; } unless ( $A > 0 && $B > 0 && $C > 0 ) { if ( $A > 0 && $B > 0 ) { $var = "C" } if ( $A > 0 && $C > 0 ) { $var = "B" } if ( $B > 0 && $C > 0 ) { $var = "A" } if ( $var eq "C" ) { $sum = $angles{B} + $angles{A}; $other = 180 - $sum; $angles{$var} = $other; $C = sprintf( "%.10f", Math::NumberCruncher::deg2rad( +$other ) ); } elsif ( $var eq "B" ) { $sum = $angles{A} + $angles{C}; $other = 180 - $sum; $angles{$var} = $other; $B = sprintf( "%.10f", Math::NumberCruncher::deg2rad( +$other ) ); } elsif ( $var eq "A" ) { $sum = $angles{B} + $angles{C}; print ("Sum: $sum\n"); $other = 180 - $sum; $angles{$var} = $other; $A = sprintf( "%.10f", Math::NumberCruncher::deg2rad( +$other ) ); } undef $var; } if ( $b && $B == 0 ) { my $sin_B = ( 1/$x ) * $b; $B = asin( $sin_B ); $angles{B} = sprintf( "%.10f", Math::NumberCruncher::rad2d +eg( $B ) ); } elsif ( !$b && $B > 0 ) { $b = sprintf( "%.3f", ( $x * sin( $B ) ) ); $sides{b} = $b; } unless ( $A > 0 && $B > 0 && $C > 0 ) { if ( $A > 0 && $B > 0 ) { $var = "C" } if ( $A > 0 && $C > 0 ) { $var = "B" } if ( $B > 0 && $C > 0 ) { $var = "A" } if ( $var eq "C" ) { $sum = $angles{B} + $angles{A}; $other = 180 - $sum; $angles{$var} = $other; $C = sprintf( "%.10f", Math::NumberCruncher::deg2rad( +$other ) ); } elsif ( $var eq "B" ) { $sum = $angles{A} + $angles{C}; $other = 180 - $sum; $angles{$var} = $other; $B = sprintf( "%.10f", Math::NumberCruncher::deg2rad( +$other ) ); } elsif ( $var eq "A" ) { $sum = $angles{B} + $angles{C}; $other = 180 - $sum; $angles{$var} = $other; $A = sprintf( "%.10f", Math::NumberCruncher::deg2rad( +$other ) ); } undef $var; } if ( $a && $A == 0 ) { my $sin_A = ( 1/$x ) * $a; $A = asin( $sin_A ); $angles{A} = sprintf( "%.10f", Math::NumberCruncher::rad2d +eg( $A ) ); } elsif ( !$a && $A > 0 ) { $a = sprintf( "%.3f", ( $x * sin( $A ) ) ); $sides{a} = $a; } } if ( $format eq "d" ) { $A = sprintf( "%.3f", Math::NumberCruncher::rad2deg( $A ) ); $B = sprintf( "%.3f", Math::NumberCruncher::rad2deg( $B ) ); $C = sprintf( "%.3f", Math::NumberCruncher::rad2deg( $C ) ); } $A = sprintf( "%.3f", $A ); $a = sprintf( "%.3f", $a ); $B = sprintf( "%.3f", $B ); $b = sprintf( "%.3f", $b ); $C = sprintf( "%.3f", $C ); $c = sprintf( "%.3f", $c ); return ( $A, $B, $C, $a, $b, $c ); } print <<END; Enter the triangle items you have available. You must enter at least three items, including at least one side and at least one angle. In ad +dition, two of the three must be an angle and its opposing side. (i.e., B and +b ). END print ("A: "); chomp($A = <STDIN>); print ("a: "); chomp($a = <STDIN>); print ("B: "); chomp($B = <STDIN>); print ("b: "); chomp($b = <STDIN>); print ("C: "); chomp($C = <STDIN>); print ("c: "); chomp($c = <STDIN>); ( $A1, $B1, $C1, $a1, $b1, $c1 ) = LawOfSines( $A, $a, $B, $b, $C, $c, + "d" ); print <<END; A: $A1 a: $a1 B: $B1 b: $b1 C: $C1 c: $c1 END
I was more interested in doing it quickly that I was in making it efficient or elegant. Now that I have the time, though, I want to clean it up. My problem is that after looking at it for as many hours as I have, I could really use someone else's input. I use Math::NumberCruncher to perform any degree/radian conversions. I'm really just doing this for fun (egad, did I just say that I'm doing the Law of Sines for fun? I need to get out more....), so there is no hurry, but if someone could take a look at my code and give me an assist in making it more efficient and/or elegant, I would appreciate it greatly.

Thanks a bunch.
___________________
Kurt

In reply to Help w/ Law of Sines script by sifukurt

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.