Law of cosines - triples: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|REXX}}: corrected calculations for width of various side lengths.)
m (→‎{{header|REXX}}: added checks to see if computations are needed when some angles are skipped.)
Line 179: Line 179:
This REXX version used some optimization.
This REXX version used some optimization.
<lang rexx>/*REXX pgm finds integer sided triangles that satisfy Law of cosines for 60º, 90º, 120º.*/
<lang rexx>/*REXX pgm finds integer sided triangles that satisfy Law of cosines for 60º, 90º, 120º.*/
parse arg sides1 sides2 sides3 . /*obtain optional arguments from the CL*/
parse arg s1 s2 s3 . /*obtain optional arguments from the CL*/
if sides1=='' | sides1=="," then sides1= 13 /*Not specified? Then use the default.*/
if s1=='' | s1=="," then s1= 13 /*Not specified? Then use the default.*/
if sides2=='' | sides2=="," then sides2= sides1 /* " " " " " " */
if s2=='' | s2=="," then s2= s1 /* " " " " " " */
if sides3=='' | sides3=="," then sides3= sides2 /* " " " " " " */
if s3=='' | s3=="," then s3= s2 /* " " " " " " */
w= max(length(sides1), length(sides2), length(sides3)) /*W: used to align side lengths*/
w= max( length(s1), length(s2), length(s3) ) /*W is used to align the side lengths.*/

call head 120 /*title for 120º: + + ab == */
do a=1 for sides1; aa = a*a
if s1>0 then do; call head 120 /*title for 120º: + + ab == */
do b=a+1 to sides1; x= aa + b*b + a*b
do a=1 for s1; aa = a*a
do c=b+1 to sides1; if x==c*c then call show
do b=a+1 to s1; x= aa + b*b + a*b
end /*c*/
do c=b+1 to s1; if x==c*c then call show
end /*b*/
end /*c*/
end /*a*/
end /*b*/
end /*a*/
call foot sides1
call head 90 /*title for 90º: a² + b² == c² */
call foot s1
do a=1 for sides2; aa = a*a
end

do b=a+1 to sides2; x= aa + b*b
do c=b+1 to sides2; if x==c*c then call show
if s2>0 then do; call head 90 /*title for 90º: a² + == c² */
end /*c*/
do a=1 for s2; aa = a*a
end /*b*/
do b=a+1 to s2; x= aa + b*b
end /*a*/
do c=b+1 to s2; if x==c*c then call show
end /*c*/
call foot sides2
call head 60 /*title for 60º: a² + b² - ab == c² */
end /*b*/
do a=1 for sides3; aa = a*a
end /*a*/
do b=a for sides3; x= aa + b*b - a*b
call foot s2
end
do c=b for sides3; if x==c*c then call show

end /*c*/
end /*b*/
if s3>0 then do; call head 60 /*title for 60º: a² + b² - ab == c² */
end /*a*/
do a=1 for s3; aa = a*a
do b=a for s3; x= aa + b*b - a*b
call foot sides3
do c=b for s3; if x==c*c then call show
end /*c*/
end /*b*/
end /*a*/
call foot s3
end
exit /*stick a fork in it, we're all done. */
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────────────────────────────────────────────────────────*/

Revision as of 17:44, 23 September 2018

Law of cosines - triples is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

The Law of cosines states that for an angle γ, (gamma) of any triangle, if the sides adjacent to the angle are A and B and the side opposite is C; then the lengths of the sides are related by this formula:

           A2 + B2 - 2ABcos(γ) = C2 
Specific angles

For an angle of of   90º   this becomes the more familiar "Pythagoras equation":

           A2 + B2  =  C2           

For an angle of   60º   this becomes the less familiar equation:

           A2 + B2 - AB  =  C2       

And finally for an angle of   120º   this becomes the equation:

           A2 + B2 + AB  =  C2      


Task
  • Find all integer solutions to the three specific cases, in order; distinguishing between each angle being considered.
  • Restrain all sides to the integers 1..13 inclusive.
  • Show how many results there are for each angle.
  • Display results on this page.


