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