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

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:
```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 ) {
+eg( \$A ) );
}
if ( \$B ) {
+eg( \$B ) );
}
if ( \$C ) {
+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 );
+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;
+\$other ) );
} elsif ( \$var eq "B" ) {
\$sum = \$angles{A} + \$angles{C};
\$other = 180 - \$sum;
\$angles{\$var} = \$other;
+\$other ) );
} elsif ( \$var eq "A" ) {
\$sum = \$angles{B} + \$angles{C};
\$other = 180 - \$sum;
\$angles{\$var} = \$other;
+\$other ) );
}
undef \$var;
}

if ( \$c && \$C == 0 ) {
my \$sin_C = ( 1/\$x ) * \$c;
\$C = asin( \$sin_C );
+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 );
+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;
+\$other ) );
} elsif ( \$var eq "B" ) {
\$sum = \$angles{A} + \$angles{C};
\$other = 180 - \$sum;
\$angles{\$var} = \$other;
+\$other ) );
} elsif ( \$var eq "A" ) {
\$sum = \$angles{B} + \$angles{C};
\$other = 180 - \$sum;
\$angles{\$var} = \$other;
+\$other ) );
}
undef \$var;
}

if ( \$c && \$C == 0 ) {
my \$sin_C = ( 1/\$x ) * \$c;
\$C = asin( \$sin_C );
+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 );
+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;
+\$other ) );
} elsif ( \$var eq "B" ) {
\$sum = \$angles{A} + \$angles{C};
\$other = 180 - \$sum;
\$angles{\$var} = \$other;
+\$other ) );
} elsif ( \$var eq "A" ) {
\$sum = \$angles{B} + \$angles{C};
print ("Sum: \$sum\n");
\$other = 180 - \$sum;
\$angles{\$var} = \$other;
+\$other ) );
}
undef \$var;
}

if ( \$b && \$B == 0 ) {
my \$sin_B = ( 1/\$x ) * \$b;
\$B = asin( \$sin_B );
+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;
+\$other ) );
} elsif ( \$var eq "B" ) {
\$sum = \$angles{A} + \$angles{C};
\$other = 180 - \$sum;
\$angles{\$var} = \$other;
+\$other ) );
} elsif ( \$var eq "A" ) {
\$sum = \$angles{B} + \$angles{C};
\$other = 180 - \$sum;
\$angles{\$var} = \$other;
+\$other ) );
}
undef \$var;
}

if ( \$a && \$A == 0 ) {
my \$sin_A = ( 1/\$x ) * \$a;
\$A = asin( \$sin_A );
+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