Optional Extra credit
  • How many 60° integer triples are there for sides in the range 1..10_000 where the sides are not all of the same length.


Related Task


See also



Factor

<lang factor>USING: backtrack formatting kernel locals math math.ranges sequences sets sorting ; IN: rosetta-code.law-of-cosines

triples ( quot -- seq )
   [
       V{ } clone :> seen        
       13 [1,b] dup dup [ amb-lazy ] tri@ :> ( a b c )
       a sq b sq + a b quot call( x x x -- x ) c sq =
       { b a c } seen member? not and
       must-be-true { a b c } dup seen push
   ] bag-of ;
show-solutions ( quot angle -- )
   [ triples { } like dup length ] dip rot
   "%d solutions for %d degrees:\n%u\n\n" printf ;

[ * + ] 120 [ 2drop 0 - ] 90 [ * - ] 60 [ show-solutions ] 2tri@</lang>

Output:
2 solutions for 120 degrees:
{ { 3 5 7 } { 7 8 13 } }

3 solutions for 90 degrees:
{ { 3 4 5 } { 5 12 13 } { 6 8 10 } }

15 solutions for 60 degrees:
{
    { 1 1 1 }
    { 2 2 2 }
    { 3 3 3 }
    { 3 8 7 }
    { 4 4 4 }
    { 5 5 5 }
    { 5 8 7 }
    { 6 6 6 }
    { 7 7 7 }
    { 8 8 8 }
    { 9 9 9 }
    { 10 10 10 }
    { 11 11 11 }
    { 12 12 12 }
    { 13 13 13 }
}

Haskell

<lang haskell>import Data.List (groupBy, nub, sort, sortBy) import Data.Ord (comparing) import Data.Function (on) import Data.Monoid ((<>)) import Control.Arrow (second)

triplesFound :: Int -> [(Int, [(Int, Int)])] triplesFound n =

 let xs = ((,) <*> (^ 2)) <$> [1 .. n] :: [(Int, Int)]
 in xs >>=
    \x ->
       xs >>=
       \y ->
          xs >>=
          \z ->
             let d = snd z - (snd x + snd y)
             in if 0 == d
                  then [(90, [x, y, z])]
                  else if (fst x * fst y) == abs d
                         then if 0 < d
                                then [(60, [x, y, z])]
                                else [(120, [x, y, z])]
                         else []

showTriples :: [(Int, [(Int, Int)])] -> String showTriples xs =

 unlines $
 zipWith
   (\n vs ->
       '\n' :
       show (length vs) <> " solutions for " <> show n <> " degrees:\n" <>
       show vs)
   [120, 90, 60] $
 (nub . fmap (sort . snd)) <$>
 groupBy (on (==) fst) (second (fmap fst) <$> sortBy (comparing fst) xs)

main :: IO () main = putStrLn $ showTriples (triplesFound 13)</lang>

Output:
2 solutions for 120 degrees:
[[3,5,7],[7,8,13]]

3 solutions for 90 degrees:
[[3,4,5],[5,12,13],[6,8,10]]

15 solutions for 60 degrees:
[[1,1,1],[2,2,2],[3,3,3],[3,7,8],[4,4,4],[5,5,5],[5,7,8],[6,6,6],[7,7,7],[8,8,8],[9,9,9],[10,10,10],[11,11,11],[12,12,12],[13,13,13]]

Python

<lang>N = 13

def method1(N=N):

   squares = [x**2 for x in range(0, N+1)]
   sqrset = set(squares)
   tri90, tri60, tri120 = (set() for _ in range(3))
   for a in range(1, N+1):
       a2 = squares[a]
       for b in range(1, a + 1):
           b2 = squares[b]
           c2 = a2 + b2
           if c2 in sqrset:
               tri90.add(tuple(sorted((a, b, int(c2**0.5)))))
               continue
           ab = a * b
           c2 -= ab
           if c2 in sqrset:
               tri60.add(tuple(sorted((a, b, int(c2**0.5)))))
               continue
           c2 += 2 * ab
           if c2 in sqrset:
               tri120.add(tuple(sorted((a, b, int(c2**0.5)))))
   return  sorted(tri90), sorted(tri60), sorted(tri120)
  1. %%

