sifukurt has asked for the wisdom of the Perl Monks concerning the following question:
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:
Thanks a bunch.
___________________
Kurt
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.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
Thanks a bunch.
___________________
Kurt


Replies are listed 'Best First'.  

Re: Help w/ Law of Sines script
by dragonchild (Archbishop) on Aug 02, 2001 at 01:29 UTC  
by sifukurt (Hermit) on Aug 03, 2001 at 00:36 UTC  
Re: Help w/ Law of Sines script
by lucs (Sexton) on Aug 02, 2001 at 11:28 UTC  
Re: Help w/ Law of Sines script
by John M. Dlugosz (Monsignor) on Aug 02, 2001 at 02:15 UTC 
Back to
Seekers of Perl Wisdom