Law of cosines - triples: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|Factor}}: fixed a logic error resulting in incorrect output)
Line 36: Line 36:
:: triples ( quot -- seq )
:: triples ( quot -- seq )
[
[
V{ } clone :> seen
13 [1,b] dup dup [ amb-lazy ] tri@ :> ( a b c )
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 =
a sq b sq + a b quot call( x x x -- x ) c sq =
must-be-true { a b c }
{ b a c } seen member? not and
must-be-true { a b c } dup seen push
] bag-of ;
] bag-of ;

: solutions ( quot -- seq )
triples [ natural-sort ] map members { } like ;


: show-solutions ( quot angle -- )
: show-solutions ( quot angle -- )
[ solutions dup length ] dip rot
[ triples { } like dup length ] dip rot
"%d solutions for %d degrees:\n%u\n\n" printf ;
"%d solutions for %d degrees:\n%u\n\n" printf ;


Line 64: Line 63:
{ 2 2 2 }
{ 2 2 2 }
{ 3 3 3 }
{ 3 3 3 }
{ 3 7 8 }
{ 3 8 7 }
{ 4 4 4 }
{ 4 4 4 }
{ 5 5 5 }
{ 5 5 5 }
{ 5 7 8 }
{ 5 8 7 }
{ 6 6 6 }
{ 6 6 6 }
{ 7 7 7 }
{ 7 7 7 }

Revision as of 14:31, 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:
A² + B² - 2ABcos(γ) = C²

Specific angles

For an angle of of 90° this becomes the more familiar "Pythagoras equation:
A² + B² = C²

For an angle of 60° this becomes the less familiar equation:
A² + B² - AB = C²

And finally for an angle of 120° this becomes the equation:
A² + B² + AB = C²

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