if __name__ == '__main__':

   print(f'Integer triangular triples for sides 1..{N}:')
   for angle, triples in zip([90, 60, 120], method1(N)):
       print(f'  {angle:3}° has {len(triples)} solutions:\n    {triples}')
   _, t60, _ = method1(10_000)
   notsame = sum(1 for a, b, c in t60 if a != b or b != c)
   print('Extra credit:', notsame)</lang>
Output:
Integer triangular triples for sides 1..13:
   90° has 3 solutions:
    [(3, 4, 5), (5, 12, 13), (6, 8, 10)]
   60° has 15 solutions:
    [(1, 1, 1), (2, 2, 2), (3, 3, 3), (3, 7, 8), (4, 4, 4), (5, 5, 5), (5, 7, 8), (6, 6, 6), (7, 7, 7), (8, 8, 8), (9, 9, 9), (10, 10, 10), (11, 11, 11), (12, 12, 12), (13, 13, 13)]
  120° has 2 solutions:
    [(3, 5, 7), (7, 8, 13)]
Extra credit: 17806

REXX

This REXX version used some optimization. <lang rexx>/*REXX pgm finds integer sided triangles that satisfy Law of cosines for 60º, 90º, 120º.*/ parse arg s1 s2 s3 . /*obtain optional arguments from the CL*/ if s1== | s1=="," then s1= 13 /*Not specified? Then use the default.*/ if s2== | s2=="," then s2= s1 /* " " " " " " */ if s3== | s3=="," then s3= s2 /* " " " " " " */ w= max( length(s1), length(s2), length(s3) ) /*W is used to align the side lengths.*/

if s1>0 then do; call head 120 /*title for 120º: a² + b² + ab == c² */

                                 do     a=1   for s1;  aa  = a*a
                                   do   b=a+1  to s1;  x= aa + b*b + a*b
                                     do c=b+1  to s1;  if x==c*c  then call show
                                     end   /*c*/
                                   end     /*b*/
                                 end       /*a*/
                  call foot s1
             end

if s2>0 then do; call head 90 /*title for 90º: a² + b² == c² */

                                 do     a=1   for s2;  aa  = a*a
                                   do   b=a+1  to s2;  x= aa + b*b
                                     do c=b+1  to s2;  if x==c*c  then call show
                                     end   /*c*/
                                   end     /*b*/
                                 end       /*a*/
                  call foot s2
             end

if s3>0 then do; call head 60 /*title for 60º: a² + b² - ab == c² */

                                 do     a=1   for s3;  aa  = a*a
                                   do   b=a   for s3;  x= aa + b*b - a*b
                                     do c=b   for s3;  if x==c*c  then call show
                                     end   /*c*/
                                   end     /*b*/
                                 end       /*a*/
                  call foot s3
             end

exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ foot: say right(# ' solutions found for' angle "(sides up to" arg(1)')', 65); say; return head: #= 0; angle= ' 'arg(1)"º "; say center(angle, 65, '═'); return show: #= # + 1; say ' ('right(a, w)"," right(b, w)"," right(c, w)')'; return</lang>

output   when using the default number of sides for the input:     13
═════════════════════════════ 120º ══════════════════════════════
     ( 3,  5,  7)
     ( 7,  8, 13)
                   2  solutions found for  120º  (sides up to 13)

══════════════════════════════ 90º ══════════════════════════════
     ( 3,  4,  5)
     ( 5, 12, 13)
     ( 6,  8, 10)
                    3  solutions found for  90º  (sides up to 13)

══════════════════════════════ 60º ══════════════════════════════
     ( 1,  1,  1)
     ( 2,  2,  2)
     ( 3,  3,  3)
     ( 4,  4,  4)
     ( 5,  5,  5)
     ( 6,  6,  6)
     ( 7,  7,  7)
     ( 8,  8,  8)
     ( 9,  9,  9)
     (10, 10, 10)
     (11, 11, 11)
     (12, 12, 12)
     (13, 13, 13)
                   13  solutions found for  60º  (sides up to 13)