Heronian triangles: Difference between revisions

m
m (typo 2)
m (→‎{{header|Wren}}: Minor tidy)
 
(231 intermediate revisions by 56 users not shown)
Line 1:
{{task}}
[[wp:Heron's formula|Heron's formula]] for the area of a triangle given the length of its three sides
''a'', ''b'', and ''c'' is given by:
 
[[wp:Heron's formula|Hero's formula]] for the area of a triangle given the length of its three sides &nbsp; <big> ''a'',</big> &nbsp; <big>''b'',</big> &nbsp; and &nbsp; <big>''c''</big> &nbsp; is given by:
:<math>A = \sqrt{s(s-a)(s-b)(s-c)},</math>
 
:::: <big><math>A = \sqrt{s(s-a)(s-b)(s-c)},</math></big>
where ''s'' is half the perimeter of the triangle; that is,
 
where &nbsp; <big>''s''</big> &nbsp; is half the perimeter of the triangle; that is,
:<math>s=\frac{a+b+c}{2}.</math>
 
:::: <big><math>s=\frac{a+b+c}{2}.</math></big>
 
<br>
'''[http://www.had2know.com/academics/heronian-triangles-generator-calculator.html Heronian triangles]'''
are triangles whose sides ''and area'' are all integers.
: An example is the triangle with sides &nbsp; '''3, 4, 5''' &nbsp; whose area is &nbsp; '''6''' &nbsp; (and whose perimeter is &nbsp; '''12''').
 
<br>
Note that any triangle whose sides are all an integer multiple of 3,4,5; such as 6,8,10, will
Note that any triangle whose sides are all an integer multiple of &nbsp; '''3, 4, 5'''; &nbsp; such as &nbsp; '''6, 8, 10,''' &nbsp; will also be a Heronian triangle.
also be a heronian triangle.
 
Define a '''Primitive Heronian triangle''' as a heronianHeronian triangle where the greatest common divisor
of all three sides is &nbsp; '''1.''' this&nbsp; will exclude, for example triangle(unity). 6,8,10
 
This will exclude, for example, triangle &nbsp; '''6, 8, 10.'''
'''The task''' is to:
 
 
;Task:
# Create a named function/method/procedure/... that implements Hero's formula.
# Use the function to generate all the ''primitive'' heronianHeronian triangles with sides <= 200.
# Show the count of how many triangles are found.
# Order the triangles by first increasing area, then by increasing perimeter, then by increasing maximum side lengths
# Show the first ten ordered triangles in a table of sides, perimeter, and area.
# Show a similar ordered table for those triangles with area = 210
 
<br>
Show all output here.
 
<small>'''Note''': when generating triangles it may help to restrict</small> <math>a <= b <= c</math></small>
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">F gcd(=u, =v)
L v != 0
(u, v) = (v, u % v)
R abs(u)
 
F hero(a, b, c)
V s = (a + b + c) / 2
V a2 = s * (s - a) * (s - b) * (s - c)
R I a2 > 0 {sqrt(a2)} E 0
 
F is_heronian(a, b, c)
V x = hero(a, b, c)
R x > 0 & fract(x) == 0
 
F gcd3(x, y, z)
R gcd(gcd(x, y), z)
 
V MAXSIDE = 200
[(Int, Int, Int)] h
L(x) 1..MAXSIDE
L(y) x..MAXSIDE
L(z) y..MAXSIDE
I (x + y > z) & gcd3(x, y, z) == 1 & is_heronian(x, y, z)
h [+]= (x, y, z)
 
h = sorted(h, key' x -> (hero(x[0], x[1], x[2]), sum(x), (x[2], x[1], x[0])))
 
print(‘Primitive Heronian triangles with sides up to #.: #.’.format(MAXSIDE, h.len))
print("\nFirst ten when ordered by increasing area, then perimeter, then maximum sides:")
print(h[0.<10].map3((x, y, z) -> ‘ #14 perim: #3 area: #.’.format(String((x, y, z)), x + y + z, hero(x, y, z))).join("\n"))
print("\nAll with area 210 subject to the previous ordering:")
print(h.filter3((x, y, z) -> hero(x, y, z) == 210).map3((x, y, z) -> ‘ #14 perim: #3 area: #.’.format(String((x, y, z)), x + y + z, hero(x, y, z))).join("\n"))</syntaxhighlight>
 
{{out}}
<pre>
Primitive Heronian triangles with sides up to 200: 517
 
First ten when ordered by increasing area, then perimeter, then maximum sides:
(3, 4, 5) perim: 12 area: 6
(5, 5, 6) perim: 16 area: 12
(5, 5, 8) perim: 18 area: 12
(4, 13, 15) perim: 32 area: 24
(5, 12, 13) perim: 30 area: 30
(9, 10, 17) perim: 36 area: 36
(3, 25, 26) perim: 54 area: 36
(7, 15, 20) perim: 42 area: 42
(10, 13, 13) perim: 36 area: 60
(8, 15, 17) perim: 40 area: 60
 
All with area 210 subject to the previous ordering:
(17, 25, 28) perim: 70 area: 210
(20, 21, 29) perim: 70 area: 210
(12, 35, 37) perim: 84 area: 210
(17, 28, 39) perim: 84 area: 210
(7, 65, 68) perim: 140 area: 210
(3, 148, 149) perim: 300 area: 210
</pre>
 
=={{header|Ada}}==
<syntaxhighlight lang="ada">with Ada.Containers.Indefinite_Ordered_Sets;
with Ada.Finalization;
with Ada.Text_IO; use Ada.Text_IO;
procedure Heronian is
package Int_IO is new Ada.Text_IO.Integer_IO(Integer);
use Int_IO;
-- ----- Some math...
function GCD (A, B : in Natural) return Natural is (if B = 0 then A else GCD (B, A mod B));
function Int_Sqrt (N : in Natural) return Natural is
R1 : Natural := N;
R2 : Natural;
begin
if N <= 1 then
return N;
end if;
loop
R2 := (R1+N/R1)/2;
if R2 >= R1 then
return R1;
end if;
R1 := R2;
end loop;
end Int_Sqrt;
-- ----- Defines the triangle with sides as discriminants and a constructor which will
-- compute its other characteristics
type t_Triangle (A, B, C : Positive) is new Ada.Finalization.Controlled with record
Is_Heronian : Boolean;
Perimeter : Positive;
Area : Natural;
end record;
 
overriding procedure Initialize (Self : in out t_Triangle) is
-- Let's stick to integer computations, therefore a modified hero's formula
-- will be used : S*(S-a)*(S-b)*(S-c) = (a+b+c)*(-a+b+c)*(a-b+c)*(a+b-c)/16
-- This will require long integers because at max side size, the product
-- before /16 excesses 2^31
Long_Product : Long_Long_Integer;
Short_Product : Natural;
begin
Self.Perimeter := Self.A + Self.B + Self.C;
Long_Product := Long_Long_Integer(Self.Perimeter)
* Long_Long_Integer(- Self.A + Self.B + Self.C)
* Long_Long_Integer( Self.A - Self.B + Self.C)
* Long_Long_Integer( Self.A + Self.B - Self.C);
Short_Product := Natural(Long_Product / 16);
Self.Area := Int_Sqrt (Short_Product);
Self.Is_Heronian := (Long_Product mod 16 = 0) and (Self.Area * Self.Area = Short_Product);
end Initialize;
-- ----- Ordering triangles with criteria (Area,Perimeter,A,B,C)
function "<" (Left, Right : in t_Triangle) return Boolean is
(Left.Area < Right.Area or else (Left.Area = Right.Area and then
(Left.Perimeter < Right.Perimeter or else (Left.Perimeter = Right.Perimeter and then
(Left.A < Right.A or else (Left.A = Right.A and then
(Left.B < Right.B or else (Left.B = Right.B and then
Left.C < Right.C))))))));
package Triangle_Lists is new Ada.Containers.Indefinite_Ordered_Sets (t_Triangle);
use Triangle_Lists;
 
-- ----- Displaying triangle characteristics
Header : constant String := " A B C Per Area" & ASCII.LF & "---+---+---+---+-----";
procedure Put_Triangle (Position : Cursor) is
Triangle : constant t_Triangle := Element(Position);
begin
Put(Triangle.A, 3);
Put(Triangle.B, 4);
Put(Triangle.C, 4);
Put(Triangle.Perimeter, 4);
Put(Triangle.Area, 6);
New_Line;
end Put_Triangle;
 
-- ----- Global variables
Triangles : Set := Empty_Set;
-- Instead of constructing two sets, or browsing all the beginning of the set during
-- the second output, start/end cursors will be updated during the insertions.
First_201 : Cursor := No_Element;
Last_201 : Cursor := No_Element;
 
procedure Memorize_Triangle (A, B, C : in Positive) is
Candidate : t_Triangle(A, B, C);
Position : Cursor;
Dummy : Boolean;
begin
if Candidate.Is_Heronian then
Triangles.Insert (Candidate, Position, Dummy);
if Candidate.Area = 210 then
First_201 := (if First_201 = No_Element then Position
elsif Position < First_201 then Position
else First_201);
Last_201 := (if Last_201 = No_Element then Position
elsif Last_201 < Position then Position
else Last_201);
end if;
end if;
end Memorize_Triangle;
begin
-- Loops restrict to unique A,B,C (ensured by A <= B <= C) with sides < 200 and for
-- which a triangle is constructible : C is not greater than B+A (flat triangle)
for A in 1..200 loop
for B in A..200 loop
for C in B..Integer'Min(A+B-1,200) loop
-- Filter non-primitive triangles
if GCD(GCD(A,B),C) = 1 then
Memorize_Triangle (A, B, C);
end if;
end loop;
end loop;
end loop;
Put_Line (Triangles.Length'Img & " heronian triangles found :");
Put_Line (Header);
Triangles.Iterate (Process => Put_Triangle'Access);
New_Line;
Put_Line ("Heronian triangles with area = 201");
Put_Line (Header);
declare
Position : Cursor := First_201;
begin
loop
Put_Triangle (Position);
exit when Position = Last_201;
Position := Next(Position);
end loop;
end;
end Heronian;</syntaxhighlight>
{{out}}
<pre> 517 heronian triangles found :
A B C Per Area
---+---+---+---+-----
3 4 5 12 6
5 5 6 16 12
5 5 8 18 12
4 13 15 32 24
5 12 13 30 30
9 10 17 36 36
3 25 26 54 36
7 15 20 42 42
10 13 13 36 60
8 15 17 40 60</pre>
...
<pre>
Heronian triangles with area = 201
A B C Per Area
---+---+---+---+-----
17 25 28 70 210
20 21 29 70 210
12 35 37 84 210
17 28 39 84 210
7 65 68 140 210
3 148 149 300 210</pre>
 
=={{header|ALGOL 68}}==
{{Trans|Lua}}
<syntaxhighlight lang="algol68"># mode to hold details of a Heronian triangle #
MODE HERONIAN = STRUCT( INT a, b, c, area, perimeter );
# returns the details of the Heronian Triangle with sides a, b, c or nil if it isn't one #
PROC try ht = ( INT a, b, c )REF HERONIAN:
BEGIN
REF HERONIAN t := NIL;
REAL s = ( a + b + c ) / 2;
REAL area squared = s * ( s - a ) * ( s - b ) * ( s - c );
IF area squared > 0 THEN
# a, b, c does form a triangle #
REAL area = sqrt( area squared );
IF ENTIER area = area THEN
# the area is integral so the triangle is Heronian #
t := HEAP HERONIAN := ( a, b, c, ENTIER area, a + b + c )
FI
FI;
t
END # try ht # ;
# returns the GCD of a and b #
PROC gcd = ( INT a, b )INT: IF b = 0 THEN a ELSE gcd( b, a MOD b ) FI;
# prints the details of the Heronian triangle t #
PROC ht print = ( REF HERONIAN t )VOID:
print( ( whole( a OF t, -4 ), whole( b OF t, -5 ), whole( c OF t, -5 ), whole( area OF t, -5 ), whole( perimeter OF t, -10 ), newline ) );
# prints headings for the Heronian Triangle table #
PROC ht title = VOID: print( ( " a b c area perimeter", newline, "---- ---- ---- ---- ---------", newline ) );
 
BEGIN
# construct ht as a table of the Heronian Triangles with sides up to 200 #
[ 1 : 1000 ]REF HERONIAN ht;
REF HERONIAN t;
INT ht count := 0;
 
FOR c TO 200 DO
FOR b TO c DO
FOR a TO b DO
IF gcd( gcd( a, b ), c ) = 1 THEN
t := try ht( a, b, c );
IF REF HERONIAN(t) ISNT REF HERONIAN(NIL) THEN
ht[ ht count +:= 1 ] := t
FI
FI
OD
OD
OD;
 
# sort the table on ascending area, perimeter and max side length #
# note we constructed the triangles with c as the longest side #
BEGIN
INT lower := 1, upper := ht count;
WHILE upper := upper - 1;
BOOL swapped := FALSE;
FOR i FROM lower TO upper DO
REF HERONIAN h := ht[ i ];
REF HERONIAN k := ht[ i + 1 ];
IF area OF k < area OF h OR ( area OF k = area OF h
AND ( perimeter OF k < perimeter OF h
OR ( perimeter OF k = perimeter OF h
AND c OF k < c OF h
)
)
)
THEN
ht[ i ] := k;
ht[ i + 1 ] := h;
swapped := TRUE
FI
OD;
swapped
DO SKIP OD;
 
# display the triangles #
print( ( "There are ", whole( ht count, 0 ), " Heronian triangles with sides up to 200", newline ) );
ht title;
FOR ht pos TO 10 DO ht print( ht( ht pos ) ) OD;
print( ( " ...", newline ) );
print( ( "Heronian triangles with area 210:", newline ) );
ht title;
FOR ht pos TO ht count DO
REF HERONIAN t := ht[ ht pos ];
IF area OF t = 210 THEN ht print( t ) FI
OD
END
END</syntaxhighlight>
{{out}}
<pre>
There are 517 Heronian triangles with sides up to 200
a b c area perimeter
---- ---- ---- ---- ---------
3 4 5 6 12
5 5 6 12 16
5 5 8 12 18
4 13 15 24 32
5 12 13 30 30
9 10 17 36 36
3 25 26 36 54
7 15 20 42 42
10 13 13 60 36
8 15 17 60 40
...
Heronian triangles with area 210:
a b c area perimeter
---- ---- ---- ---- ---------
17 25 28 210 70
20 21 29 210 70
12 35 37 210 84
17 28 39 210 84
7 65 68 210 140
3 148 149 210 300
</pre>
 
=={{header|ALGOL W}}==
{{Trans|Lua}}
<syntaxhighlight lang="algolw">begin
% record to hold details of a Heronian triangle %
record Heronian ( integer a, b, c, area, perimeter );
% returns the details of the Heronian Triangle with sides a, b, c or nil if it isn't one %
reference(Heronian) procedure tryHt( integer value a, b, c ) ;
begin
real s, areaSquared, area;
reference(Heronian) t;
s := ( a + b + c ) / 2;
areaSquared := s * ( s - a ) * ( s - b ) * ( s - c );
t := null;
if areaSquared > 0 then begin
% a, b, c does form a triangle %
area := sqrt( areaSquared );
if entier( area ) = area then begin
% the area is integral so the triangle is Heronian %
t := Heronian( a, b, c, entier( area ), a + b + c )
end
end;
t
end tryHt ;
 
% returns the GCD of a and b %
integer procedure gcd( integer value a, b ) ; if b = 0 then a else gcd( b, a rem b );
 
% prints the details of the Heronian triangle t %
procedure htPrint( reference(Heronian) value t ) ; write( i_w := 4, s_w := 1, a(t), b(t), c(t), area(t), " ", perimeter(t) );
% prints headings for the Heronian Triangle table %
procedure htTitle ; begin write( " a b c area perimeter" ); write( "---- ---- ---- ---- ---------" ) end;
 
begin
% construct ht as a table of the Heronian Triangles with sides up to 200 %
reference(Heronian) array ht ( 1 :: 1000 );
reference(Heronian) t;
integer htCount;
 
htCount := 0;
for c := 1 until 200 do begin
for b := 1 until c do begin
for a := 1 until b do begin
if gcd( gcd( a, b ), c ) = 1 then begin
t := tryHt( a, b, c );
if t not = null then begin
htCount := htCount + 1;
ht( htCount ) := t
end
end
end
end
end;
 
% sort the table on ascending area, perimeter and max side length %
% note we constructed the triangles with c as the longest side %
begin
integer lower, upper;
reference(Heronian) k, h;
logical swapped;
lower := 1;
upper := htCount;
while begin
upper := upper - 1;
swapped := false;
for i := lower until upper do begin
h := ht( i );
k := ht( i + 1 );
if area(k) < area(h) or ( area(k) = area(h)
and ( perimeter(k) < perimeter(h)
or ( perimeter(k) = perimeter(h)
and c(k) < c(h)
)
)
)
then begin
ht( i ) := k;
ht( i + 1 ) := h;
swapped := true;
end
end;
swapped
end
do begin end;
end;
 
% display the triangles %
write( "There are ", htCount, " Heronian triangles with sides up to 200" );
htTitle;
for htPos := 1 until 10 do htPrint( ht( htPos ) );
write( " ..." );
write( "Heronian triangles with area 210:" );
htTitle;
for htPos := 1 until htCount do begin
reference(Heronian) t;
t := ht( htPos );
if area(t) = 210 then htPrint( t )
end
end
end.</syntaxhighlight>
{{out}}
<pre>
There are 517 Heronian triangles with sides up to 200
a b c area perimeter
---- ---- ---- ---- ---------
3 4 5 6 12
5 5 6 12 16
5 5 8 12 18
4 13 15 24 32
5 12 13 30 30
9 10 17 36 36
3 25 26 36 54
7 15 20 42 42
10 13 13 60 36
8 15 17 60 40
...
Heronian triangles with area 210:
a b c area perimeter
---- ---- ---- ---- ---------
17 25 28 210 70
20 21 29 210 70
12 35 37 210 84
17 28 39 210 84
7 65 68 210 140
3 148 149 210 300
</pre>
 
=={{header|AppleScript}}==
 
By composition of functional primitives, and using post-Yosemite AppleScript's ability to import Foundation classes (mainly for sorting records, here).
 
{{Trans|JavaScript}}
<syntaxhighlight lang="applescript">use framework "Foundation"
 
-- HERONIAN TRIANGLES --------------------------------------------------------
 
-- heroniansOfSideUpTo :: Int -> [(Int, Int, Int)]
on heroniansOfSideUpTo(n)
script sideA
on |λ|(a)
script sideB
on |λ|(b)
script sideC
-- primitiveHeronian :: Int -> Int -> Int -> Bool
on primitiveHeronian(x, y, z)
(x ≤ y and y ≤ z) and (x + y > z) and ¬
gcd(gcd(x, y), z) = 1 and ¬
isIntegerValue(hArea(x, y, z))
end primitiveHeronian
on |λ|(c)
if primitiveHeronian(a, b, c) then
{{a, b, c}}
else
{}
end if
end |λ|
end script
concatMap(sideC, enumFromTo(b, n))
end |λ|
end script
concatMap(sideB, enumFromTo(a, n))
end |λ|
end script
concatMap(sideA, enumFromTo(1, n))
end heroniansOfSideUpTo
 
 
-- TEST ----------------------------------------------------------------------
on run
set n to 200
set lstHeron to ¬
sortByComparing({{"area", true}, {"perimeter", true}, {"maxSide", true}}, ¬
map(triangleDimensions, heroniansOfSideUpTo(n)))
set lstCols to {"sides", "perimeter", "area"}
set lstColWidths to {20, 15, 0}
set area to 210
script areaFilter
-- Record -> [Record]
on |λ|(recTriangle)
if area of recTriangle = area then
{recTriangle}
else
{}
end if
end |λ|
end script
intercalate("\n \n", {("Number of triangles found (with sides <= 200): " & ¬
length of lstHeron as string), ¬
¬
tabulation("First 10, ordered by area, perimeter, longest side", ¬
items 1 thru 10 of lstHeron, lstCols, lstColWidths), ¬
¬
tabulation("Area = 210", ¬
concatMap(areaFilter, lstHeron), lstCols, lstColWidths)})
end run
 
-- triangleDimensions :: (Int, Int, Int) ->
-- {sides: (Int, Int, Int), area: Int, perimeter: Int, maxSize: Int}
on triangleDimensions(lstSides)
set {x, y, z} to lstSides
{sides:[x, y, z], area:hArea(x, y, z) as integer, perimeter:x + y + z, maxSide:z}
end triangleDimensions
 
-- hArea :: Int -> Int -> Int -> Num
on hArea(x, y, z)
set s to (x + y + z) / 2
set a to s * (s - x) * (s - y) * (s - z)
if a > 0 then
a ^ 0.5
else
0
end if
end hArea
 
-- gcd :: Int -> Int -> Int
on gcd(m, n)
if n = 0 then
m
else
gcd(n, m mod n)
end if
end gcd
 
 
-- TABULATION ----------------------------------------------------------------
 
-- tabulation :: [Record] -> [String] -> String -> [Integer] -> String
on tabulation(strLegend, lstRecords, lstKeys, lstWidths)
script heading
on |λ|(strTitle, iCol)
set str to toTitle(strTitle)
str & replicate((item iCol of lstWidths) - (length of str), space)
end |λ|
end script
script lineString
on |λ|(rec)
script fieldString
-- fieldString :: String -> Int -> String
on |λ|(strKey, i)
set v to keyValue(strKey, rec)
if class of v is list then
set strData to ("(" & intercalate(", ", v) & ")")
else
set strData to v as string
end if
strData & replicate(space, (item i of (lstWidths)) - (length of strData))
end |λ|
end script
tab & intercalate(tab, map(fieldString, lstKeys))
end |λ|
end script
strLegend & ":" & linefeed & linefeed & ¬
tab & intercalate(tab, ¬
map(heading, lstKeys)) & linefeed & ¬
intercalate(linefeed, map(lineString, lstRecords))
end tabulation
 
-- GENERIC FUNCTIONS ---------------------------------------------------------
 
-- concat :: [[a]] -> [a] | [String] -> String
on concat(xs)
if length of xs > 0 and class of (item 1 of xs) is string then
set acc to ""
else
set acc to {}
end if
repeat with i from 1 to length of xs
set acc to acc & item i of xs
end repeat
acc
end concat
 
-- concatMap :: (a -> [b]) -> [a] -> [b]
on concatMap(f, xs)
concat(map(f, xs))
end concatMap
 
-- enumFromTo :: Int -> Int -> [Int]
on enumFromTo(m, n)
if m > n then
set d to -1
else
set d to 1
end if
set lst to {}
repeat with i from m to n by d
set end of lst to i
end repeat
return lst
end enumFromTo
 
-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
tell mReturn(f)
set v to startValue
set lng to length of xs
repeat with i from 1 to lng
set v to |λ|(v, item i of xs, i, xs)
end repeat
return v
end tell
end foldl
 
-- intercalate :: Text -> [Text] -> Text
on intercalate(strText, lstText)
set {dlm, my text item delimiters} to {my text item delimiters, strText}
set strJoined to lstText as text
set my text item delimiters to dlm
return strJoined
end intercalate
 
-- isIntegerValue :: Num -> Bool
on isIntegerValue(n)
{real, integer} contains class of n and (n = (n as integer))
end isIntegerValue
 
-- keyValue :: String -> Record -> Maybe String
on keyValue(strKey, rec)
set ca to current application
set v to (ca's NSDictionary's dictionaryWithDictionary:rec)'s objectForKey:strKey
if v is not missing value then
item 1 of ((ca's NSArray's arrayWithObject:v) as list)
else
missing value
end if
end keyValue
 
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs, i, xs)
end repeat
return lst
end tell
end map
 
-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: Handler -> Script
on mReturn(f)
if class of f is script then
f
else
script
property |λ| : f
end script
end if
end mReturn
 
-- replicate :: Int -> String -> String
on replicate(n, s)
set out to ""
if n < 1 then return out
set dbl to s
repeat while (n > 1)
if (n mod 2) > 0 then set out to out & dbl
set n to (n div 2)
set dbl to (dbl & dbl)
end repeat
return out & dbl
end replicate
 
-- List of {strKey, blnAscending} pairs -> list of records -> sorted list of records
 
-- sortByComparing :: [(String, Bool)] -> [Records] -> [Records]
on sortByComparing(keyDirections, xs)
set ca to current application
script recDict
on |λ|(x)
ca's NSDictionary's dictionaryWithDictionary:x
end |λ|
end script
set dcts to map(recDict, xs)
script asDescriptor
on |λ|(kd)
set {k, d} to kd
ca's NSSortDescriptor's sortDescriptorWithKey:k ascending:d selector:dcts
end |λ|
end script
((ca's NSArray's arrayWithArray:dcts)'s ¬
sortedArrayUsingDescriptors:map(asDescriptor, keyDirections)) as list
end sortByComparing
 
-- toTitle :: String -> String
on toTitle(str)
set ca to current application
((ca's NSString's stringWithString:(str))'s ¬
capitalizedStringWithLocale:(ca's NSLocale's currentLocale())) as text
end toTitle</syntaxhighlight>
{{Out}}
<pre>Number of triangles found (with sides <= 200): 517
 
First 10, ordered by area, perimeter, longest side:
 
Sides Perimeter Area
(3, 4, 5) 12 6
(5, 5, 6) 16 12
(5, 5, 8) 18 12
(4, 13, 15) 32 24
(5, 12, 13) 30 30
(9, 10, 17) 36 36
(3, 25, 26) 54 36
(7, 15, 20) 42 42
(10, 13, 13) 36 60
(8, 15, 17) 40 60
 
Area = 210:
 
Sides Perimeter Area
(17, 25, 28) 70 210
(20, 21, 29) 70 210
(12, 35, 37) 84 210
(17, 28, 39) 84 210
(7, 65, 68) 140 210
(3, 148, 149) 300 210</pre>
 
=={{header|Arturo}}==
<syntaxhighlight lang="arturo">printTable: function [title, rows][
print title ++ ":"
print repeat "=" 60
 
prints pad.center "A" 10
prints pad.center "B" 10
prints pad.center "C" 10
prints pad.center "Perimeter" 15
print pad.center "Area" 15
print repeat "-" 60
 
loop rows 'row [
prints pad.center to :string row\0 10
prints pad.center to :string row\1 10
prints pad.center to :string row\2 10
prints pad.center to :string row\3 15
print pad.center to :string row\4 15
]
print ""
]
 
hero: function [a,b,c][
s: (a + b + c) // 2
return sqrt(s * (s-a) * (s-b) * (s-c))
]
 
heronian?: function [x]->
and? -> x > 0
-> x = ceil x
 
lst: []
mx: 200
 
loop 1..mx 'c ->
loop 1..c 'b ->
loop 1..b 'a [
area: hero a b c
if and? [heronian? area] [one? gcd @[a b c]]->
'lst ++ @[
@[a, b, c, a + b + c, to :integer area]
]
]
 
print ["Number of Heronian triangles:" size lst]
print ""
 
lst: arrange lst 'item ->
(item\4 * 10000) + (item\3 * 100) + max first.n:3 item
 
printTable "Ordered list of first ten Heronian triangles" first.n: 10 lst
printTable "Ordered list of Heronian triangles with area 210" select lst 'x -> x\4 = 210</syntaxhighlight>
 
{{out}}
 
<pre>Number of Heronian triangles: 517
 
Ordered list of first ten Heronian triangles:
============================================================
A B C Perimeter Area
------------------------------------------------------------
3 4 5 12 6
5 5 6 16 12
5 5 8 18 12
4 13 15 32 24
5 12 13 30 30
9 10 17 36 36
3 25 26 54 36
7 15 20 42 42
10 13 13 36 60
8 15 17 40 60
 
Ordered list of Heronian triangles with area 210:
============================================================
A B C Perimeter Area
------------------------------------------------------------
17 25 28 70 210
20 21 29 70 210
12 35 37 84 210
17 28 39 84 210
7 65 68 140 210
3 148 149 300 210</pre>
 
=={{header|AutoHotkey}}==
<syntaxhighlight lang="autohotkey">Primitive_Heronian_triangles(MaxSide){
obj :=[]
loop, % MaxSide {
a := A_Index
loop % MaxSide-a+1 {
b := A_Index+a-1
loop % MaxSide-b+1 {
c := A_Index+b-1, s := (a+b+c)/2, Area := Sqrt(s*(s-a)*(s-b)*(s-c))
if (Area = Floor(Area)) && (Area>0) && !obj[a/s, b/s, c/s]
obj[a/s, b/s, c/s]:=1 ,res .= (res?"`n":"") StrReplace(Area, ".000000") "`t" a+b+c "`t" a ", " b ", " c
} } }
Sort, res, F Sort
return res
}
 
Sort(x, y){
x := StrSplit(x, "`t"), y := StrSplit(y, "`t")
return x.1 > y.1 ? 1 : x.1 < y.1 ? -1 : x.2 > y.2 ? 1 : x.2 < y.2 ? -1 : 0
}</syntaxhighlight>
Examples:<syntaxhighlight lang="autohotkey">res := Primitive_Heronian_triangles(200)
loop, parse, res, `n, `r
{
if A_Index<=10
res2.= A_LoopField "`n"
if StrSplit(A_LoopField, "`t").1 = 210
res3.= A_LoopField "`n"
Counter := A_Index
}
 
MsgBox % Counter " results found"
. "`n`nFirst 10 results:"
. "`n" "Area`tPerimeter`tSides`n" res2
. "`nResults for Area = 210:"
. "`n" "Area`tPerimeter`tSides`n" res3
return</syntaxhighlight>
Outputs:<pre>517 results found
 
First 10 results:
Area Perimeter Sides
6 12 3, 4, 5
12 16 5, 5, 6
12 18 5, 5, 8
24 32 4, 13, 15
30 30 5, 12, 13
36 36 9, 10, 17
36 54 3, 25, 26
42 42 7, 15, 20
60 36 10, 13, 13
60 40 8, 15, 17
 
Results for Area = 210:
Area Perimeter Sides
210 70 20, 21, 29
210 70 17, 25, 28
210 84 17, 28, 39
210 84 12, 35, 37
210 140 7, 65, 68
210 300 3, 148, 149</pre>
 
=={{header|C}}==
Takes max side, number of triangles to print and area limit as inputs. Area should be -1 if it is not a restriction. Triangles are stored in a linked list which is built sorted and hence no post processing is required. Usage is printed out on incorrect invocation.
 
----
'''IMPORTANT''': This is a C99 compatible implementation. May result in errors on earlier compilers.
<syntaxhighlight lang="c">
#include<stdlib.h>
#include<stdio.h>
#include<math.h>
 
typedef struct{
int a,b,c;
int perimeter;
double area;
}triangle;
 
typedef struct elem{
triangle t;
struct elem* next;
}cell;
 
typedef cell* list;
 
void addAndOrderList(list *a,triangle t){
list iter,temp;
int flag = 0;
if(*a==NULL){
*a = (list)malloc(sizeof(cell));
(*a)->t = t;
(*a)->next = NULL;
}
else{
temp = (list)malloc(sizeof(cell));
 
iter = *a;
while(iter->next!=NULL){
if(((iter->t.area<t.area)||(iter->t.area==t.area && iter->t.perimeter<t.perimeter)||(iter->t.area==t.area && iter->t.perimeter==t.perimeter && iter->t.a<=t.a))
&&
(iter->next==NULL||(t.area<iter->next->t.area || t.perimeter<iter->next->t.perimeter || t.a<iter->next->t.a))){
temp->t = t;
temp->next = iter->next;
iter->next = temp;
flag = 1;
break;
}
 
iter = iter->next;
}
if(flag!=1){
temp->t = t;
temp->next = NULL;
iter->next = temp;
}
}
}
 
int gcd(int a,int b){
if(b!=0)
return gcd(b,a%b);
return a;
}
 
void calculateArea(triangle *t){
(*t).perimeter = (*t).a + (*t).b + (*t).c;
(*t).area = sqrt(0.5*(*t).perimeter*(0.5*(*t).perimeter - (*t).a)*(0.5*(*t).perimeter - (*t).b)*(0.5*(*t).perimeter - (*t).c));
}
 
list generateTriangleList(int maxSide,int *count){
int a,b,c;
triangle t;
list herons = NULL;
*count = 0;
for(a=1;a<=maxSide;a++){
for(b=1;b<=a;b++){
for(c=1;c<=b;c++){
if(c+b > a && gcd(gcd(a,b),c)==1){
t = (triangle){a,b,c};
calculateArea(&t);
if(t.area/(int)t.area == 1){
addAndOrderList(&herons,t);
(*count)++;
}
}
}
}
}
return herons;
}
 
void printList(list a,int limit,int area){
list iter = a;
int count = 1;
printf("\nDimensions\tPerimeter\tArea");
while(iter!=NULL && count!=limit+1){
if(area==-1 ||(area==iter->t.area)){
printf("\n%d x %d x %d\t%d\t\t%d",iter->t.a,iter->t.b,iter->t.c,iter->t.perimeter,(int)iter->t.area);
count++;
}
iter = iter->next;
}
}
 
int main(int argC,char* argV[])
{
int count;
list herons = NULL;
if(argC!=4)
printf("Usage : %s <Max side, max triangles to print and area, -1 for area to ignore>",argV[0]);
else{
herons = generateTriangleList(atoi(argV[1]),&count);
printf("Triangles found : %d",count);
(atoi(argV[3])==-1)?printf("\nPrinting first %s triangles.",argV[2]):printf("\nPrinting triangles with area %s square units.",argV[3]);
printList(herons,atoi(argV[2]),atoi(argV[3]));
free(herons);
}
return 0;
}
</syntaxhighlight>
Invocation and output :
<pre>
C:\rosettaCode>heronian.exe 200 10 -1
Triangles found : 517
Printing first 10 triangles.
Dimensions Perimeter Area
5 x 4 x 3 12 6
6 x 5 x 5 16 12
8 x 5 x 5 18 12
15 x 13 x 4 32 24
13 x 12 x 5 30 30
17 x 10 x 9 36 36
26 x 25 x 3 54 36
20 x 15 x 7 42 42
13 x 13 x 10 36 60
17 x 15 x 8 40 60
C:\rosettaCode>heronian.exe 200 10 210
Triangles found : 517
Printing triangles with area 210 square units.
Dimensions Perimeter Area
28 x 25 x 17 70 210
29 x 21 x 20 70 210
37 x 35 x 12 84 210
39 x 28 x 17 84 210
68 x 65 x 7 140 210
149 x 148 x 3 300 210
</pre>
 
=={{header|C sharp|C#}}==
<syntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
 
namespace heron
{
class Program{
static void Main(string[] args){
List<int[]> list = new List<int[]>();
for (int c = 1; c <= 200; c++)
for (int b = 1; b <= c; b++)
for (int a = 1; a <= b; a++)
if (gcd(a, gcd(b, c)) == 1 && isHeron(heronArea(a, b, c)))
list.Add(new int[] { a, b, c, a + b + c, (int)heronArea(a, b, c)});
sort(list);
Console.WriteLine("Number of primitive Heronian triangles with sides up to 200: " + list.Count + "\n\nFirst ten when ordered by increasing area, then perimeter,then maximum sides:\nSides\t\t\tPerimeter\tArea");
for(int i = 0; i < 10; i++)
Console.WriteLine(list[i][0] + "\t" + list[i][1] + "\t" + list[i][2] + "\t" + list[i][3] + "\t\t" + list[i][4]);
Console.WriteLine("\nPerimeter = 210\nSides\t\t\tPerimeter\tArea");
foreach (int[] i in list)
if (i[4] == 210)
Console.WriteLine(i[0] + "\t" + i[1] + "\t" + i[2] + "\t" + i[3] + "\t\t" + i[4]);
}
static bool isHeron(double heronArea){
return heronArea % 1 == 0 && heronArea != 0;
}
static double heronArea(int a, int b, int c){
double s = (a + b + c) / 2d;
return Math.Sqrt(s * (s - a) * (s - b) * (s - c));
}
static int gcd(int a, int b){
int remainder = 1, dividend, divisor;
dividend = a > b ? a : b;
divisor = a > b ? b : a;
while (remainder != 0){
remainder = dividend % divisor;
if (remainder != 0){
dividend = divisor;
divisor = remainder;
}
}
return divisor;
}
static void sort(List<int[]> list){
int[] temp = new int[5];
bool changed = true;
while(changed){
changed = false;
for (int i = 1; i < list.Count; i++)
if (list[i][4] < list[i - 1][4] || list[i][4] == list[i - 1][4] && list[i][3] < list[i - 1][3]){
temp = list[i];
list[i] = list[i - 1];
list[i - 1] = temp;
changed = true;
}
}
}
}
}</syntaxhighlight>
{{out}}
<pre>Number of primitive Heronian triangles with sides up to 200: 517
 
First ten when ordered by increasing area, then perimeter,then maximum sides:
Sides Perimeter Area
3 4 5 12 6
5 5 6 16 12
5 5 8 18 12
4 13 15 32 24
5 12 13 30 30
9 10 17 36 36
3 25 26 54 36
7 15 20 42 42
10 13 13 36 60
8 15 17 40 60
 
Perimeter = 210
Sides Perimeter Area
17 25 28 70 210
20 21 29 70 210
12 35 37 84 210
17 28 39 84 210
7 65 68 140 210
3 148 149 300 210</pre>
 
=={{header|C++}}==
{{Works with|C++17}}
<syntaxhighlight lang="cpp">#include <tuple>
#include <vector>
#include <numeric>
#include <iostream>
#include <algorithm>
 
#include <cmath>
 
struct Triangle {
int a{};
int b{};
int c{};
 
[[nodiscard]] constexpr auto perimeter() const noexcept { return a + b + c; }
 
[[nodiscard]] constexpr auto area() const noexcept {
const auto p_2 = static_cast<double>(perimeter()) / 2;
const auto area_sq = p_2 * (p_2 - a) * (p_2 - b) * (p_2 - c);
return std::sqrt(area_sq);
}
};
 
 
auto generate_triangles(int side_limit = 200) {
std::vector<Triangle> result;
for(int a = 1; a <= side_limit; ++a)
for(int b = 1; b <= a; ++b)
for(int c = a + 1 - b; c <= b; ++c) // skip too-small values of c, which will violate triangle inequality
{
Triangle t{ a, b, c };
const auto t_area = t.area();
if (t_area == 0) continue;
if (std::floor(t_area) == std::ceil(t_area) && std::gcd(a, std::gcd(b, c)) == 1)
result.push_back(t);
}
return result;
}
 
bool compare(const Triangle& lhs, const Triangle& rhs) noexcept {
return std::make_tuple(lhs.area(), lhs.perimeter(), std::max(lhs.a, std::max(lhs.b, lhs.c))) <
std::make_tuple(rhs.area(), rhs.perimeter(), std::max(rhs.a, std::max(rhs.b, rhs.c)));
}
 
struct area_compare {
[[nodiscard]] constexpr bool operator()(const Triangle& t, int i) const noexcept { return t.area() < i; }
[[nodiscard]] constexpr bool operator()(int i, const Triangle& t) const noexcept { return i < t.area(); }
};
 
int main() {
auto tri = generate_triangles();
std::cout << "There are " << tri.size() << " primitive Heronian triangles with sides up to 200\n\n";
 
std::cout << "First ten when ordered by increasing area, then perimeter, then maximum sides:\n";
std::sort(tri.begin(), tri.end(), compare);
std::cout << "area\tperimeter\tsides\n";
for(int i = 0; i < 10; ++i)
std::cout << tri[i].area() << '\t' << tri[i].perimeter() << "\t\t" <<
tri[i].a << 'x' << tri[i].b << 'x' << tri[i].c << '\n';
 
std::cout << "\nAll with area 210 subject to the previous ordering:\n";
auto range = std::equal_range(tri.begin(), tri.end(), 210, area_compare());
std::cout << "area\tperimeter\tsides\n";
for(auto it = range.first; it != range.second; ++it)
std::cout << (*it).area() << '\t' << (*it).perimeter() << "\t\t" <<
it->a << 'x' << it->b << 'x' << it->c << '\n';
}</syntaxhighlight>
{{out}}
<pre>There are 517 primitive Heronian triangles with sides up to 200
 
First ten when ordered by increasing area, then perimeter, then maximum sides:
area perimeter sides
6 12 5x4x3
12 16 6x5x5
12 18 8x5x5
24 32 15x13x4
30 30 13x12x5
36 36 17x10x9
36 54 26x25x3
42 42 20x15x7
60 36 13x13x10
60 40 17x15x8
 
All with area 210 subject to the previous ordering:
area perimeter sides
210 70 28x25x17
210 70 29x21x20
210 84 37x35x12
210 84 39x28x17
210 140 68x65x7
210 300 149x148x3</pre>
 
=={{header|CoffeeScript}}==
{{trans|JavaScript}}
<syntaxhighlight lang="coffeescript">heronArea = (a, b, c) ->
s = (a + b + c) / 2
Math.sqrt s * (s - a) * (s - b) * (s - c)
 
isHeron = (h) -> h % 1 == 0 and h > 0
 
gcd = (a, b) ->
leftover = 1
dividend = if a > b then a else b
divisor = if a > b then b else a
until leftover == 0
leftover = dividend % divisor
if leftover > 0
dividend = divisor
divisor = leftover
divisor
 
list = []
for c in [1..200]
for b in [1..c]
for a in [1..b]
area = heronArea(a, b, c)
if gcd(gcd(a, b), c) == 1 and isHeron(area)
list.push new Array(a, b, c, a + b + c, area)
 
sort = (list) ->
swapped = true
while swapped
swapped = false
for i in [1..list.length-1]
if list[i][4] < list[i - 1][4] or list[i][4] == list[i - 1][4] and list[i][3] < list[i - 1][3]
temp = list[i]
list[i] = list[i - 1]
list[i - 1] = temp
swapped = true
sort list
 
# some results:
console.log 'primitive Heronian triangles with sides up to 200: ' + list.length
console.log 'First ten when ordered by increasing area, then perimeter:'
for i in list[0..10-1]
console.log i[0..2].join(' x ') + ', p = ' + i[3] + ', a = ' + i[4]
 
console.log '\nHeronian triangles with area = 210:'
for i in list
if i[4] == 210
console.log i[0..2].join(' x ') + ', p = ' + i[3]</syntaxhighlight>
{{out}}
<pre>primitive Heronian triangles with sides up to 200: 517
First ten when ordered by increasing area, then perimeter:
3 x 4 x 5, p = 12, a = 6
5 x 5 x 6, p = 16, a = 12
5 x 5 x 8, p = 18, a = 12
4 x 13 x 15, p = 32, a = 24
5 x 12 x 13, p = 30, a = 30
9 x 10 x 17, p = 36, a = 36
3 x 25 x 26, p = 54, a = 36
7 x 15 x 20, p = 42, a = 42
10 x 13 x 13, p = 36, a = 60
8 x 15 x 17, p = 40, a = 60
 
Heronian triangles with area = 210:
17 x 25 x 28, p = 70
20 x 21 x 29, p = 70
12 x 35 x 37, p = 84
17 x 28 x 39, p = 84
7 x 65 x 68, p = 140
3 x 148 x 149, p = 300</pre>
 
=={{header|D}}==
{{trans|Python}}
<langsyntaxhighlight lang="d">import std.stdio, std.math, std.range, std.algorithm, std.numeric, std.traits, std.typecons;
 
double hero(in uint a, in uint b, in uint c) pure nothrow @safe @nogc {
Line 75 ⟶ 1,394:
"\nAll with area 210 subject to the previous ordering:".writeln;
showTriangles(h.filter!(t => t[].hero == 210));
}</langsyntaxhighlight>
{{out}}
<pre>Primitive Heronian triangles with sides up to 200: 517
Line 100 ⟶ 1,419:
210 140 7x65x68
210 300 3x148x149</pre>
=={{header|Delphi}}==
See [https://rosettacode.org/wiki/Heronian_triangles#Pascal Pascal].
 
=={{header|EchoLisp}}==
<syntaxhighlight lang="scheme">
;; returns quintuple (A s a b c)
;; or #f if not hero
(define (hero a b c (s 0) (A 0))
(when
(= 1 (gcd a b c))
(set! s (// (+ a b c) 2))
(set! A (* s (- s a)(- s b)(- s c)))
(when (square? A)
(list (sqrt A) (* s 2) c b a))))
;; all heroes a,b,c < sidemax
;; sorted by A|s|c & a <=b <= c
(define (heroes (sidemax 201))
(list-sort/fields 3
(for*/list ((a (in-range 1 sidemax)) (b (in-range a sidemax)) (c (in-range b sidemax)))
#:continue (<= (+ a b) c) ;; triangle inequality must hold !! cut search
#:continue (not (hero a b c))
(hero a b c))))
(define (print-hero h)
(printf "A: %6d s: %6d sides: %dx%dx%d"
(list-ref h 0) (list-ref h 1)
(list-ref h 2)(list-ref h 3) (list-ref h 4)))
(define (print-laurels H)
(writeln '🌿🌿 (length H) 'heroes '🌿🌿))
</syntaxhighlight>
{{out}}
<pre>(define H (heroes))
 
(print-laurels H)
🌿🌿 517 heroes 🌿🌿
 
(for-each print-hero (take H 10))
 
A: 6 s: 12 sides: 5x4x3
A: 12 s: 16 sides: 6x5x5
A: 12 s: 18 sides: 8x5x5
A: 24 s: 32 sides: 15x13x4
A: 30 s: 30 sides: 13x12x5
A: 36 s: 36 sides: 17x10x9
A: 36 s: 54 sides: 26x25x3
A: 42 s: 42 sides: 20x15x7
A: 60 s: 36 sides: 13x13x10
A: 60 s: 40 sides: 17x15x8
 
(for-each print-hero (filter (lambda(h) (= 210 (first h))) H))
 
A: 210 s: 70 sides: 28x25x17
A: 210 s: 70 sides: 29x21x20
A: 210 s: 84 sides: 37x35x12
A: 210 s: 84 sides: 39x28x17
A: 210 s: 140 sides: 68x65x7
A: 210 s: 300 sides: 149x148x3</pre>
 
=={{header|Elixir}}==
<syntaxhighlight lang="elixir">defmodule Heronian do
def triangle?(a,b,c) when a+b <= c, do: false
def triangle?(a,b,c) do
area = area(a,b,c)
area == round(area) and primitive?(a,b,c)
end
def area(a,b,c) do
s = (a + b + c) / 2
:math.sqrt(s * (s-a) * (s-b) * (s-c))
end
defp primitive?(a,b,c), do: gcd(gcd(a,b),c) == 1
defp gcd(a,0), do: a
defp gcd(a,b), do: gcd(b, rem(a,b))
end
 
max = 200
triangles = for a <- 1..max, b <- a..max, c <- b..max, Heronian.triangle?(a,b,c), do: {a,b,c}
IO.puts length(triangles)
 
IO.puts "\nSides\t\t\tPerim\tArea"
Enum.map(triangles, fn {a,b,c} -> {Heronian.area(a,b,c),a,b,c} end)
|> Enum.sort
|> Enum.take(10)
|> Enum.each(fn {area, a, b, c} ->
IO.puts "#{a}\t#{b}\t#{c}\t#{a+b+c}\t#{round(area)}"
end)
IO.puts ""
area_size = 210
Enum.filter(triangles, fn {a,b,c} -> Heronian.area(a,b,c) == area_size end)
|> Enum.sort_by(fn {a,b,c} -> a+b+c end)
|> Enum.each(fn {a, b, c} ->
IO.puts "#{a}\t#{b}\t#{c}\t#{a+b+c}\t#{area_size}"
end)</syntaxhighlight>
 
{{out}}
<pre>517
 
Sides Perim Area
3 4 5 12 6
5 5 6 16 12
5 5 8 18 12
4 13 15 32 24
5 12 13 30 30
3 25 26 54 36
9 10 17 36 36
7 15 20 42 42
6 25 29 60 60
8 15 17 40 60
 
17 25 28 70 210
20 21 29 70 210
12 35 37 84 210
17 28 39 84 210
7 65 68 140 210
3 148 149 300 210</pre>
 
=={{header|ERRE}}==
<syntaxhighlight lang="erre">
PROGRAM HERON
 
DIM LISTA%[600,4]
 
PROCEDURE GCD(J%,K%->MCD%)
WHILE J%<>K% DO
IF J%>K% THEN
J%=J%-K%
ELSE
K%=K%-J%
END IF
END WHILE
MCD%=J%
END PROCEDURE
 
BEGIN
PRINT(CHR$(12);) !CLS
FOR C%=1 TO 200 DO
FOR B%=1 TO C% DO
FOR A%=1 TO B% DO
S#=(A%+B%+C%)/2#
AREA#=S#*(S#-A%)*(S#-B%)*(S#-C%)
IF AREA#>0 THEN
AREA#=SQR(AREA#)
IF AREA#=INT(AREA#) THEN
GCD(B%,C%->RES%)
GCD(A%,RES%->RES%)
IF RES%=1 THEN
COUNT%=COUNT%+1
LISTA%[COUNT%,0]=A% LISTA%[COUNT%,1]=B% LISTA%[COUNT%,2]=C%
LISTA%[COUNT%,3]=2*S# LISTA%[COUNT%,4]=AREA#
END IF
END IF
END IF
END FOR
END FOR
END FOR
 
PRINT("Number of triangles:";COUNT%)
 
! sorting array
FLIPS%=TRUE
WHILE FLIPS% DO
FLIPS%=FALSE
FOR I%=1 TO COUNT%-1 DO
IF LISTA%[I%,4]>LISTA%[I%+1,4] THEN
FOR K%=0 TO 4 DO
SWAP(LISTA%[I%,K%],LISTA%[I%+1,K%])
END FOR
FLIPS%=TRUE
END IF
END FOR
END WHILE
 
! first ten
FOR I%=1 TO 10 DO
PRINT(#1,LISTA%[I%,0],LISTA%[I%,1],LISTA%[I%,2],LISTA%[I%,3],LISTA%[I%,4])
END FOR
PRINT
 
! triangle with area=210
FOR I%=1 TO COUNT% DO
IF LISTA%[I%,4]=210 THEN
PRINT(LISTA%[I%,0],LISTA%[I%,1],LISTA%[I%,2],LISTA%[I%,3],LISTA%[I%,4])
END IF
END FOR
END PROGRAM
</syntaxhighlight>
<pre>Number of triangles: 517
3 4 5 12 6
5 5 6 16 12
5 5 8 18 12
4 13 15 32 24
5 12 13 30 30
9 10 17 36 36
3 25 26 54 36
7 15 20 42 42
10 13 13 36 60
8 15 17 40 60
 
17 25 28 70 210
20 21 29 70 210
12 35 37 84 210
17 28 39 84 210
7 65 68 140 210
3 148 149 300 210</pre>
 
=={{header|Factor}}==
<syntaxhighlight lang="factor">USING: accessors assocs backtrack combinators.extras
combinators.short-circuit formatting io kernel locals math
math.functions math.order math.parser math.ranges mirrors qw
sequences sorting.slots ;
IN: rosetta-code.heronian-triangles
 
TUPLE: triangle a b c area perimeter ;
 
:: area ( a b c -- x )
a b + c + 2 / :> s
s s a - * s b - * s c - * sqrt ;
 
: <triangle> ( triplet-seq -- triangle )
[ first3 ] [ first3 area >integer ] [ sum ] tri
triangle boa ;
 
: heronian? ( a b c -- ? )
area dup [ complex? ] [ 0 number= ] bi or
[ drop f ] [ dup >integer number= ] if ;
: 3gcd ( a b c -- n ) [ gcd nip ] twice ;
: primitive-heronian? ( a b c -- ? )
{ [ 3gcd 1 = ] [ heronian? ] } 3&& ;
 
:: find-triangles ( -- seq )
[
200 [1,b] amb-lazy :> c ! Use backtrack vocab to test
c [1,b] amb-lazy :> b ! permutations of sides such
b [1,b] amb-lazy :> a ! that c >= b >= a.
a b c primitive-heronian? must-be-true
{ a b c } <triangle>
] bag-of ; ! collect every triangle
: sort-triangles ( seq -- seq' )
{ { area>> <=> } { perimeter>> <=> } } sort-by ;
CONSTANT: format "%4s%5s%5s%5s%10s\n"
: print-header ( -- )
qw{ a b c area perimeter } format vprintf
"---- ---- ---- ---- ---------" print ;
: print-triangle ( triangle -- )
<mirror> >alist values [ number>string ] map format vprintf ;
 
: print-triangles ( seq -- ) [ print-triangle ] each ; inline
: first10 ( sorted-triangles -- )
dup length "%d triangles found. First 10: \n" printf
print-header 10 head print-triangles ;
: area210= ( sorted-triangles -- )
"Triangles with area 210: " print print-header
[ area>> 210 = ] filter print-triangles ;
: main ( -- )
"Finding heronian triangles with sides <= 200..." print nl
find-triangles sort-triangles
[ first10 nl ] [ area210= ] bi ;
MAIN: main</syntaxhighlight>
{{out}}
<pre>
Finding heronian triangles with sides <= 200...
 
517 triangles found. First 10:
a b c area perimeter
---- ---- ---- ---- ---------
3 4 5 6 12
5 5 6 12 16
5 5 8 12 18
4 13 15 24 32
5 12 13 30 30
9 10 17 36 36
3 25 26 36 54
7 15 20 42 42
10 13 13 60 36
8 15 17 60 40
 
Triangles with area 210:
a b c area perimeter
---- ---- ---- ---- ---------
17 25 28 210 70
20 21 29 210 70
12 35 37 210 84
17 28 39 210 84
7 65 68 210 140
3 148 149 210 300
</pre>
 
=={{header|Fortran}}==
Earlier Fortran doesn't offer special functions such as SUM, PRODUCT and MAXVAL of arrays, nor the ability to create compound data aggregates such as STASH to store a triangle's details. Simple code would have to be used in the absence of such conveniences, and multiple ordinary arrays rather than an array of a compound data entity. Rather than attempt to create the candidate triangles in the desired order, the simple approach is to sort a list of triangles, and using an XNDX array evades tossing compound items about. Rather than create a procedure to do the sorting, a comb sort is not too much trouble to place in-line once. Further, since the ordering is based on a compound key, having only one comparison to code is a boon. The three-way-if statement is central to the expedient evaluation of a compound sort key, but this facility is deprecated by the modernists, with no alternative offered that avoids re-comparison of parts.
<syntaxhighlight lang="fortran">
MODULE GREEK MATHEMATICIANS !Two millenia back and more.
CONTAINS
INTEGER FUNCTION GCD(I,J) !Greatest common divisor.
INTEGER I,J !Of these two integers.
INTEGER N,M,R !Workers.
N = MAX(I,J) !Since I don't want to damage I or J,
M = MIN(I,J) !These copies might as well be the right way around.
1 R = MOD(N,M) !Divide N by M to get the remainder R.
c write (6,*) "M,N,R",M,N,R
IF (R.GT.0) THEN !Remainder zero?
N = M !No. Descend a level.
M = R !M-multiplicity has been removed from N.
IF (R .GT. 1) GO TO 1 !No point dividing by one.
END IF !If R = 0, M divides N.
GCD = M !There we are.
END FUNCTION GCD !Euclid lives on!
FUNCTION GCD3(I,J,K) !Double do.
INTEGER I,J,K !Three numbers.
INTEGER R !One remainder.
R = GCD(I,J) !Greatest common divisor.
IF (R .GT. 1) R = GCD(R,K) !The first two might be co-prime.
GCD3 = R !The result.
END FUNCTION GCD3
 
REAL*8 FUNCTION HERO(SIDE) !Hero's calculation for the area of a triangle.
Calculations could proceed with non-integer sides.
INTEGER SIDE(3) !The lengths of each of the sides.
REAL*8 S !A scratchpad.
S = SUM(SIDE) !Definitely integer arithmetic.
S = S/2 !Full precision without muttering /2D0.
S = S*PRODUCT(S - SIDE) !Negative for non-joining triangles.
HERO = SIGN(SQRT(ABS(S)),S) !Protect the SQRT against such.
END FUNCTION HERO !As when one side is longer than the other two combined.
END MODULE GREEK MATHEMATICIANS !Only a selection here.
 
PROGRAM TEST !Find triangles with integral sides and areas.
USE GREEK MATHEMATICIANS !For guidance.
INTEGER LIMIT,LOTS !And then descend to Furrytran.
PARAMETER (LIMIT = 200, LOTS = 666) !This should do.
INTEGER I,J,K,SIDE(3) !The lengths of the sides of the triangles.
EQUIVALENCE (SIDE(1),I),(SIDE(2),J),(SIDE(3),K) !I want two access styles.
REAL*8 A !The area of the triangle.
TYPE ABLOB !Define a stash for the desired results.
INTEGER SIDE(3) !The three sides,
INTEGER PERIMETER !Their summation, somewhat redundant.
INTEGER AREA !This is rather more difficult to calculate.
END TYPE ABLOB !That will do.
TYPE(ABLOB) STASH(LOTS) !I'll have some.
INTEGER N,XNDX(LOTS) !A counter and an index..
INTEGER H,T !Stuff for the in-line combsort.
LOGICAL CURSE !Rather than mess with subroutines and parameters.
INTEGER TASTE,CHOICE !Output selection stuff.
PARAMETER (TASTE = 10, CHOICE = 210) !As specified.
 
Collect some triangles.
N = 0 !So, here we go.
DO K = 1,LIMIT !Just slog away,
DO J = 1,K !With brute force and ignorance.
DO I = 1,J !This way, a 3,4,5 triangle is in that order.
IF (GCD3(I,J,K).GT.1) CYCLE !A mere multiple. Seen it before.
A = HERO(SIDE) !Assess the area.
IF (A.LE.0) CYCLE !Not a valid triangle!
IF (A .NE. INT(A)) CYCLE !Not an integral area. Precision is adequate...
N = N + 1 !Another candidate survives.
IF (N.GT.LOTS) STOP "Too many!" !Perhaps not for long!
XNDX(N) = N !So, keep a finger.
STASH(N).SIDE = SIDE !Stash its details.
STASH(N).PERIMETER = SUM(SIDE) !Calculate once, here.
STASH(N).AREA = A !And save this as an integer.
c WRITE (6,10) N,STASH(N)
10 FORMAT (I4,":",3I4,I7,I8) !A reasonable layout.
END DO
END DO
END DO
WRITE (6,11) N,LIMIT !The first result.
11 FORMAT (I0," triangles of integral area. Sides up to ",I0)
 
Comb sort involves coding only one test, and the comparison is to be compound...
H = N - 1 !Last - First, and not +1.
20 H = MAX(1,H*10/13) !The special feature.
IF (H.EQ.9 .OR. H.EQ.10) H = 11 !A twiddle.
CURSE = .FALSE. !So far, so good.
DO 24 I = N - H,1,-1 !If H = 1, this is a BubbleSort.
IF (STASH(XNDX(I)).AREA - STASH(XNDX(I + H)).AREA) 24,21,23 !One compare. But, a compound key.
21 IF (STASH(XNDX(I)).PERIMETER-STASH(XNDX(I+H)).PERIMETER)24,22,23 !Equal area, so, perimeter?
22 IF (MAXVAL(STASH(XNDX(I)).SIDE) !Equal perimeter, so, longest side?
1 - MAXVAL(STASH(XNDX(I+H)).SIDE)) 24,24,23 !At last, equality here can be passed over.
23 T=XNDX(I); XNDX(I)=XNDX(I+H); XNDX(I+H)=T !One swap.
CURSE = .TRUE. !One curse.
24 CONTINUE !One loop.
IF (CURSE .OR. H.GT.1) GO TO 20 !Work remains?
 
Cast forth the results, as per the specification.
WRITE (6,30) TASTE
30 FORMAT ("First ",I0,", ordered by area, perimeter, longest side.",
1 /,"Index ---Sides--- Perimeter Area")
DO I = 1,TASTE
WRITE (6,10) XNDX(I),STASH(XNDX(I))
END DO
 
WRITE (6,31) CHOICE
31 FORMAT ("Those triangles with area",I7)
DO I = 1,N !I could go looking through the ordered list for CHOICE entries,
IF (STASH(XNDX(I)).AREA.NE.CHOICE) CYCLE!But I can't be bothered.
WRITE (6,10) XNDX(I),STASH(XNDX(I)) !Here is one such.
END DO !Just thump through the lot.
END
</syntaxhighlight>
 
{{out}}
<pre>517 triangles of integral area. Sides up to 200
First 10, ordered by area, perimeter, longest side.
Index ---Sides--- Perimeter Area
1: 3 4 5 12 6
2: 5 5 6 16 12
3: 5 5 8 18 12
6: 4 13 15 32 24
4: 5 12 13 30 30
8: 9 10 17 36 36
19: 3 25 26 54 36
12: 7 15 20 42 42
5: 10 13 13 36 60
9: 8 15 17 40 60
Those triangles with area 210
21: 17 25 28 70 210
22: 20 21 29 70 210
33: 12 35 37 84 210
36: 17 28 39 84 210
91: 7 65 68 140 210
329: 3 148 149 300 210</pre>
 
=={{header|FreeBASIC}}==
<syntaxhighlight lang="freebasic">' version 02-05-2016
' compile with: fbc -s console
 
#Macro header
Print
Print " a b c s area"
Print "-----------------------------------"
#EndMacro
 
Type triangle
Dim As UInteger a
Dim As UInteger b
Dim As UInteger c
Dim As UInteger s
Dim As UInteger area
End Type
 
Function gcd(x As UInteger, y As UInteger) As UInteger
 
Dim As UInteger t
 
While y
t = y
y = x Mod y
x = t
Wend
 
Return x
 
End Function
 
Function Heronian_triangles(a_max As UInteger, b_max As UInteger, _
c_max As UInteger, result() As triangle) As UInteger
 
Dim As UInteger a, b, c
Dim As UInteger s, sqroot, total, temp
 
For a = 1 To a_max
For b = a To b_max
' make sure that a + b + c is even
For c = b + (a And 1) To c_max Step 2
' to form a triangle a + b must be greater then c
If (a + b) <= c Then Exit For
' check if a, b and c have a common divisor
If (gcd(c, b) <> 1 And gcd(c, a) <> 1) Then
Continue For
End If
s = (a + b + c) \ 2
temp = s * (s - a) * (s - b) * (s - c)
sqroot = Sqr(temp)
If (sqroot * sqroot) = temp Then
total += 1
With result(total)
.a = a
.b = b
.c = c
.s = s
.area = sqroot
End With
End If
Next
Next
Next
 
Return total
 
End Function
 
 
Sub sort_tri(result() As triangle, total As UInteger)
' shell sort
' sort order: area, s, c
 
Dim As UInteger x, y, inc, done
 
inc = total
Do
inc = IIf(inc > 1, inc \ 2, 1)
Do
done = 0
For x = 1 To total - inc
y = x + inc
If result(x).area > result(y).area Then
Swap result(x), result(y)
done = 1
Else
If result(x).area = result(y).area Then
If result(x).s > result(y).s Then
Swap result(x), result(y)
done = 1
Else
If result(x).s = result(y).s Then
If result(x).c > result(y).c Then
Swap result(x), result(y)
done = 1
End If
End If
End If
End If
End If
Next
Loop Until done = 0
Loop Until inc = 1
 
End Sub
 
 
' ------=< MAIN >=------
 
ReDim result(1 To 1000) As triangle
Dim As UInteger x, y, total
 
total = Heronian_triangles(200, 200, 200, result() )
 
' trim the array by removing empty entries
ReDim Preserve result(1 To total ) As triangle
 
sort_tri(result(), total)
 
Print "There are ";total;" Heronian triangles with sides <= 200"
Print
 
Print "First ten sorted entries"
header ' print header
For x = 1 To IIf(total > 9, 10, total)
With result(x)
Print Using " #####"; .a; .b; .c; .s; .area
End With
Next
Print
Print
 
Print "Entries with a area = 210"
header ' print header
For x = 1 To UBound(result)
With result(x)
If .area = 210 Then
Print Using " #####"; .a; .b; .c; .s; .area
End If
End With
Next
 
' empty keyboard buffer
While Inkey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End</syntaxhighlight>
{{out}}
<pre>There are 517 Heronian triangles with sides <= 200
 
First ten sorted entries
 
a b c s area
-----------------------------------
3 4 5 6 6
5 5 6 8 12
5 5 8 9 12
4 13 15 16 24
5 12 13 15 30
9 10 17 18 36
3 25 26 27 36
7 15 20 21 42
10 13 13 18 60
8 15 17 20 60
 
 
Entries with a area = 210
 
a b c s area
-----------------------------------
17 25 28 35 210
20 21 29 35 210
12 35 37 42 210
17 28 39 42 210
7 65 68 70 210
3 148 149 150 210</pre>
 
=={{header|FutureBasic}}==
<syntaxhighlight lang="futurebasic">
text,,,,,70// Set width of tabs
 
local fn gcd( a as long, b as long )
dim as long result
if ( b != 0 )
result = fn gcd( b, a mod b)
else
result = abs(a)
end if
end fn = result
 
begin globals
dim as long triangleInfo( 600, 4 )
end globals
 
local fn CalculateHeronianTriangles( numberToCheck as long ) as long
dim as long c, b, a, result, count : count = 0
dim as double s, area
for c = 1 to numberToCheck
for b = 1 to c
for a = 1 to b
s = ( a + b + c ) / 2
area = s * ( s - a ) * ( s - b ) * ( s - c )
if area > 0
area = sqr( area )
if area = int( area )
result = fn gcd( b, c )
result = fn gcd( a, result )
if result == 1
count++
triangleInfo( count, 0 ) = a
triangleInfo( count, 1 ) = b
triangleInfo( count, 2 ) = c
triangleInfo( count, 3 ) = 2 * s
triangleInfo( count, 4 ) = area
end if
end if
end if
next
next
next
end fn = count
 
dim as long i, k, count
 
count = fn CalculateHeronianTriangles( 200 )
 
print
print "Number of triangles:"; count
print
print "---------------------------------------------"
print "Side A", "Side B", "Side C", "Perimeter", "Area"
print "---------------------------------------------"
 
// Sort array
dim as Boolean flips : flips = _true
while ( flips = _true )
flips = _false
for i = 1 to count - 1
if triangleInfo( i, 4 ) > triangleInfo( i + 1, 4 )
for k = 0 to 4
swap triangleInfo( i, k ), triangleInfo( i + 1, k )
next
flips = _true
end if
next
wend
 
// Find first 10 heronian triangles
for i = 1 to 10
print triangleInfo( i, 0 ), triangleInfo( i, 1 ), triangleInfo( i, 2 ), triangleInfo( i, 3 ), triangleInfo( i, 4 )
next
print
print "Triangles with an area of 210:"
print
// Search for triangle with area of 210
for i = 1 to count
if triangleInfo( i, 4 ) == 210
print triangleInfo( i, 0 ), triangleInfo( i, 1 ), triangleInfo( i, 2 ), triangleInfo( i, 3 ), triangleInfo( i, 4 )
end if
next
 
HandleEvents
</syntaxhighlight>
 
Output:
<pre>
Number of triangles: 517
 
---------------------------------------------
Side A Side B Side C Perimeter Area
---------------------------------------------
3 4 5 12 6
5 5 6 16 12
5 5 8 18 12
4 13 15 32 24
5 12 13 30 30
9 10 17 36 36
3 25 26 54 36
7 15 20 42 42
10 13 13 36 60
8 15 17 40 60
 
Triangles with an area of 210:
 
17 25 28 70 210
20 21 29 70 210
12 35 37 84 210
17 28 39 84 210
7 65 68 140 210
3 148 149 300 210
</pre>
 
=={{header|Go}}==
<syntaxhighlight lang="go">package main
 
import (
"fmt"
"math"
"sort"
)
 
const (
n = 200
header = "\nSides P A"
)
 
func gcd(a, b int) int {
leftover := 1
var dividend, divisor int
if (a > b) { dividend, divisor = a, b } else { dividend, divisor = b, a }
 
for (leftover != 0) {
leftover = dividend % divisor
if (leftover > 0) {
dividend, divisor = divisor, leftover
}
}
return divisor
}
 
func is_heron(h float64) bool {
return h > 0 && math.Mod(h, 1) == 0.0
}
 
// by_area_perimeter implements sort.Interface for [][]int based on the area first and perimeter value
type by_area_perimeter [][]int
 
func (a by_area_perimeter) Len() int { return len(a) }
func (a by_area_perimeter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a by_area_perimeter) Less(i, j int) bool {
return a[i][4] < a[j][4] || a[i][4] == a[j][4] && a[i][3] < a[j][3]
}
 
func main() {
var l [][]int
for c := 1; c <= n; c++ {
for b := 1; b <= c; b++ {
for a := 1; a <= b; a++ {
if (gcd(gcd(a, b), c) == 1) {
p := a + b + c
s := float64(p) / 2.0
area := math.Sqrt(s * (s - float64(a)) * (s - float64(b)) * (s - float64(c)))
if (is_heron(area)) {
l = append(l, []int{a, b, c, p, int(area)})
}
}
}
}
}
 
fmt.Printf("Number of primitive Heronian triangles with sides up to %d: %d", n, len(l))
sort.Sort(by_area_perimeter(l))
fmt.Printf("\n\nFirst ten when ordered by increasing area, then perimeter:" + header)
for i := 0; i < 10; i++ { fmt.Printf("\n%3d", l[i]) }
 
a := 210
fmt.Printf("\n\nArea = %d%s", a, header)
for _, it := range l {
if (it[4] == a) {
fmt.Printf("\n%3d", it)
}
}
}</syntaxhighlight>
{{out}}
<pre>Number of primitive Heronian triangles with sides up to 200: 517
 
First ten when ordered by increasing area, then perimeter:
Sides P A
[ 3 4 5 12 6]
[ 5 5 6 16 12]
[ 5 5 8 18 12]
[ 4 13 15 32 24]
[ 5 12 13 30 30]
[ 9 10 17 36 36]
[ 3 25 26 54 36]
[ 7 15 20 42 42]
[ 10 13 13 36 60]
[ 8 15 17 40 60]
 
Area = 210
Sides P A
[ 17 25 28 70 210]
[ 20 21 29 70 210]
[ 12 35 37 84 210]
[ 17 28 39 84 210]
[ 7 65 68 140 210]
[ 3 148 149 300 210]</pre>
 
=={{header|Haskell}}==
<syntaxhighlight lang="haskell">import qualified Data.List as L
import Data.Maybe
import Data.Ord
import Text.Printf
 
-- Determine if a number n is a perfect square and return its square root if so.
-- This is used instead of sqrt to avoid fixed sized floating point numbers.
perfectSqrt :: Integral a => a -> Maybe a
perfectSqrt n
| n == 1 = Just 1
| n < 4 = Nothing
| otherwise =
let search low high =
let guess = (low + high) `div` 2
square = guess ^ 2
next
| square == n = Just guess
| low == guess = Nothing
| square < n = search guess high
| otherwise = search low guess
in next
in search 0 n
 
-- Determine the area of a Heronian triangle if it is one.
heronTri :: Integral a => a -> a -> a -> Maybe a
heronTri a b c =
let -- Rewrite Heron's formula to factor out the term 16 under the root.
areaSq16 = (a + b + c) * (b + c - a) * (a + c - b) * (a + b - c)
(areaSq, r) = areaSq16 `divMod` 16
in if r == 0
then perfectSqrt areaSq
else Nothing
 
isPrimitive :: Integral a => a -> a -> a -> a
isPrimitive a b c = gcd a (gcd b c)
 
third (_, _, x, _, _) = x
fourth (_, _, _, x, _) = x
fifth (_, _, _, _, x) = x
 
orders :: Ord b => [(a -> b)] -> a -> a -> Ordering
orders [f] a b = comparing f a b
orders (f:fx) a b =
case comparing f a b of
EQ -> orders fx a b
n -> n
 
main :: IO ()
main = do
let range = [1 .. 200]
tris :: [(Integer, Integer, Integer, Integer, Integer)]
tris = L.sortBy (orders [fifth, fourth, third])
$ map (\(a, b, c, d, e) -> (a, b, c, d, fromJust e))
$ filter (isJust . fifth)
[(a, b, c, a + b + c, heronTri a b c)
| a <- range, b <- range, c <- range
, a <= b, b <= c, isPrimitive a b c == 1]
printTri (a, b, c, d, e) = printf "%3d %3d %3d %9d %4d\n" a b c d e
printf "Heronian triangles found: %d\n\n" $ length tris
putStrLn " Sides Perimeter Area"
mapM_ printTri $ take 10 tris
putStrLn ""
mapM_ printTri $ filter ((== 210) . fifth) tris</syntaxhighlight>
{{out}}
<pre>Heronian triangles found: 517
 
Sides Perimeter Area
3 4 5 12 6
5 5 6 16 12
5 5 8 18 12
4 13 15 32 24
5 12 13 30 30
9 10 17 36 36
3 25 26 54 36
7 15 20 42 42
10 13 13 36 60
8 15 17 40 60
 
17 25 28 70 210
20 21 29 70 210
12 35 37 84 210
17 28 39 84 210
7 65 68 140 210
3 148 149 300 210</pre>
 
=={{header|J}}==
 
'''Hero's formula Implementation'''
Supporting implementation:
 
<langsyntaxhighlight Jlang="j">a=: 0&{"1
b=: 1&{"1
c=: 2&{"1
s=: (a+b+c) % 2:
Aarea=: 2 %: s*(s-a)*(s-b)*(s-c) NB. Hero's formula
Pperim=: +/"1
isprimheroisPrimHero=: (0&~: * (= <.@:+))@Aarea * 1 = a +. b +. c</syntaxhighlight>
 
We exclude triangles with zero area, triangles with complex area, non-integer area, and triangles whose sides share a common integer multiple.
tri=: (/: A,.P,.{:"1) (#~ isprimhero)~./:"1~1+200 200 200#:i.200^3</lang>
 
'''Alternative Implementation'''
Required examples:
 
The implementation above uses the symbols as given in the formula at the top of the page, making it easier to follow along as well as spot any errors. That formula distinguishes between the individual sides of the triangles but J could easily treat these sides as a single entity or array. The implementation below uses this "typical J" approach:
<lang J> #tri
 
<syntaxhighlight lang="j">perim=: +/"1
s=: -:@:perim
area=: [: %: s * [: */"1 s - ] NB. Hero's formula
isNonZeroInt=: 0&~: *. (= <.@:+)
isPrimHero=: isNonZeroInt@area *. 1 = +./&.|:</syntaxhighlight>
 
'''Required examples'''
 
<syntaxhighlight lang="j"> Tri=:(1-i.3)+"1]3 comb 202 NB. distinct triangles with sides <= 200
HeroTri=: (#~ isPrimHero) Tri NB. all primitive Heronian triangles with sides <= 200
 
# HeroTri NB. count triangles found
517
 
HeroTri=: (/: area ,. perim ,. ]) HeroTri NB. sort by area, perimeter & sides
10{.(,._,.A,.P) tri
 
3 4 5 _ 6 12
(,. _ ,. perim ,. area) 10 {. HeroTri NB. tabulate sides, perimeter & area for top 10 triangles
5 5 6 _ 12 16
53 54 85 _ 12 18 6
45 13 155 6 _ 2416 3212
5 5 8 _ 18 12
4 13 15 _ 32 24
5 12 13 _ 30 30
9 10 17 _ 36 36
3 25 26 _ 36 54 36
7 15 20 _ 42 42
10 13 13 _ 60 36 60
8 15 17 _ 60 40 60
 
(,. _ ,. perim ,. area) (#~ 210 = area) HeroTri NB. tablulate sides, perimeter & area for triangles with area = 210
17 25 28 _ 70 210
20 21 29 _ 70 210
12 35 37 _ 84 210
17 28 39 _ 84 210
7 65 68 _ 140 210
3 148 149 _ 300 210</syntaxhighlight>
 
=={{header|Java}}==
<syntaxhighlight lang="java">import java.util.ArrayList;
 
public class Heron {
public static void main(String[] args) {
ArrayList<int[]> list = new ArrayList<>();
 
for (int c = 1; c <= 200; c++) {
for (int b = 1; b <= c; b++) {
for (int a = 1; a <= b; a++) {
 
if (gcd(gcd(a, b), c) == 1 && isHeron(heronArea(a, b, c))){
int area = (int) heronArea(a, b, c);
list.add(new int[]{a, b, c, a + b + c, area});
}
}
}
}
sort(list);
 
System.out.printf("Number of primitive Heronian triangles with sides up "
+ "to 200: %d\n\nFirst ten when ordered by increasing area, then"
+ " perimeter:\nSides Perimeter Area", list.size());
 
for (int i = 0; i < 10; i++) {
System.out.printf("\n%d x %d x %d %d %d",
list.get(i)[0], list.get(i)[1], list.get(i)[2],
list.get(i)[3], list.get(i)[4]);
}
 
System.out.printf("\n\nArea = 210\nSides Perimeter Area");
for (int i = 0; i < list.size(); i++) {
if (list.get(i)[4] == 210)
System.out.printf("\n%d x %d x %d %d %d",
list.get(i)[0], list.get(i)[1], list.get(i)[2],
list.get(i)[3], list.get(i)[4]);
}
}
 
public static double heronArea(int a, int b, int c) {
double s = (a + b + c) / 2f;
return Math.sqrt(s * (s - a) * (s - b) * (s - c));
}
 
public static boolean isHeron(double h) {
return h % 1 == 0 && h > 0;
}
 
public static int gcd(int a, int b) {
int leftover = 1, dividend = a > b ? a : b, divisor = a > b ? b : a;
while (leftover != 0) {
leftover = dividend % divisor;
if (leftover > 0) {
dividend = divisor;
divisor = leftover;
}
}
return divisor;
}
 
public static void sort(ArrayList<int[]> list) {
boolean swapped = true;
int[] temp;
while (swapped) {
swapped = false;
for (int i = 1; i < list.size(); i++) {
if (list.get(i)[4] < list.get(i - 1)[4] ||
list.get(i)[4] == list.get(i - 1)[4] &&
list.get(i)[3] < list.get(i - 1)[3]) {
temp = list.get(i);
list.set(i, list.get(i - 1));
list.set(i - 1, temp);
swapped = true;
}
}
}
}
}</syntaxhighlight>
{{out}}
<pre>Number of primitive Heronian triangles with sides up to 200: 517
 
First ten when ordered by increasing area, then perimeter:
Sides Perimeter Area
3 x 4 x 5 12 6
5 x 5 x 6 16 12
5 x 5 x 8 18 12
4 x 13 x 15 32 24
5 x 12 x 13 30 30
9 x 10 x 17 36 36
3 x 25 x 26 54 36
7 x 15 x 20 42 42
10 x 13 x 13 36 60
8 x 15 x 17 40 60
 
Area = 210
Sides Perimeter Area
17 x 25 x 28 70 210
20 x 21 x 29 70 210
12 x 35 x 37 84 210
17 x 28 x 39 84 210
7 x 65 x 68 140 210
3 x 148 x 149 300 210</pre>
 
=={{header|JavaScript}}==
 
===Imperative===
 
<syntaxhighlight lang="javascript">
window.onload = function(){
var list = [];
var j = 0;
for(var c = 1; c <= 200; c++)
for(var b = 1; b <= c; b++)
for(var a = 1; a <= b; a++)
if(gcd(gcd(a, b), c) == 1 && isHeron(heronArea(a, b, c)))
list[j++] = new Array(a, b, c, a + b + c, heronArea(a, b, c));
sort(list);
document.write("<h2>Primitive Heronian triangles with sides up to 200: " + list.length + "</h2><h3>First ten when ordered by increasing area, then perimeter:</h3><table><tr><th>Sides</th><th>Perimeter</th><th>Area</th><tr>");
for(var i = 0; i < 10; i++)
document.write("<tr><td>" + list[i][0] + " x " + list[i][1] + " x " + list[i][2] + "</td><td>" + list[i][3] + "</td><td>" + list[i][4] + "</td></tr>");
document.write("</table><h3>Area = 210</h3><table><tr><th>Sides</th><th>Perimeter</th><th>Area</th><tr>");
for(var i = 0; i < list.length; i++)
if(list[i][4] == 210)
document.write("<tr><td>" + list[i][0] + " x " + list[i][1] + " x " + list[i][2] + "</td><td>" + list[i][3] + "</td><td>" + list[i][4] + "</td></tr>");
function heronArea(a, b, c){
var s = (a + b + c)/ 2;
return Math.sqrt(s *(s -a)*(s - b)*(s - c));
}
function isHeron(h){
return h % 1 == 0 && h > 0;
}
function gcd(a, b){
var leftover = 1, dividend = a > b ? a : b, divisor = a > b ? b : a;
while(leftover != 0){
leftover = dividend % divisor;
if(leftover > 0){
dividend = divisor;
divisor = leftover;
}
}
return divisor;
}
function sort(list){
var swapped = true;
var temp = [];
while(swapped){
swapped = false;
for(var i = 1; i < list.length; i++){
if(list[i][4] < list[i - 1][4] || list[i][4] == list[i - 1][4] && list[i][3] < list[i - 1][3]){
temp = list[i];
list[i] = list[i - 1];
list[i - 1] = temp;
swapped = true;
}
}
}
}
}
</syntaxhighlight>
{{out}}
<pre>Primitive Heronian triangles with sides up to 200: 517
 
First ten when ordered by increasing area, then perimeter:
Sides Perimeter Area
3 x 4 x 5 12 6
5 x 5 x 6 16 12
5 x 5 x 8 18 12
4 x 13 x 15 32 24
5 x 12 x 13 30 30
9 x 10 x 17 36 36
3 x 25 x 26 54 36
7 x 15 x 20 42 42
10 x 13 x 13 36 60
8 x 15 x 17 40 60
 
Area = 210
Sides Perimeter Area
17 x 25 x 28 70 210
20 x 21 x 29 70 210
12 x 35 x 37 84 210
17 x 28 x 39 84 210
7 x 65 x 68 140 210
3 x 148 x 149 300 210</pre>
 
===Functional (ES5)===
 
Using the list monad pattern to define a filtered cartesian product:
:- Monadic bind/chain for lists is ''concat map''.
:- Return/inject for lists is ''λx -> [x]''
:- Monadic fail for lists is simply ''λx -> []''.
 
List comprehension syntax is convenient and concise, but efficient use of it may be helped by a clearer understanding of the formally equivalent – but slightly more flexible – list monad pattern.
See, for example [https://wiki.haskell.org/List_comprehension List comprehension] at wiki.haskell.org. (Haskell list comprehensions are themselves implemented in terms of ''concat map'').
ES6 JavaScript introduces syntactic sugar for list comprehensions, but the list monad pattern can already be used in ES5 – indeed in any language which supports the use of higher-order functions.
 
<syntaxhighlight lang="javascript">(function (n) {
var chain = function (xs, f) { // Monadic bind/chain
return [].concat.apply([], xs.map(f));
},
hArea = function (x, y, z) {
var s = (x + y + z) / 2,
a = s * (s - x) * (s - y) * (s - z);
return a ? Math.sqrt(a) : 0;
},
gcd = function (m, n) { return n ? gcd(n, m % n) : m; },
rng = function (m, n) {
return Array.apply(null, Array(n - m + 1)).map(function (x, i) {
return m + i;
});
},
sum = function (a, x) { return a + x; };
// DEFINING THE SORTED SUB-SET IN TERMS OF A LIST MONAD
var lstHeron = chain( rng(1, n), function (x) {
return chain( rng(x, n), function (y) {
return chain( rng(y, n), function (z) {
return (
(x + y > z) &&
gcd(gcd(x, y), z) === 1 && // Primitive.
(function () { // Heronian.
var a = hArea(x, y, z);
return a && (a === parseInt(a, 10))
})()
) ? [[x, y, z]] : []; // Monadic inject or fail
})})}).sort(function (a, b) {
var dArea = hArea.apply(null, a) - hArea.apply(null, b);
if (dArea) return dArea;
else {
var dPerim = a.reduce(sum, 0) - b.reduce(sum, 0);
return dPerim ? dPerim : (a[2] - b[2]);
}
});
// OUPUT FORMATTED AS TWO WIKITABLES
var lstColumns = ['Sides Perimeter Area'.split(' ')],
fnData = function (lst) {
return [JSON.stringify(lst), lst.reduce(sum, 0), hArea.apply(null, lst)];
},
wikiTable = function (lstRows, blnHeaderRow, strStyle) {
return '{| class="wikitable" ' + (
strStyle ? 'style="' + strStyle + '"' : ''
) + lstRows.map(function (lstRow, iRow) {
var strDelim = ((blnHeaderRow && !iRow) ? '!' : '|');
return '\n|-\n' + strDelim + ' ' + lstRow.map(function (v) {
return typeof v === 'undefined' ? ' ' : v;
}).join(' ' + strDelim + strDelim + ' ');
}).join('') + '\n|}';
};
return 'Found: ' + lstHeron.length +
' primitive Heronian triangles with sides up to ' + n + '.\n\n' +
'(Showing first 10, sorted by increasing area, ' +
'perimeter, and longest side)\n\n' +
wikiTable(
lstColumns.concat(lstHeron.slice(0, 10).map(fnData)),
true
) + '\n\n' +
'All primitive Heronian triangles in this range where area = 210\n' +
'\n(also in order of increasing perimeter and longest side)\n\n' +
wikiTable(
lstColumns.concat(lstHeron.filter(function (x) {
return 210 === hArea.apply(null, x);
}).map(fnData)),
true
) + '\n\n';
})(200);</syntaxhighlight>
 
{{out}}
Found: 517 primitive Heronian triangles with sides up to 200.
 
(Showing first 10, sorted by increasing area, perimeter, and longest side)
 
{| class="wikitable"
|-
! Sides !! Perimeter !! Area
|-
| [3,4,5] || 12 || 6
|-
| [5,5,6] || 16 || 12
|-
| [5,5,8] || 18 || 12
|-
| [4,13,15] || 32 || 24
|-
| [5,12,13] || 30 || 30
|-
| [9,10,17] || 36 || 36
|-
| [3,25,26] || 54 || 36
|-
| [7,15,20] || 42 || 42
|-
| [10,13,13] || 36 || 60
|-
| [8,15,17] || 40 || 60
|}
 
All primitive Heronian triangles in this range where area = 210
 
(also in order of increasing perimeter and longest side)
 
{| class="wikitable"
(#~210=A) (,._,.A,.P) tri
|-
17 25 28 _ 210 70
! Sides !! Perimeter !! Area
20 21 29 _ 210 70
|-
12 35 37 _ 210 84
| [17 ,25,28] || 3970 _|| 210 84
|-
7 65 68 _ 210 140
| [20,21,29] || 70 || 210
3 148 149 _ 210 300</lang>
|-
| [12,35,37] || 84 || 210
|-
| [17,28,39] || 84 || 210
|-
| [7,65,68] || 140 || 210
|-
| [3,148,149] || 300 || 210
|}
 
=={{header|jq}}==
{{works with|jq|1.4}}
<langsyntaxhighlight lang="jq"># input should be an array of the lengths of the sides
def hero:
(add/2) as $s
Line 181 ⟶ 2,754:
( .[] | select( hero == 210 ) | "\(rjust(11)) \(add|rjust(3)) \(hero|rjust(4))" ) ;
 
task(200)</langsyntaxhighlight>
{{out}}
<langsyntaxhighlight lang="sh">$ time jq -n -r -f heronian.jq
The number of primitive Heronian triangles with sides up to 200: 517
The first ten when ordered by increasing area, then perimeter, then maximum sides:
Line 204 ⟶ 2,777:
[17,28,39] 84 210
[7,65,68] 140 210
[3,148,149] 300 210</langsyntaxhighlight>
 
=={{header|Julia}}==
The type <tt>IntegerTriangle</tt> stores a triangle's sides (a, b, c), perimeter (p) and area (&sigma;) as integers. The function <tt>isprimheronian</tt> checks whether the a triangle of integer sides is a primitive Heronian triangle and is called prior to construction of an <tt>IntegerTriangle</tt>.
 
'''Types and Functions'''
<syntaxhighlight lang="julia">
type IntegerTriangle{T<:Integer}
a::T
b::T
c::T
p::T
σ::T
end
 
function IntegerTriangle{T<:Integer}(a::T, b::T, c::T)
p = a + b + c
s = div(p, 2)
σ = isqrt(s*(s-a)*(s-b)*(s-c))
(x, y, z) = sort([a, b, c])
IntegerTriangle(x, y, z, p, σ)
end
 
function isprimheronian{T<:Integer}(a::T, b::T, c::T)
p = a + b + c
iseven(p) || return false
gcd(a, b, c) == 1 || return false
s = div(p, 2)
t = s*(s-a)*(s-b)*(s-c)
0 < t || return false
σ = isqrt(t)
σ^2 == t
end
</syntaxhighlight>
 
'''Main'''
<syntaxhighlight lang="julia">
slim = 200
 
ht = IntegerTriangle[]
 
for a in 1:slim, b in a:slim, c in b:slim
isprimheronian(a, b, c) || continue
push!(ht, IntegerTriangle(a, b, c))
end
 
sort!(ht, by=x->(x.σ, x.p, x.c))
 
print("The number of primitive Hernonian triangles having sides ≤ ")
println(slim, " is ", length(ht))
 
tlim = 10
tlim = min(tlim, length(ht))
 
println()
println("Tabulating the first (by σ, p, c) ", tlim, " of these:")
println(" a b c σ p")
for t in ht[1:tlim]
println(@sprintf "%6d %3d %3d %4d %4d" t.a t.b t.c t.σ t.p)
end
 
tlim = 210
println()
println("Tabulating those having σ = ", tlim, ":")
println(" a b c σ p")
for t in ht
t.σ == tlim || continue
t.σ == tlim || break
println(@sprintf "%6d %3d %3d %4d %4d" t.a t.b t.c t.σ t.p)
end
</syntaxhighlight>
 
{{out}}
<pre>The number of primitive Hernonian triangles having sides ≤ 200 is 517
 
Tabulating the first (by σ, p, c) 10 of these:
a b c σ p
3 4 5 6 12
5 5 6 12 16
5 5 8 12 18
4 13 15 24 32
5 12 13 30 30
9 10 17 36 36
3 25 26 36 54
7 15 20 42 42
10 13 13 60 36
8 15 17 60 40
 
Tabulating those having σ = 210:
a b c σ p
17 25 28 210 70
20 21 29 210 70
12 35 37 210 84
17 28 39 210 84
7 65 68 210 140
3 148 149 210 300</pre>
 
=={{header|Kotlin}}==
{{trans|Scala}}
<syntaxhighlight lang="scala">import java.util.ArrayList
 
object Heron {
private val n = 200
 
fun run() {
val l = ArrayList<IntArray>()
for (c in 1..n)
for (b in 1..c)
for (a in 1..b)
if (gcd(gcd(a, b), c) == 1) {
val p = a + b + c
val s = p / 2.0
val area = Math.sqrt(s * (s - a) * (s - b) * (s - c))
if (isHeron(area))
l.add(intArrayOf(a, b, c, p, area.toInt()))
}
print("Number of primitive Heronian triangles with sides up to $n: " + l.size)
 
sort(l)
print("\n\nFirst ten when ordered by increasing area, then perimeter:" + header)
for (i in 0 until 10) {
print(format(l[i]))
}
val a = 210
print("\n\nArea = $a" + header)
l.filter { it[4] == a }.forEach { print(format(it)) }
}
 
private fun gcd(a: Int, b: Int): Int {
var leftover = 1
var dividend = if (a > b) a else b
var divisor = if (a > b) b else a
while (leftover != 0) {
leftover = dividend % divisor
if (leftover > 0) {
dividend = divisor
divisor = leftover
}
}
return divisor
}
 
fun sort(l: MutableList<IntArray>) {
var swapped = true
while (swapped) {
swapped = false
for (i in 1 until l.size)
if (l[i][4] < l[i - 1][4] || l[i][4] == l[i - 1][4] && l[i][3] < l[i - 1][3]) {
val temp = l[i]
l[i] = l[i - 1]
l[i - 1] = temp
swapped = true
}
}
}
 
private fun isHeron(h: Double) = h.rem(1) == 0.0 && h > 0
 
private val header = "\nSides Perimeter Area"
private fun format(a: IntArray) = "\n%3d x %3d x %3d %5d %10d".format(a[0], a[1], a[2], a[3], a[4])
}
 
fun main(args: Array<String>) = Heron.run()</syntaxhighlight>
{{out}}
<pre>Number of primitive Heronian triangles with sides up to 200: 517
 
First ten when ordered by increasing area, then perimeter:
Sides Perimeter Area
3 x 4 x 5 12 6
5 x 5 x 6 16 12
5 x 5 x 8 18 12
4 x 13 x 15 32 24
5 x 12 x 13 30 30
9 x 10 x 17 36 36
3 x 25 x 26 54 36
7 x 15 x 20 42 42
10 x 13 x 13 36 60
8 x 15 x 17 40 60
 
Area = 210
Sides Perimeter Area
17 x 25 x 28 70 210
20 x 21 x 29 70 210
12 x 35 x 37 84 210
17 x 28 x 39 84 210
7 x 65 x 68 140 210
3 x 148 x 149 300 210</pre>
 
=={{header|Logtalk}}==
 
Implemented as a parametric object, the solution to making primitive Heronian triangles would look something like this:
 
<syntaxhighlight lang="logtalk">
% In this example we assume that A<=B<=C.
% Non-pedagogical code would verify and force this.
:- object(triangle(_A_, _B_, _C_)).
 
:- public([a/1, b/1, c/1, area/1, perimeter/1, primitive/0]).
 
a(_A_). b(_B_). c(_C_).
 
area(A) :-
AB is _A_ + _B_,
AB @> _C_, % you can't make a triangle if one side is half or longer the perimeter
s(S),
A is sqrt(S * (S - _A_) * (S - _B_) * (S - _C_)).
 
perimeter(P) :-
P is _A_ + _B_ + _C_.
 
primitive :- heronian, gcd(1).
 
% helper predicates
 
heronian :-
integer(_A_),
integer(_B_),
integer(_C_),
area(A),
A > 0.0,
0.0 is float_fractional_part(A).
 
gcd(G) :- G is gcd(_A_, gcd(_B_, _C_)).
 
s(S) :- perimeter(P), S is P / 2.
 
:- end_object.
</syntaxhighlight>
 
A quickly hacked-together test that produces the output for the task assignment would look something like this:
 
<syntaxhighlight lang="logtalk">
:- object(test_triangle).
 
:- uses(integer, [between/3]).
:- uses(list, [length/2, member/2, sort/3, take/3]).
:- uses(logtalk, [print_message(information, heronian, Message) as print(Message)]).
 
:- public(start/0).
 
start :-
 
gather_primitive_heronians(Primitives),
length(Primitives, L),
print('There are ~w primitive Heronian triangles with sides under 200.~n'+[L]),
 
sort(order_by(area), Primitives, AreaSorted),
take(10, AreaSorted, Area10),
print(@'The first ten found, ordered by area, are:\n'),
display_each_element(Area10),
 
sort(order_by(perimeter), Primitives, PerimeterSorted),
take(10, PerimeterSorted, Perimeter10),
print(@'The first ten found, ordered by perimeter, are:\n'),
display_each_element(Perimeter10),
 
findall(
t(A, B, C, 210.0, Perimeter),
member(t(A, B, C, 210.0, Perimeter), Primitives),
Area210
),
print(@'The list of those with an area of 210 is:\n'),
display_each_element(Area210).
 
% localized helper predicates
 
% display a single element in the provided format
display_single_element(t(A,B,C,Area,Perimeter)) :-
format(F),
print(F+[A, B, C, Area, Perimeter]).
 
% display each element in a list of elements, printing a header first
display_each_element(L) :-
print(@' A B C Area Perimeter'),
print(@'=== === === ======= ========='),
forall(member(T, L), display_single_element(T)),
print(@'\n').
 
format('~|~` t~w~3+~` t~w~4+~` t~w~4+~` t~w~8+~` t~w~7+').
 
% collect all the primitive heronian triangles within the boundaries of the provided task
gather_primitive_heronians(Primitives) :-
findall(
t(A, B, C, Area, Perimeter),
(
between(3, 200, A),
between(A, 200, B),
between(B, 200, C),
triangle(A, B, C)::primitive,
triangle(A, B, C)::area(Area),
triangle(A, B, C)::perimeter(Perimeter)
),
Primitives
).
 
order_by(_, =, T, T) :- !.
order_by(area, <, t(_,_,_,Area1,_), t(_,_,_,Area2,_)) :- Area1 < Area2, !.
order_by(area, >, t(_,_,_,Area1,_), t(_,_,_,Area2,_)) :- Area1 > Area2, !.
order_by(perimeter, <, t(_,_,_,_,Perimeter1), t(_,_,_,_,Perimeter2)) :- Perimeter1 < Perimeter2, !.
order_by(perimeter, >, t(_,_,_,_,Perimeter1), t(_,_,_,_,Perimeter2)) :- Perimeter1 > Perimeter2, !.
order_by(_, <, t(A1,_,_,_,_), t(A2,_,_,_,_)) :- A1 < A2, !.
order_by(_, <, t(_,B1,_,_,_), t(_,B2,_,_,_)) :- B1 < B2, !.
order_by(_, <, t(_,_,C1,_,_), t(_,_,C2,_,_)) :- C1 < C2, !.
order_by(_, >, _, _).
 
:- end_object.
</syntaxhighlight>
 
{{Out}}
 
<pre>
?- test_triangle::start.
% There are 517 primitive Heronian triangles with sides under 200.
 
% The first ten found, ordered by area, are:
 
% A B C Area Perimeter
% === === === ======= =========
% 3 4 5 6.0 12
% 5 5 6 12.0 16
% 5 5 8 12.0 18
% 4 13 15 24.0 32
% 5 12 13 30.0 30
% 3 25 26 36.0 54
% 9 10 17 36.0 36
% 7 15 20 42.0 42
% 6 25 29 60.0 60
% 8 15 17 60.0 40
%
 
% The first ten found, ordered by perimeter, are:
 
% A B C Area Perimeter
% === === === ======= =========
% 3 4 5 6.0 12
% 5 5 6 12.0 16
% 5 5 8 12.0 18
% 5 12 13 30.0 30
% 4 13 15 24.0 32
% 9 10 17 36.0 36
% 10 13 13 60.0 36
% 8 15 17 60.0 40
% 7 15 20 42.0 42
% 13 14 15 84.0 42
%
 
% The list of those with an area of 210 is:
 
% A B C Area Perimeter
% === === === ======= =========
% 3 148 149 210.0 300
% 7 65 68 210.0 140
% 12 35 37 210.0 84
% 17 25 28 210.0 70
% 17 28 39 210.0 84
% 20 21 29 210.0 70
%
 
true.
</pre>
 
=={{header|Lua}}==
<syntaxhighlight lang="lua">-- Returns the details of the Heronian Triangle with sides a, b, c or nil if it isn't one
local function tryHt( a, b, c )
local result
local s = ( a + b + c ) / 2;
local areaSquared = s * ( s - a ) * ( s - b ) * ( s - c );
if areaSquared > 0 then
-- a, b, c does form a triangle
local area = math.sqrt( areaSquared );
if math.floor( area ) == area then
-- the area is integral so the triangle is Heronian
result = { a = a, b = b, c = c, perimeter = a + b + c, area = area }
end
end
return result
end
 
-- Returns the GCD of a and b
local function gcd( a, b ) return ( b == 0 and a ) or gcd( b, a % b ) end
 
-- Prints the details of the Heronian triangle t
local function htPrint( t ) print( string.format( "%4d %4d %4d %4d %4d", t.a, t.b, t.c, t.area, t.perimeter ) ) end
-- Prints headings for the Heronian Triangle table
local function htTitle() print( " a b c area perimeter" ); print( "---- ---- ---- ---- ---------" ) end
 
-- Construct ht as a table of the Heronian Triangles with sides up to 200
local ht = {};
for c = 1, 200 do
for b = 1, c do
for a = 1, b do
local t = gcd( gcd( a, b ), c ) == 1 and tryHt( a, b, c );
if t then
ht[ #ht + 1 ] = t
end
end
end
end
 
-- sort the table on ascending area, perimiter and max side length
-- note we constructed the triangles with c as the longest side
table.sort( ht, function( a, b )
return a.area < b.area or ( a.area == b.area
and ( a.perimeter < b.perimeter
or ( a.perimiter == b.perimiter
and a.c < b.c
)
)
)
end
);
 
-- Display the triangles
print( "There are " .. #ht .. " Heronian triangles with sides up to 200" );
htTitle();
for htPos = 1, 10 do htPrint( ht[ htPos ] ) end
print( " ..." );
print( "Heronian triangles with area 210:" );
htTitle();
for htPos = 1, #ht do
local t = ht[ htPos ];
if t.area == 210 then htPrint( t ) end
end</syntaxhighlight>
{{out}}
<pre>
There are 517 Heronian triangles with sides up to 200
a b c area perimeter
---- ---- ---- ---- ---------
3 4 5 6 12
5 5 6 12 16
5 5 8 12 18
4 13 15 24 32
5 12 13 30 30
9 10 17 36 36
3 25 26 36 54
7 15 20 42 42
10 13 13 60 36
8 15 17 60 40
...
Heronian triangles with area 210:
a b c area perimeter
---- ---- ---- ---- ---------
17 25 28 210 70
20 21 29 210 70
12 35 37 210 84
17 28 39 210 84
7 65 68 210 140
3 148 149 210 300
</pre>
 
=={{header|Mathematica}} / {{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">ClearAll[Heron]
Heron[a_, b_, c_] := With[{s = (a + b + c)/2}, Sqrt[s (s - a) (s - b) (s - c)]]
PrintTemporary[Dynamic[{a, b, c}]];
results = Reap[
Do[
If[a < b + c \[And] b < c + a \[And] c < a + b,
If[GCD[a, b, c] == 1,
If[IntegerQ[Heron[a, b, c]],
Sow[<|"Sides" -> {a, b, c}, "Area" -> Heron[a, b, c],
"Perimeter" -> a + b + c, "MaximumSide" -> Max[a, b, c]|>]
]
]
]
,
{a, 1, 200},
{b, a, 200},
{c, b, 200}
]
][[2, 1]];
results = SortBy[results, {#["Area"] &, #["Perimeter"] &, #["MaximumSide"] &}];
results // Length
Take[results, 10] // Dataset
Select[results, #["Area"] == 210 &] // Dataset</syntaxhighlight>
{{out}}
<pre>517
 
Sides Area Perimeter MaximumSide
{3,4,5} 6 12 5
{5,5,6} 12 16 6
{5,5,8} 12 18 8
{4,13,15} 24 32 15
{5,12,13} 30 30 13
{9,10,17} 36 36 17
{3,25,26} 36 54 26
{7,15,20} 42 42 20
{10,13,13} 60 36 13
{8,15,17} 60 40 17
 
Sides Area Perimeter MaximumSide
{17,25,28} 210 70 28
{20,21,29} 210 70 29
{12,35,37} 210 84 37
{17,28,39} 210 84 39
{7,65,68} 210 140 68
{3,148,149} 210 300 149</pre>
 
=={{header|Nim}}==
<syntaxhighlight lang="nim">import std/[math, algorithm, lenientops, strformat, sequtils]
 
type HeronianTriangle = tuple[a, b, c: int; p: int; area: int]
 
# Functions with three operands.
func max(a, b, c: int): int = max(a, max(b, c))
func gcd(a, b, c: int): int = gcd(a, gcd(b, c))
 
func cmp(x, y: HeronianTriangle): int =
## Compare two Heronian triangles.
result = cmp(x.area, y.area)
if result == 0:
result = cmp(x.p, y.p)
if result == 0:
result = cmp(max(x.a, x.b, x.c), max(y.a, y.b, y.c))
 
func `$`(t: HeronianTriangle): string =
## Return the representation of a Heronian triangle.
fmt"{t.a:3d}, {t.b:3d}, {t.c:3d} {t.p:7d} {t.area:8d}"
 
 
func hero(a, b, c: int): float =
## Return the area of a triangle using Hero's formula.
let s = (a + b + c) / 2
result = sqrt(s * (s - a) * (s - b) * (s - c))
 
func isHeronianTriangle(x: float): bool = x > 0 and ceil(x) == x
 
const Header = " Sides Perimeter Area\n------------- --------- ----"
 
var list: seq[HeronianTriangle]
const Max = 200
 
for c in 1..Max:
for b in 1..c:
for a in 1..b:
let area = hero(a, b, c)
if area.isHeronianTriangle and gcd(a, b, c) == 1:
let t: HeronianTriangle = (a, b, c, a + b + c, area.toInt)
list.add t
 
list.sort(cmp)
echo "Number of Heronian triangles: ", list.len
 
echo "\nOrdered list of first ten Heronian triangles:"
echo Header
for t in list[0 ..< 10]: echo t
 
echo "\nOrdered list of Heronian triangles with area 210:"
echo Header
for t in list.filterIt(it.area == 210): echo t
</syntaxhighlight>
{{out}}
<pre>Number of Heronian triangles: 517
 
Ordered list of first ten Heronian triangles:
Sides Perimeter Area
------------- --------- ----
3, 4, 5 12 6
5, 5, 6 16 12
5, 5, 8 18 12
4, 13, 15 32 24
5, 12, 13 30 30
9, 10, 17 36 36
3, 25, 26 54 36
7, 15, 20 42 42
10, 13, 13 36 60
8, 15, 17 40 60
 
Ordered list of Heronian triangles with area 210:
Sides Perimeter Area
------------- --------- ----
17, 25, 28 70 210
20, 21, 29 70 210
12, 35, 37 84 210
17, 28, 39 84 210
7, 65, 68 140 210
3, 148, 149 300 210</pre>
 
=={{header|ooRexx}}==
Derived from REXX with some changes
<syntaxhighlight lang="rexx">/*REXX pgm generates primitive Heronian triangles by side length & area.*/
Call time 'R'
Numeric Digits 12
Parse Arg mxs area list
If mxs ='' Then mxs =200
If area='' Then area=210
If list='' Then list=10
tx='primitive Heronian triangles'
Call heronian mxs /* invoke sub with max SIDES. */
Say nt tx 'found with side length up to' mxs "(inclusive)."
Call show '2'
Call show '3'
Say time('E') 'seconds elapsed'
Exit
 
heronian:
abc.=0 /* abc.ar.p.* contains 'a b c' for area ar and perimeter p */
nt=0 /* number of triangles found */
min.=''
max.=''
mem.=0
ln=length(mxs)
Do a=3 To mxs
Do b=a To mxs
ab=a+b
Do c=b To mxs
If hgcd(a,b,c)=1 Then Do /* GCD=1 */
ar=heron_area()
If pos('.',ar)=0 Then Do /* is an integer */
nt=nt+1 /* a primitive Heronian triangle.*/
Call minmax '0P',p
Call minmax '0A',a
per=ab+c
abc_ar=right(per,4) right(a,4) right(b,4) right(c,4),
right(ar,5)
Call mem abc_ar
End
End
End
End
End
/*
say 'min.p='min.0p
say 'max.p='max.0p
say 'min.a='min.0a
say 'max.a='max.0a
*/
Return nt
 
hgcd: Procedure
Parse Arg x
Do j=2 For 2
y=arg(j)
Do Until _==0
_=x//y
x=y
y=_
End
End
Return x
 
minmax:
Parse Arg which,x
If min.which='' Then Do
min.which=x
max.which=x
End
Else Do
min.which=min(min.which,x)
max.which=max(max.which,x)
End
--Say which min.which '-' max.which
Return
 
heron_area:
p=ab+c /* perimeter */
s=p/2
ar2=s*(s-a)*(s-b)*(s-c) /* area**2 */
If pos(right(ar2,1),'014569')=0 Then /* ar2 cannot be */
Return '.' /* square of an integer*/
If ar2>0 Then
ar=sqrt(ar2) /* area */
Else
ar='.'
Return ar
 
show: Parse Arg which
Say ''
Select
When which='2' Then Do
Say 'Listing of the first' list tx":"
Do i=1 To list
Call ot i,mem.i
End
End
When which='3' Then Do
Say 'Listing of the' tx "with area=210"
j=0
Do i=1 To mem.0
Parse Var mem.i per a b c area
If area=210 Then Do
j=j+1
Call ot j,mem.i
End
End
End
End
Return
 
ot: Parse Arg k,mem
Parse Var mem per a b c area
Say right(k,9)' area:'right(area,6)||,
' perimeter:'right(per,4)' sides:',
right(a,3) right(b,3) right(c,3)
Return
 
mem:
Parse Arg e
Do i=1 To mem.0
If mem.i>>e Then Leave
End
Do j=mem.0 to i By -1
j1=j+1
mem.j1=mem.j
End
mem.i=e
mem.0=mem.0+1
Return
/* for "Classic" REXX
sqrt: procedure; parse arg x;if x=0 then return 0;d=digits();numeric digits 11
numeric form; parse value format(x,2,1,,0) 'E0' with g 'E' _ .; g=g*.5'E'_%2
p=d+d%4+2; m.=11; do j=0 while p>9; m.j=p; p=p%2+1; end; do k=j+5 to 0 by -1
if m.k>11 then numeric digits m.k;g=.5*(g+x/g);end;numeric digits d;return g/1
*/
/* for ooRexx */
::requires rxmath library
::routine sqrt
Return rxCalcSqrt(arg(1),14)</syntaxhighlight>
{{out}}
<pre>517 primitive Heronian triangles found with side length up to 200 (inclusive).
 
Listing of the first 10 primitive Heronian triangles:
1 area: 6 perimeter: 12 sides: 3 4 5
2 area: 12 perimeter: 16 sides: 5 5 6
3 area: 12 perimeter: 18 sides: 5 5 8
4 area: 30 perimeter: 30 sides: 5 12 13
5 area: 24 perimeter: 32 sides: 4 13 15
6 area: 36 perimeter: 36 sides: 9 10 17
7 area: 60 perimeter: 36 sides: 10 13 13
8 area: 60 perimeter: 40 sides: 8 15 17
9 area: 42 perimeter: 42 sides: 7 15 20
10 area: 84 perimeter: 42 sides: 13 14 15
 
Listing of the primitive Heronian triangles with area=210
1 area: 210 perimeter: 70 sides: 17 25 28
2 area: 210 perimeter: 70 sides: 20 21 29
3 area: 210 perimeter: 84 sides: 12 35 37
4 area: 210 perimeter: 84 sides: 17 28 39
5 area: 210 perimeter: 140 sides: 7 65 68
6 area: 210 perimeter: 300 sides: 3 148 149
26.054000 seconds elapsed </pre>
 
=={{header|PARI/GP}}==
 
<syntaxhighlight lang="parigp">Heron(v)=my([a,b,c]=v); (a+b+c)*(-a+b+c)*(a-b+c)*(a+b-c) \\ returns 16 times the squared area
is(a,b,c)=(a+b+c)%2==0 && gcd(a,gcd(b,c))==1 && issquare(Heron([a,b,c]))
v=List(); for(a=1,200,for(b=a+1,200,for(c=b+1,200, if(is(a,b,c),listput(v, [a,b,c])))));
v=Vec(v); #v
vecsort(v, (a,b)->Heron(a)-Heron(b))[1..10]
vecsort(v, (a,b)->vecsum(a)-vecsum(b))[1..10]
vecsort(v, 3)[1..10] \\ shortcut: order by third component
u=select(v->Heron(v)==705600, v);
vecsort(u, (a,b)->Heron(a)-Heron(b))
vecsort(u, (a,b)->vecsum(a)-vecsum(b))
vecsort(u, 3) \\ shortcut: order by third component</syntaxhighlight>
{{out}}
<pre>%1 = [[1, 2, 3], [1, 3, 4], [1, 4, 5], [1, 5, 6], [1, 6, 7], [1, 7, 8], [1, 8, 9], [1, 9, 10], [1, 10, 11], [1, 11, 12]]
%2 = [[1, 2, 3], [1, 3, 4], [1, 4, 5], [2, 3, 5], [1, 5, 6], [3, 4, 5], [1, 6, 7], [2, 5, 7], [3, 4, 7], [1, 7, 8]]
%3 = [[1, 2, 3], [1, 3, 4], [1, 4, 5], [2, 3, 5], [3, 4, 5], [1, 5, 6], [1, 6, 7], [2, 5, 7], [3, 4, 7], [1, 7, 8]]
%4 = [[3, 148, 149], [7, 65, 68], [12, 35, 37], [17, 25, 28], [17, 28, 39], [20, 21, 29]]
%5 = [[17, 25, 28], [20, 21, 29], [12, 35, 37], [17, 28, 39], [7, 65, 68], [3, 148, 149]]
%6 = [[17, 25, 28], [20, 21, 29], [12, 35, 37], [17, 28, 39], [7, 65, 68], [3, 148, 149]]</pre>
 
=={{header|Pascal}}==
{{Trans|Lua}}
<syntaxhighlight lang="pascal">program heronianTriangles ( input, output );
type
(* record to hold details of a Heronian triangle *)
Heronian = record a, b, c, area, perimeter : integer end;
refHeronian = ^Heronian;
 
var
 
ht : array [ 1 .. 1000 ] of refHeronian;
htCount, htPos : integer;
a, b, c, i : integer;
lower, upper : integer;
k, h, t : refHeronian;
swapped : boolean;
 
(* returns the details of the Heronian Triangle with sides a, b, c or nil if it isn't one *)
function tryHt( a, b, c : integer ) : refHeronian;
var
s, areaSquared, area : real;
t : refHeronian;
begin
s := ( a + b + c ) / 2;
areaSquared := s * ( s - a ) * ( s - b ) * ( s - c );
t := nil;
if areaSquared > 0 then begin
(* a, b, c does form a triangle *)
area := sqrt( areaSquared );
if trunc( area ) = area then begin
(* the area is integral so the triangle is Heronian *)
new(t);
t^.a := a; t^.b := b; t^.c := c; t^.area := trunc( area ); t^.perimeter := a + b + c
end
end;
tryHt := t
end (* tryHt *) ;
 
(* returns the GCD of a and b *)
function gcd( a, b : integer ) : integer;
begin
if b = 0 then gcd := a else gcd := gcd( b, a mod b )
end (* gcd *) ;
 
(* prints the details of the Heronian triangle t *)
procedure htPrint( t : refHeronian ) ; begin writeln( t^.a:4, t^.b:5, t^.c:5, t^.area:5, t^.perimeter:10 ) end;
(* prints headings for the Heronian Triangle table *)
procedure htTitle ; begin writeln( ' a b c area perimeter' ); writeln( '---- ---- ---- ---- ---------' ) end;
 
begin
(* construct ht as a table of the Heronian Triangles with sides up to 200 *)
htCount := 0;
for c := 1 to 200 do begin
for b := 1 to c do begin
for a := 1 to b do begin
if gcd( gcd( a, b ), c ) = 1 then begin
t := tryHt( a, b, c );
if t <> nil then begin
htCount := htCount + 1;
ht[ htCount ] := t
end
end
end
end
end;
 
(* sort the table on ascending area, perimeter and max side length *)
(* note we constructed the triangles with c as the longest side *)
lower := 1;
upper := htCount;
repeat
upper := upper - 1;
swapped := false;
for i := lower to upper do begin
h := ht[ i ];
k := ht[ i + 1 ];
if ( k^.area < h^.area ) or ( ( k^.area = h^.area )
and ( ( k^.perimeter < h^.perimeter )
or ( ( k^.perimeter = h^.perimeter )
and ( k^.c < h^.c )
)
)
)
then begin
ht[ i ] := k;
ht[ i + 1 ] := h;
swapped := true
end
end;
until not swapped;
 
(* display the triangles *)
writeln( 'There are ', htCount:1, ' Heronian triangles with sides up to 200' );
htTitle;
for htPos := 1 to 10 do htPrint( ht[ htPos ] );
writeln( ' ...' );
writeln( 'Heronian triangles with area 210:' );
htTitle;
for htPos := 1 to htCount do begin
t := ht[ htPos ];
if t^.area = 210 then htPrint( t )
end
end.</syntaxhighlight>
{{out}}
<pre>
There are 517 Heronian triangles with sides up to 200
a b c area perimeter
---- ---- ---- ---- ---------
3 4 5 6 12
5 5 6 12 16
5 5 8 12 18
4 13 15 24 32
5 12 13 30 30
9 10 17 36 36
3 25 26 36 54
7 15 20 42 42
10 13 13 60 36
8 15 17 60 40
...
Heronian triangles with area 210:
a b c area perimeter
---- ---- ---- ---- ---------
17 25 28 210 70
20 21 29 210 70
12 35 37 210 84
17 28 39 210 84
7 65 68 210 140
3 148 149 210 300
</pre>
 
=={{header|Perl}}==
{{trans|Perl 6Raku}}
<langsyntaxhighlight lang="perl">use strict;
use warnings;
use List::Util qw(max);
Line 270 ⟶ 3,733:
}
 
&main();</langsyntaxhighlight>
{{out}}
<pre>Primitive Heronian triangles with sides up to 200: 517
Line 294 ⟶ 3,757:
210 300 3×148×149</pre>
 
=={{header|Perl 6Phix}}==
<!--<syntaxhighlight lang="phix">-->
{{works with|rakudo|2015-01-03}}
<span style="color: #008080;">function</span> <span style="color: #000000;">heroArea</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">)</span>
<lang perl6>sub hero($a, $b, $c) {
<span style="color: #004080;">atom</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">+</span><span style="color: #000000;">b</span><span style="color: #0000FF;">+</span><span style="color: #000000;">c</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span>
my $s = ($a + $b + $c) / 2;
<span style="color: #008080;">return</span> <span style="color: #7060A8;">sqrt</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">max</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">*(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">-</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)*(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">-</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)*(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">-</span><span style="color: #000000;">c</span><span style="color: #0000FF;">),</span><span style="color: #000000;">0</span><span style="color: #0000FF;">))</span>
my $a2 = $s * ($s - $a) * ($s - $b) * ($s - $c);
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
$a2.sqrt;
}
<span style="color: #008080;">function</span> <span style="color: #000000;">hero</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">h</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">remainder</span><span style="color: #0000FF;">(</span><span style="color: #000000;">h</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span> <span style="color: #008080;">and</span> <span style="color: #000000;">h</span><span style="color: #0000FF;">></span><span style="color: #000000;">0</span>
sub heronian-area($a, $b, $c) {
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
$_ when Int given hero($a, $b, $c).narrow;
}
<span style="color: #004080;">sequence</span> <span style="color: #000000;">list</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">tries</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">200</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">a</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">b</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">tries</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">gcd</span><span style="color: #0000FF;">({</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">c</span><span style="color: #0000FF;">})=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">hArea</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">heroArea</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">c</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">hero</span><span style="color: #0000FF;">(</span><span style="color: #000000;">hArea</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">list</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">list</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">hArea</span><span style="color: #0000FF;">,</span><span style="color: #000000;">a</span><span style="color: #0000FF;">+</span><span style="color: #000000;">b</span><span style="color: #0000FF;">+</span><span style="color: #000000;">c</span><span style="color: #0000FF;">,</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">c</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">list</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">list</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Primitive Heronian triangles with sides up to 200: %d (of %,d tested)\n\n"</span><span style="color: #0000FF;">,{</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">list</span><span style="color: #0000FF;">),</span><span style="color: #000000;">tries</span><span style="color: #0000FF;">})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"First 10 ordered by area/perimeter/sides:\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"area perimeter sides\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">10</span> <span style="color: #008080;">do</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%4d %3d %dx%dx%d\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">list</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\narea = 210:\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"area perimeter sides\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">list</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">list</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">210</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%4d %3d %dx%dx%d\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">list</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Primitive Heronian triangles with sides up to 200: 517 (of 1,353,400 tested)
 
First 10 ordered by area/perimeter/sides:
sub primitive-heronian-area($a, $b, $c) {
area perimeter sides
heronian-area $a, $b, $c
6 if 112 == [gcd] $a, $b, $c;5x4x3
12 16 6x5x5
}
12 18 8x5x5
24 32 15x13x4
30 30 13x12x5
36 36 17x10x9
36 54 26x25x3
42 42 20x15x7
60 36 13x13x10
60 40 17x15x8
 
area = 210:
sub show {
area perimeter sides
say " Area Perimeter Sides";
210 for @_ ->70 [$area, $perim, $c, $b, $a] {28x25x17
210 70 29x21x20
printf "%6d %6d %12s\n", $area, $perim, "$a×$b×$c";
210 84 37x35x12
210 84 39x28x17
210 140 68x65x7
210 300 149x148x3
</pre>
 
=={{header|PowerShell}}==
<syntaxhighlight lang="powershell">
function Get-Gcd($a, $b){
if($a -ge $b){
$dividend = $a
$divisor = $b
}
else{
$dividend = $b
$divisor = $a
}
$leftover = 1
while($leftover -ne 0){
$leftover = $dividend % $divisor
if($leftover -ne 0){
$dividend = $divisor
$divisor = $leftover
}
}
$divisor
}
function Is-Heron($heronArea){
$heronArea -gt 0 -and $heronArea % 1 -eq 0
}
function Get-HeronArea($a, $b, $c){
$s = ($a + $b + $c) / 2
[math]::Sqrt($s * ($s - $a) * ($s - $b) * ($s - $c))
}
$result = @()
foreach ($c in 1..200){
sub MAIN ($maxside = 200, $first = 10, $witharea = 210) {
my \hfor($b = sort1; $b -le $c; gather$b++){
for($a = 1 ..; $maxsidea ->le $cb; $a++){
forif((Get-Gcd 1$c ..(Get-Gcd $cb $a)) ->eq 1 -and (Is-Heron(Get-HeronArea $a $b $c))){
for$result += @(,@($a, $b, $c,($a -+ $b + 1 .. $bc), (Get->HeronArea $a {$b $c)))
if primitive-heronian-area($a,$b,$c) -> $area {
take [$area, $a+$b+$c, $c, $b, $a];
}
}
}
}
}
 
}
say "Primitive Heronian triangles with sides up to $maxside: ", +h;
$result = $result | sort-object @{Expression={$_[4]}}, @{Expression={$_[3]}}, @{Expression={$_[2]}}
 
"Primitive Heronian triangles with sides up to 200: $($result.length)`nFirst ten when ordered by increasing area, then perimeter,then maximum sides:`nSides`t`t`t`tPerimeter`tArea"
say "\nFirst $first:";
for($i = 0; $i -lt 10; $i++){
show h[^$first];
"$($result[$i][0])`t$($result[$i][1])`t$($result[$i][2])`t`t`t$($result[$i][3])`t`t`t$($result[$i][4])"
 
}
say "\nArea $witharea:";
"`nArea = 210`nSides`t`t`t`tPerimeter`tArea"
show h.grep: *[0] == $witharea;
foreach($i in $result){
}</lang>
if($i[4] -eq 210){
"$($i[0])`t$($i[1])`t$($i[2])`t`t`t$($i[3])`t`t`t$($i[4])"
}
}
</syntaxhighlight>
{{out}}
<syntaxhighlight lang="text">
<pre>Primitive Heronian triangles with sides up to 200: 517
Primitive Heronian triangles with sides up to 200: 517
 
First ten when ordered by increasing area, then perimeter,then maximum sides:
First 10:
Sides Perimeter Area
Area Perimeter Sides
3 4 5 12 6
6 12 3×4×5
5 5 6 16 12
12 16 5×5×6
5 5 8 18 12
12 18 5×5×8
4 13 15 32 24
24 32 4×13×15
5 12 13 30 30
30 30 5×12×13
9 10 17 36 36
36 36 9×10×17
3 25 26 54 36
36 54 3×25×26
7 15 20 42 42
42 42 7×15×20
10 13 13 36 60
60 36 10×13×13
8 15 17 40 60
60 40 8×15×17
 
Area = 210:
Sides Perimeter Area
Area Perimeter Sides
17 25 28 70 210
210 70 17×25×28
20 21 29 70 210
210 70 20×21×29
12 35 37 84 210
210 84 12×35×37
17 28 39 84 210
210 84 17×28×39
7 65 68 140 210
210 140 7×65×68
3 148 149 300 210
210 300 3×148×149</pre>
</syntaxhighlight>
 
=={{header|Python}}==
 
<lang python>from math import sqrt
<syntaxhighlight lang="python">from __future__ import division, print_function
from fractions import gcd
from itertoolsmath import productgcd, sqrt
 
 
def hero(a, b, c):
s = (a + b + c) / 2
a2 = s * (s - a) * (s - b) * (s - c)
return sqrt(a2) if a2 > 0 else 0
 
 
def is_heronian(a, b, c):
a = hero(a, b, c)
return a > 0 and a.is_integer()
 
 
def gcd3(x, y, z):
def gcd3(x, y, z):
return gcd(gcd(x, y), z)
 
 
if __name__ == '__main__':
maxsideMAXSIDE = 200
 
h = [(a, b, c) for a,b,c in product(range(1, maxside + 1), repeat=3)
N = 1 + MAXSIDE
if a <= b <= c and a + b > c and gcd3(a, b, c) == 1 and is_heronian(a, b, c)]
h = [(x, y, z)
h.sort(key = lambda x: (hero(*x), sum(x), x[::-1])) # By increasing area, perimeter, then sides
for x in range(1, N)
print('Primitive Heronian triangles with sides up to %i:' % maxside, len(h))
for y in range(x, N)
print('\nFirst ten when ordered by increasing area, then perimeter,then maximum sides:')
for z in range(y, N) if (x + y > z) and
print('\n'.join(' %14r perim: %3i area: %i'
1 == gcd3(x, y, z) and
is_heronian(x, y, z)]
 
# By increasing area, perimeter, then sides
h.sort(key=lambda x: (hero(*x), sum(x), x[::-1]))
 
print(
'Primitive Heronian triangles with sides up to %i:' % MAXSIDE, len(h)
)
print('\nFirst ten when ordered by increasing area, then perimeter,',
'then maximum sides:')
print('\n'.join(' %14r perim: %3i area: %i'
% (sides, sum(sides), hero(*sides)) for sides in h[:10]))
print('\nAll with area 210 subject to the previous ordering:')
print('\n'.join(' %14r perim: %3i area: %i'
% (sides, sum(sides), hero(*sides)) for sides in h
if hero(*sides) == 210))</lang>
</syntaxhighlight>
 
{{out}}
<pre>Primitive Heronian triangles with sides up to 200: 517
Line 421 ⟶ 3,972:
(3, 148, 149) perim: 300 area: 210</pre>
 
=={{header|RacketR}}==
 
Mostly adopted from Python implementation:
<lang>#lang racket
(require xml/xml data/order)
 
<syntaxhighlight lang="r">
;; Returns the area of triangle sides a, b, c
(definearea (A<- function(a, b, c) {
(define s = (/a (+ a b + c) 2))/ ; where s=\frac{a+b+c}{2}.
(sqrt (* s (- s a) (- s b) (- s c)))) ; Aa2 = \sqrt{s*(s-a)*(s-b)*(s-c)}
if (a2>0) sqrt(a2) else 0
}
 
is.heronian <- function(a, b, c) {
;; Returns same as A iff a, b, c and A are integers; #f otherwise
h = area(a, b, c)
(define (heronian?-area a b c)
h > 0 && 0==h%%1
(and (integer? a) (integer? b) (integer? c)
}
(let ((h (A a b c))) (and (integer? h) h))))
 
# borrowed from stackoverflow http://stackoverflow.com/questions/21502181/finding-the-gcd-without-looping-r
;; Returns same as heronian?-area, with the additional condition that (gcd a b c) = 1
gcd <- function(x,y) {
(define (primitive-heronian?-area a b c)
r <- x%%y;
ifelse(r, gcd(y, r), y)
}
 
gcd3 <- function(x, y, z) {
gcd(gcd(x, y), z)
}
 
maxside = 200
r <- NULL
for(c in 1:maxside){
for(b in 1:c){
for(a in 1:b){
if(1==gcd3(a, b, c) && is.heronian(a, b, c)) {
r <- rbind(r,c(a=a, b=b, c=c, perimeter=a+b+c, area=area(a,b,c)))
}
}
}
}
 
cat("There are ",nrow(r)," Heronian triangles up to a maximal side length of ",maxside,".\n", sep="")
cat("Showing the first ten ordered first by perimeter, then by area:\n")
print(head(r[order(x=r[,"perimeter"],y=r[,"area"]),],n=10))
</syntaxhighlight>
 
{{out}}
 
<syntaxhighlight lang="text">There are 517 Heronian triangles up to a maximal side length of 200.
Showing the first ten ordered first by perimeter, then by area:
a b c perimeter area
[1,] 3 4 5 12 6
[2,] 5 5 6 16 12
[3,] 5 5 8 18 12
[4,] 5 12 13 30 30
[5,] 4 13 15 32 24
[6,] 9 10 17 36 36
[7,] 10 13 13 36 60
[8,] 8 15 17 40 60
[9,] 7 15 20 42 42
[10,] 13 14 15 42 84</syntaxhighlight>
 
=={{header|Racket}}==
 
<syntaxhighlight lang="text">#lang at-exp racket
(require data/order scribble/html)
 
;; Returns the area of a triangle iff the sides have gcd 1, and it is an
;; integer; #f otherwise
(define (heronian?-area a b c)
(and (= 1 (gcd a b c))
(heronian?-arealet ([s (/ (+ a b c) 2)]) ; ** If s=\frac{a+b+c}{2}
(and (integer? s) ; (s must be an integer for the area to b an integer)
(let-values ([[q r] (integer-sqrt/remainder ; (faster than sqrt)
; ** Then the area is \sqrt{s(s-a)(s-b)(s-c)}
(* s (- s a) (- s b) (- s c)))])
(and (zero? r) q)))))) ; (return only integer areas)
 
(define (generate-heronian-triangles max-side)
(for*/list ([c (in-range 1 (add1 max-side))]
((a [b (in-range 1 (add1 max-side)c))] ; b<=c
(b [a (in-range 1 (add1 a(- c b)) (add1 b))] ; ensures a<=b and c<a+b
(c [area (in-range 1value (add1heronian?-area a b c)))]
#:when (< a (+ b c) #:when area)
;; datum-order can sort this for the tables (c is the max side length)
(h (in-value (primitive-heronian?-area a b c)))
(list area (+ a b c) c (list a b c))))
#:when h)
(define rv (vector h (+ a b c) (sort (list a b c) >))) ; datum-order can sort this for the tables
rv))
 
;; Order the triangles by first increasing area, then by increasing perimeter,
;; then by increasing maximum side lengths
(define (tri<?-sort t1 t2triangles)
(sort triangles (λ(t1 t2) (eq? '< (datum-order t1 t2)))))
 
(define (triangles->table triangles)
(define triangle->tds (match-lambda [`#(,h ,p ,s) `((td ,(~a s)) (td ,(~a p)) (td ,(~a h)))]))
(table
 
(tr (map th '("#" sides perimeter area))) "\n"
(define (triangles->table ts)
(for/list ([i (in-naturals 1)] [triangle (in-list triangles)])
`(table
(match-define (list area perimeter max-side sides) triangle)
(tr (th "#") (th "sides") (th "perimiter") (th "area")) "\n"
,@ (for/listtr ((td i) (intd (add-naturalsbetween 1))sides (t ts",")) `(tr (td ,(~a i)perimeter) ,@(triangle->tdstd tarea) "\n"))))
 
(define (sorted-triangles-table triangles)
(triangles->table (sort triangles tri<?)))
 
(module+ main
(define ts (generate-heronian-triangles 200))
(define divoutput-outxml
@div{@p{number of primitive triangles found with perimeter @entity{le} 200 = @(length ts)}
`(div
@; Show the first ten ordered triangles in a table of sides, perimeter,
(p "number of primitive triangles found with perimeter "le" 200 = " ,(~a (length ts))) "\n"
;; Show the first ten ordered triangles in a table of sides, perimeter,@; and area.
, @(sorted-triangles->table (take (tri-sort ts tri<?) 10)) "\n"
; @; Show a similar ordered table for those triangles with area = 210
, @(sorted-triangles->table (tri-sort (filter (match-lambdaλ(t) [(vectoreq? 210 _(car _) #t] [_ #f]) ts)) tri<?)ts)))
}))</syntaxhighlight>
(displayln (xexpr->string div-out)))</lang>
 
This program generates HTML, so the output is inline with the page, not in a <code>&lt;pre></code> block.
Line 484 ⟶ 4,084:
 
<div><p>number of primitive triangles found with perimeter &le; 200 = 517</p>
<table><tr><th>#</th><th>sides</th><th>perimiterperimeter</th><th>area</th></tr>
<tr><td>1</td><td>(5 4 3),4,5</td><td>12</td><td>6</td>
</tr><tr><td>2</td><td>(6 5 ,5),6</td><td>16</td><td>12</td>
</tr><tr><td>3</td><td>(8 5 ,5),8</td><td>18</td><td>12</td>
</tr><tr><td>4</td><td>(15 13 4),13,15</td><td>32</td><td>24</td>
</tr><tr><td>5</td><td>(13 12 5),12,13</td><td>30</td><td>30</td>
</tr><tr><td>6</td><td>(17 10 9),10,17</td><td>36</td><td>36</td>
</tr><tr><td>7</td><td>(26 25 3),25,26</td><td>54</td><td>36</td>
</tr><tr><td>8</td><td>(20 15 7),15,20</td><td>42</td><td>42</td>
</tr><tr><td>9</td><td>(10,13 ,13 10)</td><td>36</td><td>60</td>
</tr><tr><td>10</td><td>(17 15 8),15,17</td><td>40</td><td>60</td>
</tr></table>
<table><tr><th>#</th><th>sides</th><th>perimiterperimeter</th><th>area</th></tr>
<tr><td>1</td><td>(28 25 17),25,28</td><td>70</td><td>210</td>
</tr><tr><td>2</td><td>(29 21 20),21,29</td><td>70</td><td>210</td>
</tr><tr><td>3</td><td>(37 35 12),35,37</td><td>84</td><td>210</td>
</tr><tr><td>4</td><td>(39 28 17),28,39</td><td>84</td><td>210</td>
</tr><tr><td>5</td><td>(68 65 7),65,68</td><td>140</td><td>210</td>
</tr><tr><td>6</td><td>(149 148 3),148,149</td><td>300</td><td>210</td>
</tr></table></div>
 
<br><br>
 
=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2018.09}}
<syntaxhighlight lang="raku" line>sub hero($a, $b, $c) {
my $s = ($a + $b + $c) / 2;
($s * ($s - $a) * ($s - $b) * ($s - $c)).sqrt;
}
sub heronian-area($a, $b, $c) {
$_ when Int given hero($a, $b, $c).narrow;
}
 
sub primitive-heronian-area($a, $b, $c) {
heronian-area $a, $b, $c
if 1 == [gcd] $a, $b, $c;
}
 
sub show(@measures) {
say " Area Perimeter Sides";
for @measures -> [$area, $perim, $c, $b, $a] {
printf "%6d %6d %12s\n", $area, $perim, "$a×$b×$c";
}
}
sub MAIN ($maxside = 200, $first = 10, $witharea = 210) {
my @hh[1000];
my atomicint $i;
(1 .. $maxside).race(:12batch).map: -> $c {
for 1 .. $c -> $b {
for $c - $b + 1 .. $b -> $a {
if primitive-heronian-area($a,$b,$c) -> $area {
@hh[$i⚛++] = [$area, $a+$b+$c, $c, $b, $a];
}
}
}
}
 
my @h = (@hh.grep: so *).sort;
say "Primitive Heronian triangles with sides up to $maxside: ", +@h;
 
say "\nFirst $first:";
show @h[^$first];
 
say "\nArea $witharea:";
show @h.grep: *[0] == $witharea;
}</syntaxhighlight>
{{out}}
<pre>Primitive Heronian triangles with sides up to 200: 517
 
First 10:
Area Perimeter Sides
6 12 3×4×5
12 16 5×5×6
12 18 5×5×8
24 32 4×13×15
30 30 5×12×13
36 36 9×10×17
36 54 3×25×26
42 42 7×15×20
60 36 10×13×13
60 40 8×15×17
 
Area 210:
Area Perimeter Sides
210 70 17×25×28
210 70 20×21×29
210 84 12×35×37
210 84 17×28×39
210 140 7×65×68
210 300 3×148×149</pre>
 
=={{header|REXX}}==
=== using iSQRT ===
Programming note: &nbsp; the &nbsp; '''hGCD''' &nbsp; subroutine is a specialized version of a GCD routine in that it doesn't check for non-positive integers.
This REXX version makes use of these facts:
:::* &nbsp; if &nbsp; '''A''' &nbsp; is even, &nbsp; then &nbsp; '''B''' &nbsp; and &nbsp; '''C''' &nbsp; must be odd.
:::* &nbsp; if &nbsp; '''B''' &nbsp; is even, &nbsp; then &nbsp; '''C''' &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; must be odd.
:::* &nbsp; if &nbsp; '''A''' &nbsp; and &nbsp; '''B''' &nbsp; are odd, &nbsp; then &nbsp; '''C''' &nbsp; must be even.
:::* &nbsp; with the 1<sup>st</sup> three truisms, then:
::::::* &nbsp; '''C''' &nbsp; can be incremented by &nbsp; <big>'''2'''</big>.
::::::* &nbsp; the area is always even.
 
Also, a fair amount of code was added to optimize the speed &nbsp; (at the expense of program simplicity).
Programming notes:
<lang rexx>/*REXX pgm generates primitive Heronian triangles by side length & area.*/
parse arg N first area . /*get optional N (sides). */
The &nbsp; '''hGCD''' &nbsp; subroutine is a specialized version of a '''GCD''' routine in that:
if N=='' then N=200 /*maybe use the default. */
:::* &nbsp; it doesn't check for non-positive integers
sides=N /* 05 Jan 2015 added by WP */
:::* &nbsp; it expects exactly three arguments
if first=='' then first= 10 /* " " " " */
if area=='' then area=210 /* " " " " */
numeric digits max(9, 1+length(sides**4)) /*ensure enough dec digits. */
Also, a fair amount of code was added to optimize the speed &nbsp; (at the expense of program simplicity).
@pmt=' primitive Heronian triangles' /*define handy-dandy literal*/
call heronian sides /*invoke sub with max SIDES.*/
By thoughtful ordering of the elimination checks, and also the use of an &nbsp; ''integer version'' &nbsp;
say # @pmt 'found with sides up to ' sides " (inclusive)."
of a &nbsp; '''SQRT'''
call show , 'listing of the first ' first @pmt":"
<br>subroutine, &nbsp; the execution time was greatly reduced &nbsp; (by a factor of eight).
call show area, 'listing of the'@pmt "with area=" area
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────HERONIAN subroutine─────────────────*/
Note that the &nbsp; '''hIsqrt''' &nbsp; ('''h'''eronian '''I'''nteger '''sq'''are '''r'''oo'''t''') &nbsp;
heronian: @.=.; #=0; minP=9e9; maxP=0; minA=9e9; maxA=0; Ln=length(N)
subroutine doesn't use floating point.
do a=3 to N
<br>['''hIsqrt''' &nbsp; is a modified/simplified version of an &nbsp; '''Isqrt''' &nbsp; function.]
do b=a to N; ab=a+b
do c=b to N /* [↓] if GCD ¬=1, it's not a */
This REXX version doesn't need to explicitly sort the triangles as they are listed in the proper order.
if hGCD(a,b,c)\==1 then iterate /* primitive Heronian triangle.*/
<syntaxhighlight lang="rexx">/*REXX program generates & displays primitive Heronian triangles by side length and area*/
p=ab+c ; s=p*.5 /*calculate the perimeter and S.*/
parse arg N first area . _=(s-a)*(s-b)*(s-c); if _<=0 then iterate /*¬positiveobtain optional arguments from the CL*/
if arN=sqrt(s*_)='' | ;N=="," ifthen pos(.,ar)\= N=0 200 then iterate /*area¬intNot specified? Then use the default.*/
if first=='' | first=="," then first= 10 /* " " if ar==0 " " " then iterate " /*area=zero*/
if area=='' | #area=#+1="," then area= 210 /* " " " /*a primitive Heronian" " " triangle. */
numeric digits 99 /*ensure 'nuff dec. digs to calc. N**5.*/
minP=min( p,minP); maxP=max( p,maxP); Lp=length(maxP)
numeric digits max(9, 1 + length(N**5) ) /*minimize decimal digits for REXX pgm.*/
minA=min(ar,minA); maxA=max(ar,maxA); La=length(maxA); @.ar=
call Heron; HT= 'Heronian triangles' /*invoke the Heron subroutine. */
if @.ar.p.0==. then @.ar.p.0=0; _=@.ar.p.0+1 /*bump triangle ctr*/
say # @.ar.p.0=_; @.ar.p._=a b c ' primitive' HT "found with sides up to " N ' /*unique triangle(inclusive). */'
call show end, 'Listing of /*c*/the first ' first ' primitive' /* [↑] keep each unique P items.*/HT":"
call show area, 'Listing of the (above) found primitive' HT "with an area of " area
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
Heron: @.= 0; minP= 9e9; maxP= 0; maxA= 0; minA= 9e9; Ln= length(N) /* __*/
#= 0; #.= 0; #.2= 1; #.3= 1; #.7= 1; #.8= 1 /*digits ¬good √ */
do a=3 to N /*start at a minimum side length of 3. */
Aeven= a//2==0 /*if A is even, B and C must be odd.*/
do b=a+Aeven to N by 1+Aeven; ab= a + b /*AB: a shortcut for the sum of A & B. */
if b//2==0 then bump= 1 /*Is B even? Then C is odd. */
else if Aeven then bump= 0 /*Is A even? " " " " */
else bump= 1 /*A and B are both odd, biz as usual.*/
do c=b+bump to N by 2; s= (ab + c) % 2 /*calculate triangle's perimeter: S. */
_= s*(s-a)*(s-b)*(s-c); if _<=0 then iterate /*is _ not positive? Skip it*/
parse var _ '' -1 z ; if #.z then iterate /*Last digit not square? Skip it*/
ar= hIsqrt(_); if ar*ar\==_ then iterate /*Is area not an integer? Skip it*/
if hGCD(a, b, c) \== 1 then iterate /*GCD of sides not equal 1? Skip it*/
#= # + 1; p= ab + c /*primitive Heronian triangle. */
minP= min( p, minP); maxP= max( p, maxP); Lp= length(maxP)
minA= min(ar, minA); maxA= max(ar, maxA); La= length(maxA)
_=@.ar.p.0 + 1 /*bump Heronian triangle counter. */
@.ar.p.0= _; @.ar.p._= right(a, Ln) right(b, Ln) right(c, Ln) /*unique.*/
end /*c*/ /* [↑] keep each unique perimeter#*/
end /*b*/
end /*a*/; return # /*return # of Heronian triangles. */
end /*a*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
 
return # hGCD: x=a; do j=2 for 2; y= arg(j); do until y==0; parse value x/*return/y #y ofwith Heroniany triangles.*/x
end /*until*/
/*──────────────────────────────────HGCD subroutine─────────────────────*/
end /*j*/; return x
hGCD: procedure; parse arg x
/*──────────────────────────────────────────────────────────────────────────────────────*/
do j=2 for 2; y=arg(j); do until _==0; _=x//y; x=y; y=_; end; end
hIsqrt: procedure; parse arg x; q= 1; r= 0; do while q<=x; q= q * 4
return x
end /*while q<=x*/
/*──────────────────────────────────SHOW subroutine─────────────────────*/
show: m=0; say do while q>1; sayq=q%4; parse_= arg ae,txtx-r-q; sayr= txtr%2; if ae\_>==''0 then first=9e9parse value _ r+q with x r
end /*while q>1*/; return r
say
/*──────────────────────────────────────────────────────────────────────────────────────*/
do i=minA to maxA; if @.i==. then iterate /*skip nulls.*/
show: m=0; say; say; parse arg ae; say arg(2); if ae\=='' then first= 9e9
if ae\=='' & i\==ae then iterate /*Area specified? Then check*/
say; do j$=minPleft('',9); to maxP$a= $"area:"; until m>$p=first /*only$'perimeter:'; list $s= FIRST$"sides:" entries./*literals*/
do i=minA to maxA; if @.ae\=='' & i.j.0\==.ae then iterate /*Not= definedarea? Then skip it.*/
do k=1 do for @.i.j.0 =minP to maxP until m>=first /*looponly display the through eachFIRST elemententries.*/
m do k=m+1; parse varfor @.i.j.k0; m= m + 1 a b c /*parsedisplay foreach nice formattingperimeter entry. */
say right(m, 9) ' $a area:' right(i, La) " $p perimeter:" right(j, Lp) $s @.i.j.k
right(j,Lp)end ' sides:' right(a,Ln) right(b,Ln) right(c,Ln)/*k*/
end /*kj*/ /* [↑] use the known perimeters. */
end /*i*/; return /* [↑] show any found triangles. */</syntaxhighlight>
end /*j*/
{{out|output|text=&nbsp; when using the default inputs:}}
end /*i*/
return
/*──────────────────────────────────SQRT subroutine─────────────────────────*/
sqrt: procedure; parse arg x;if x=0 then return 0;d=digits();numeric digits 11
numeric form; parse value format(x,2,1,,0) 'E0' with g 'E' _ .; g=g*.5'E'_%2
p=d+d%4+2; m.=11; do j=0 while p>9; m.j=p; p=p%2+1; end; do k=j+5 to 0 by -1
if m.k>11 then numeric digits m.k;g=.5*(g+x/g);end;numeric digits d;return g/1</lang>
'''output'''
<pre>
517 primitive Heronian triangles found with sides up to 200 (inclusive).
 
 
listingListing of the first 10 primitive Heronian triangles:
 
1 area: 6 perimeter: 12 sides: 3 4 5
2 area: 12 perimeter: 16 sides: 5 5 6
3 area: 12 perimeter: 18 sides: 5 5 8
4 area: 24 perimeter: 32 sides: 4 13 15
5 area: 30 perimeter: 30 sides: 5 12 13
6 area: 36 perimeter: 36 sides: 9 10 17
7 area: 36 perimeter: 54 sides: 3 25 26
8 area: 42 perimeter: 42 sides: 7 15 20
9 area: 60 perimeter: 36 sides: 10 13 13
10 area: 60 perimeter: 40 sides: 8 15 17
 
 
listingListing of the (above) found primitive Heronian triangles with an area= of 210
 
1 area: 210 perimeter: 70 sides: 17 25 28
2 area: 210 perimeter: 70 sides: 20 21 29
3 area: 210 perimeter: 84 sides: 12 35 37
4 area: 210 perimeter: 84 sides: 17 28 39
5 area: 210 perimeter: 140 sides: 7 65 68
6 area: 210 perimeter: 300 sides: 3 148 149
</pre>
 
===using SQRT table===
=={{header|Ruby}}==
This REXX version makes use of a precalculated table of squares of some
<lang ruby>Triangle = Struct.new(:a, :b, :c) do
integers &nbsp; (which are used to find square roots very quickly).
include Comparable
 
It is about eight times faster than the 1<sup>st</sup> REXX version.
def self.valid?(a,b,c) # class method
<syntaxhighlight lang="rexx">/*REXX program generates & displays primitive Heronian triangles by side length and area*/
short, middle, long = [a, b, c].sort
parse arg N first area . /*obtain optional arguments from the CL*/
short + middle > long
if N=='' | N=="," then N= 200 /*Not specified? Then use the default.*/
end
if first=='' | first=="," then first= 10 /* " " " " " " */
if area=='' | area=="," then area= 210 /* " " " " " " */
numeric digits 99; numeric digits max(9, 1+length(N**5)) /*ensure 'nuff decimal digits.*/
call Heron; HT= 'Heronian triangles' /*invoke the Heron subroutine. */
say # ' primitive' HT "found with sides up to " N ' (inclusive).'
call show , 'Listing of the first ' first ' primitive' HT":"
call show area, 'Listing of the (above) found primitive' HT "with an area of " area
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
Heron: @.= 0; #= 0; !.= .; minP= 9e9; maxA= 0; maxP= 0; minA= 9e9; Ln= length(N)
do i=1 for N**2%2; _= i*i; !._= i /* __ */
end /*i*/ /* [↑] pre─calculate some fast √ */
do a=3 to N /*start at a minimum side length of 3. */
Aeven= a//2==0 /*if A is even, B and C must be odd.*/
do b=a+Aeven to N by 1+Aeven; ab= a + b /*AB: a shortcut for the sum of A & B. */
if b//2==0 then bump= 1 /*Is B even? Then C is odd. */
else if Aeven then bump= 0 /*Is A even? " " " " */
else bump= 1 /*A and B are both odd, biz as usual.*/
do c=b+bump to N by 2; s= (ab + c) % 2 /*calculate triangle's perimeter: S. */
_= s*(s-a)*(s-b)*(s-c); if !._==. then iterate /*Is _ not a square? Skip.*/
if hGCD(a,b,c) \== 1 then iterate /*GCD of sides not 1? Skip.*/
#= # + 1; p= ab + c; ar= !._ /*primitive Heronian triangle*/
minP= min( p, minP); maxP= max( p, maxP); Lp= length(maxP)
minA= min(ar, minA); maxA= max(ar, maxA); La= length(maxA); @.ar=
_= @.ar.p.0 + 1 /*bump the triangle counter. */
@.ar.p.0= _; @.ar.p._= right(a, Ln) right(b, Ln) right(c, Ln) /*unique*/
end /*c*/ /* [↑] keep each unique perimeter #. */
end /*b*/
end /*a*/; return # /*return number of Heronian triangles. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
hGCD: x=a; do j=2 for 2; y= arg(j); do until y==0; parse value x//y y with y x
end /*until*/
end /*j*/; return x
/*──────────────────────────────────────────────────────────────────────────────────────*/
show: m=0; say; say; parse arg ae; say arg(2); if ae\=='' then first= 9e9
say; $=left('',9); $a= $"area:"; $p= $'perimeter:'; $s= $"sides:" /*literals*/
do i=minA to maxA; if ae\=='' & i\==ae then iterate /*= area? */
do j=minP to maxP until m>=first /*only display the FIRST entries.*/
do k=1 for @.i.j.0; m= m + 1 /*display each perimeter entry. */
say right(m, 9) $a right(i, La) $p right(j, Lp) $s @.i.j.k
end /*k*/
end /*j*/ /* [↑] use the known perimeters. */
end /*i*/; return /* [↑] show any found triangles. */</syntaxhighlight>
{{out|output|text=&nbsp; is identical to the 1<sup>st</sup> REXX version.}} <br><br>
 
=={{header|Ring}}==
def sides
<syntaxhighlight lang="ring">
@sides ||= [a, b, c].sort
# Project : Heronian triangles
end
 
see "Heronian triangles with sides up to 200" + nl
def perimeter
see "Sides Perimeter Area" + nl
@perimeter ||= a + b + c
for n = 1 to 200
end
for m = n to 200
for p = m to 200
s = (n + m + p) / 2
w = sqrt(s * (s - n) * (s - m) * (s - p))
bool = (gcd(n, m) = 1 or gcd(n, m) = n) and (gcd(n, p) = 1 or gcd(n, p) = n) and (gcd(m, p) = 1 or gcd(m, p) = m)
if w = floor(w) and w > 0 and bool
see "{" + n + ", " + m + ", " + p + "}" + " " + s*2 + " " + w + nl
ok
next
next
next
see nl
 
see "Heronian triangles with area 210:" + nl
def semiperimeter
see "Sides Perimeter Area" + nl
@semiperimeter ||= perimeter/2.0
for n = 1 to 150
end
for m = n to 150
for p = m to 150
s = (n + m + p) / 2
w = sqrt(s * (s - n) * (s - m) * (s - p))
bool = (gcd(n, m) = 1 or gcd(n, m) = n) and (gcd(n, p) = 1 or gcd(n, p) = n) and (gcd(m, p) = 1 or gcd(m, p) = m)
if w = 210 and bool
see "{" + n + ", " + m + ", " + p + "}" + " " + s*2 + " " + w + nl
ok
next
next
next
 
func gcd(gcd, b)
def area
s = semiperimeter while b
@area ||= Math.sqrt(s*(s - a)*(s - b)*(s - c)) = gcd
gcd = b
end
b = c % b
end
return gcd
</syntaxhighlight>
Output:
<pre>
Heronian triangles with sides up to 200
Sides Perimeter Area
{3, 4, 5} 12 6
{3, 25, 26} 54 36
{4, 13, 15} 32 24
{5, 5, 6} 16 12
{5, 5, 8} 18 12
{5, 12, 13} 30 30
{7, 15, 20 } 42 42
{8, 15, 17} 40 60
{9, 10, 17} 36 36
{10, 13, 13} 36 60
{13, 13, 24} 50 60
 
Heronian triangles with area 210:
Sides Perimeter Area
{3, 148, 149} 300 210
{7, 65, 68} 140 210
{12, 35, 37} 84 210
{17, 25, 28} 70 210
{17, 28, 39} 84 210
{20, 21, 29} 70 210
</pre>
 
=={{header|RPL}}==
We use here the <code>→V3</code> and<code>SORT</code> instructions, available for HP-48G or newer models only. <code>GCD </code> is not a built-in instruction, but it is a question of a few words:
≪ WHILE DUP REPEAT SWAP OVER MOD END DROP ABS ≫ ''''GCD'''' STO
{{trans|FreeBASIC}}
{{works with|Halcyon Calc|4.2.8}}
{| class="wikitable"
! RPL code
! Comment
|-
|
3 DUPN + + 2 / → a b c s
≪ s DUP a - * s b - * s c - *
≫ ≫ ‘'''SURF2'''’ STO
IF '''SURF2''' DUP 0 > THEN √ FP NOT ELSE DROP 0 END
≫ ‘'''HERO?'''’ STO
≪ → n
≪ { } 1 n FOR x
x n FOR y
y x 2 MOD + x y + 1 - n MIN FOR z
IF x y z '''GCD GCD''' THEN
IF x y z '''HERO?''' THEN x y z →V3 +
END END
2 STEP NEXT NEXT
≫ ≫ ‘'''TASK2'''’ RCL
|
'''SURF2''' ''( a b c → A² ) ''
s = (a+b+c)/2
A² = s(s-a)(s-b)(s-c)
return A²
'''HERO?''' ''( a b c → boolean ) ''
return true if A > 0 and √A is an integer
'''TASK2''' ''( n → { [Heronians] ) ''
for x = 1 to n
for y = x to n
for z = y+u to min(x+y-1,n) // u ensures x+y+z is even
if gcd(x,y,z) == 1
if x y z is Heronian then append to list
z += 2 to keep x+y+z even
|}
The rest of the code, which is devoted to printing the requested tables, is boring and the result is awful: native RPL works on machines with a 22-character screen.
{{in}}
<pre>
≪ → a b c
≪ c →STR WHILE DUP SIZE 4 < REPEAT " " SWAP + END
a b c + + →STR SWAP + WHILE DUP SIZE 8 < REPEAT " " SWAP + END
a b c SURF √ →STR SWAP + WHILE DUP SIZE 12 < REPEAT " " SWAP + END
" (" + a →STR + " " + b →STR + " " + c →STR + ")" +
≫ ≫ 'PRTRI' STO
200 TASK2 'H' STO
≪ { } 1 H SIZE FOR j H j GET ARRY→ DROP PRTRI + NEXT SORT 'H2' STO ≫ EVAL
"Area P. LS (triangle)"
1 10 H2 SUB
≪ { } 1 H2 SIZE FOR j H2 j GET IF DUP 1 4 SUB " 210" == THEN + END NEXT ≫ EVAL
</pre>
{{out}}
<pre style="height:40ex;overflow:scroll;">
4: 517
3: "Area P. LS (triangle)"
2: { " 6 12 5 (3 4 5)"
" 12 16 6 (5 5 6)"
" 12 18 8 (5 5 8)"
" 24 32 15 (4 13 15)"
" 30 30 13 (5 12 13)"
" 36 36 17 (9 10 17)"
" 36 54 26 (3 25 26)"
" 42 42 20 (7 15 20)"
" 60 36 13 (10 13 13)"
" 60 40 17 (8 15 17)" }
1: { " 210 70 28 (17 25 28)"
" 210 70 29 (20 21 29)"
" 210 84 37 (12 35 37)"
" 210 84 39 (17 28 39)"
" 210 140 68 (7 65 68)"
" 210 300 149 (3 148 149)" }
</pre>
 
=={{header|Ruby}}==
<syntaxhighlight lang="ruby">class Triangle
def self.valid?(a,b,c) # class method
short, middle, long = [a, b, c].sort
short + middle > long
end
attr_reader :sides, :perimeter, :area
def initialize(a,b,c)
@sides = [a, b, c].sort
@perimeter = a + b + c
s = @perimeter / 2.0
@area = Math.sqrt(s * (s - a) * (s - b) * (s - c))
end
def heronian?
area == area.to_i
end
 
def <=>(other)
[area, perimeter, sides] <=> [other.area, other.perimeter, other.sides]
end
 
def to_s
"#{%-11s%6d%8.1f" % [sides.join("'x"').ljust(10)}\t#{, perimeter}\t#{, area}"]
end
end
Line 648 ⟶ 4,540:
 
puts "Primitive heronian triangles with sides upto #{max}: #{sorted.size}"
puts "\nsides \tperim perim.\tarea area"
puts sorted.first(10).each{|tr| puts tr }map(&:to_s)
puts "\nTriangles with an area of: #{area}"
sorted.selecteach{|tr| puts tr if tr.area == area}.each{|tr| puts tr }</syntaxhighlight>
</lang>
{{out}}
<pre>
Primitive heronian triangles with sides upto 200: 517
 
sides perim. area
3x4x5 12 6.0
5x5x6 16 12.0
5x5x8 18 12.0
4x13x15 32 24.0
5x12x13 30 30.0
9x10x17 36 36.0
3x25x26 54 36.0
7x15x20 42 42.0
10x13x13 36 60.0
8x15x17 40 60.0
 
Triangles with an area of: 210
17x25x28 70 210.0
20x21x29 70 210.0
12x35x37 84 210.0
17x28x39 84 210.0
7x65x68 140 210.0
3x148x149 300 210.0
</pre>
 
=={{header|Rust}}==
<syntaxhighlight lang="rust">
use num_integer::Integer;
use std::{f64, usize};
 
const MAXSIZE: usize = 200;
 
#[derive(Debug)]
struct HerionanTriangle {
a: usize,
b: usize,
c: usize,
area: usize,
perimeter: usize,
}
 
fn get_area(a: &usize, b: &usize, c: &usize) -> f64 {
let s = (a + b + c) as f64 / 2.;
(s * (s - *a as f64) * (s - *b as f64) * (s - *c as f64)).sqrt()
}
 
fn is_heronian(a: &usize, b: &usize, c: &usize) -> bool {
let area = get_area(a, b, c);
// Heronian if the area is an integer number
area != 0. && area.fract() == 0.
}
 
fn main() {
let mut heronians: Vec<HerionanTriangle> = vec![];
 
(1..=MAXSIZE).into_iter().for_each(|a| {
(a..=MAXSIZE).into_iter().for_each(|b| {
(b..=MAXSIZE).into_iter().for_each(|c| {
if a + b > c && a.gcd(&b).gcd(&c) == 1 && is_heronian(&a, &b, &c) {
heronians.push(HerionanTriangle {
a,
b,
c,
perimeter: a + b + c,
area: get_area(&a, &b, &c) as usize,
})
}
})
})
});
 
// sort by area then by perimeter, then by maximum side
heronians.sort_unstable_by(|x, y| {
x.area
.cmp(&y.area)
.then(x.perimeter.cmp(&y.perimeter))
.then((x.a.max(x.b).max(x.c)).cmp(&y.a.max(y.b).max(y.c)))
});
 
println!(
"Primitive Heronian triangles with sides up to 200: {}",
heronians.len()
);
 
println!("\nFirst ten when ordered by increasing area, then perimeter,then maximum sides:");
heronians.iter().take(10).for_each(|h| println!("{:?}", h));
 
println!("\nAll with area 210 subject to the previous ordering:");
heronians
.iter()
.filter(|h| h.area == 210)
.for_each(|h| println!("{:?}", h));
}
 
</syntaxhighlight>
{{out}}
<pre>
Primitive Heronian triangles with sides up to 200: 517
 
First ten when ordered by increasing area, then perimeter,then maximum sides:
HerionanTriangle { a: 3, b: 4, c: 5, area: 6, perimeter: 12 }
HerionanTriangle { a: 5, b: 5, c: 6, area: 12, perimeter: 16 }
HerionanTriangle { a: 5, b: 5, c: 8, area: 12, perimeter: 18 }
HerionanTriangle { a: 4, b: 13, c: 15, area: 24, perimeter: 32 }
HerionanTriangle { a: 5, b: 12, c: 13, area: 30, perimeter: 30 }
HerionanTriangle { a: 9, b: 10, c: 17, area: 36, perimeter: 36 }
HerionanTriangle { a: 3, b: 25, c: 26, area: 36, perimeter: 54 }
HerionanTriangle { a: 7, b: 15, c: 20, area: 42, perimeter: 42 }
HerionanTriangle { a: 10, b: 13, c: 13, area: 60, perimeter: 36 }
HerionanTriangle { a: 8, b: 15, c: 17, area: 60, perimeter: 40 }
 
All with area 210 subject to the previous ordering:
HerionanTriangle { a: 17, b: 25, c: 28, area: 210, perimeter: 70 }
HerionanTriangle { a: 20, b: 21, c: 29, area: 210, perimeter: 70 }
HerionanTriangle { a: 12, b: 35, c: 37, area: 210, perimeter: 84 }
HerionanTriangle { a: 17, b: 28, c: 39, area: 210, perimeter: 84 }
HerionanTriangle { a: 7, b: 65, c: 68, area: 210, perimeter: 140 }
HerionanTriangle { a: 3, b: 148, c: 149, area: 210, perimeter: 300 }
</pre>
 
=={{header|Scala}}==
<syntaxhighlight lang="scala">object Heron extends scala.collection.mutable.MutableList[Seq[Int]] with App {
private final val n = 200
for (c <- 1 to n; b <- 1 to c; a <- 1 to b if gcd(gcd(a, b), c) == 1) {
val p = a + b + c
val s = p / 2D
val area = Math.sqrt(s * (s - a) * (s - b) * (s - c))
if (isHeron(area))
appendElem(Seq(a, b, c, p, area.toInt))
}
print(s"Number of primitive Heronian triangles with sides up to $n: " + length)
 
private final val list = sortBy(i => (i(4), i(3)))
print("\n\nFirst ten when ordered by increasing area, then perimeter:" + header)
list slice (0, 10) map format foreach print
print("\n\nArea = 210" + header)
list filter { _(4) == 210 } map format foreach print
 
private def gcd(a: Int, b: Int) = {
var leftover = 1
var (dividend, divisor) = if (a > b) (a, b) else (b, a)
while (leftover != 0) {
leftover = dividend % divisor
if (leftover > 0) {
dividend = divisor
divisor = leftover
}
}
divisor
}
 
private def isHeron(h: Double) = h % 1 == 0 && h > 0
 
private final val header = "\nSides Perimeter Area"
private def format: Seq[Int] => String = "\n%3d x %3d x %3d %5d %10d".format
}</syntaxhighlight>
 
=={{header|Sidef}}==
{{trans|Ruby}}
<syntaxhighlight lang="ruby">class Triangle(a, b, c) {
 
has (sides, perimeter, area)
 
method init {
sides = [a, b, c].sort
perimeter = [a, b, c].sum
var s = (perimeter / 2)
area = sqrt(s * (s - a) * (s - b) * (s - c))
}
 
method is_valid(a,b,c) {
var (short, middle, long) = [a, b, c].sort...;
(short + middle) > long
}
 
method is_heronian {
area == area.to_i
}
 
method <=>(other) {
[area, perimeter, sides] <=> [other.area, other.perimeter, other.sides]
}
 
method to_s {
"%-11s%6d%8.1f" % (sides.join('x'), perimeter, area)
}
}
 
var (max, area) = (200, 210)
var prim_triangles = []
 
for a in (1..max) {
for b in (a..max) {
for c in (b..max) {
next if (Math.gcd(a, b, c) > 1)
prim_triangles << Triangle(a, b, c) if Triangle.is_valid(a, b, c)
}
}
}
 
var sorted = prim_triangles.grep{.is_heronian}.sort
 
say "Primitive heronian triangles with sides upto #{max}: #{sorted.size}"
say "\nsides perim. area"
say sorted.first(10).join("\n")
say "\nTriangles with an area of: #{area}"
sorted.each{|tr| say tr if (tr.area == area)}</syntaxhighlight>
{{out}}
<pre>
Primitive heronian triangles with sides upto 200: 517
 
sides perim. area
3x4x5 12 6.0
5x5x6 16 12.0
5x5x8 18 12.0
4x13x15 32 24.0
5x12x13 30 30.0
9x10x17 36 36.0
3x25x26 54 36.0
7x15x20 42 42.0
10x13x13 36 60.0
8x15x17 40 60.0
 
Triangles with an area of: 210
17x25x28 70 210.0
20x21x29 70 210.0
12x35x37 84 210.0
17x28x39 84 210.0
7x65x68 140 210.0
3x148x149 300 210.0
</pre>
 
=={{header|Smalltalk}}==
Works with Squeak 5.x
<syntaxhighlight lang="smalltalk">perimeter := [:triangle | triangle reduce: #+].
 
squaredArea := [:triangle |
| s |
s := (perimeter value: triangle) / 2.
triangle inject: s into: [:a2 :edge | s - edge * a2]].
 
isPrimitive := [:triangle | (triangle reduce: #gcd:) = 1].
 
isHeronian := [:triangle | (squaredArea value: triangle) sqrt isInteger].
 
heroGenerator := Generator on: [:generator |
1 to: 200 do: [:a |
a to: 200 do: [:b |
b to: (a+b-1 min: 200) do: [:c |
| triangle |
triangle := {a. b. c.}.
((isPrimitive value: triangle) and: [isHeronian value: triangle])
ifTrue: [generator nextPut: triangle]]]]].
 
heronians := heroGenerator contents.
sorter := squaredArea ascending , perimeter ascending , #third ascending , #second ascending , #first ascending.
sorted := heronians sorted: sorter.
area210 := sorted select: [:triangle | (squaredArea value: triangle) = 210 squared].
 
header := [:title |
Transcript cr; cr; nextPutAll: title; cr.
#(peri area a b c) do: [:s | Transcript nextPutAll: s; tab]].
tabulate := [:t |
Transcript cr.
Transcript print: (perimeter value: t); tab.
Transcript print: (squaredArea value: t) sqrt.
t do: [:edge | Transcript tab; print: edge].].
 
Transcript cr; print: heronians size; nextPutAll: ' heronians triangles of side <= 200 where found'.
header value: 'first 10 sorted by area, then perimeter, the largest side'.
(sorted first: 10) do: tabulate.
header value: 'heronians of area 210'.
area210 do: tabulate.
 
Transcript flush.</syntaxhighlight>
{{out}}
<pre>
517 heronians triangles of side <= 200 where found
 
first 10 sorted by area, then perimeter, the largest side
peri area a b c
12 6 3 4 5
16 12 5 5 6
18 12 5 5 8
32 24 4 13 15
30 30 5 12 13
36 36 9 10 17
54 36 3 25 26
42 42 7 15 20
36 60 10 13 13
40 60 8 15 17
 
heronians of area 210
peri area a b c
70 210 17 25 28
70 210 20 21 29
84 210 12 35 37
84 210 17 28 39
140 210 7 65 68
300 210 3 148 149
</pre>
 
=={{header|SPL}}==
<syntaxhighlight lang="spl">h,t = getem(200)
#.sort(h,4,5,1,2,3)
#.output("There are ",t," Heronian triangles")
#.output(" a b c area perimeter")
#.output("----- ----- ----- ------ ---------")
> i, 1..#.min(10,t)
print(h,i)
<
#.output(#.str("...",">34<"))
> i, 1..t
? h[4,i]=210, print(h,i)
<
print(h,i)=
#.output(#.str(h[1,i],">4>")," ",#.str(h[2,i],">4>")," ",#.str(h[3,i],">4>")," ",#.str(h[4,i],">5>")," ",#.str(h[5,i],">8>"))
.
getem(n)=
> a, 1..n
> b, #.upper((a+1)/2)..a
> c, a-b+1..b
x = ((a+b+c)*(a+b-c)*(a-b+c)*(b-a+c))^0.5
>> x%1 | #.gcd(a,b,c)>1
t += 1
h[1,t],h[2,t],h[3,t] = #.sort(a,b,c)
h[4,t],h[5,t] = heron(a,b,c)
<
<
<
<= h,t
.
heron(a,b,c)=
s = (a+b+c)/2
<= (s*(s-a)*(s-b)*(s-c))^0.5, s*2
.</syntaxhighlight>
{{out}}
<pre>
There are 517 Heronian triangles
a b c area perimeter
----- ----- ----- ------ ---------
3 4 5 6 12
5 5 6 12 16
5 5 8 12 18
4 13 15 24 32
5 12 13 30 30
9 10 17 36 36
3 25 26 36 54
7 15 20 42 42
10 13 13 60 36
8 15 17 60 40
...
17 25 28 210 70
20 21 29 210 70
12 35 37 210 84
17 28 39 210 84
7 65 68 210 140
3 148 149 210 300
</pre>
 
=={{header|Swift}}==
Works with Swift 1.2
<syntaxhighlight lang="swift">import Foundation
 
typealias PrimitiveHeronianTriangle = (s1:Int, s2:Int, s3:Int, p:Int, a:Int)
 
func heronianArea(side1 s1:Int, side2 s2:Int, side3 s3:Int) -> Int? {
let d1 = Double(s1)
let d2 = Double(s2)
let d3 = Double(s3)
let s = (d1 + d2 + d3) / 2.0
let a = sqrt(s * (s - d1) * (s - d2) * (s - d3))
if a % 1 != 0 || a <= 0 {
return nil
} else {
return Int(a)
}
}
 
func gcd(a:Int, b:Int) -> Int {
if b != 0 {
return gcd(b, a % b)
} else {
return abs(a)
}
}
 
var triangles = [PrimitiveHeronianTriangle]()
 
for s1 in 1...200 {
for s2 in 1...s1 {
for s3 in 1...s2 {
if gcd(s1, gcd(s2, s3)) == 1, let a = heronianArea(side1: s1, side2: s2, side3: s3) {
triangles.append((s3, s2, s1, s1 + s2 + s3, a))
}
}
}
}
 
sort(&triangles) {t1, t2 in
if t1.a < t2.a || t1.a == t2.a && t1.p < t2.p {
return true
} else {
return false
}
}
 
println("Number of primitive Heronian triangles with sides up to 200: \(triangles.count)\n")
println("First ten sorted by area, then perimeter, then maximum side:\n")
println("Sides\t\t\tPerimeter\tArea")
 
for t in triangles[0...9] {
println("\(t.s1)\t\(t.s2)\t\(t.s3)\t\t\(t.p)\t\t\(t.a)")
}</syntaxhighlight>
 
{{out}}
<pre>
Number of primitive Heronian triangles with sides up to 200: 517
 
First ten sorted by area, then perimeter, then maximum side:
 
Sides Perimeter Area
3 4 5 12 6
5 5 6 16 12
5 5 8 18 12
4 13 15 32 24
5 12 13 30 30
9 10 17 36 36
3 25 26 54 36
7 15 20 42 42
10 13 13 36 60
8 15 17 40 60
 
</pre>
 
=={{header|Tcl}}==
<syntaxhighlight lang="tcl">
if {[info commands let] eq ""} {
 
#make some math look nicer:
proc let {name args} {
tailcall ::set $name [uplevel 1 $args]
}
interp alias {} = {} expr
namespace import ::tcl::mathfunc::* ::tcl::mathop::*
interp alias {} sum {} +
 
# a simple adaptation of gcd from http://wiki.tcl.tk/2891
proc coprime {a args} {
set gcd $a
foreach arg $args {
while {$arg != 0} {
set t $arg
let arg = $gcd % $arg
set gcd $t
if {$gcd == 1} {return true}
}
}
return false
}
}
 
namespace eval Hero {
 
# Integer square root: returns 0 if n is not a square.
proc isqrt? {n} {
let r = entier(sqrt($n))
if {$r**2 == $n} {
return $r
} else {
return 0
}
}
 
# The square of a triangle's area
proc squarea {a b c} {
let s = ($a + $b + $c) / 2.0
let sqrA = $s * ($s - $a) * ($s - $b) * ($s - $c)
return $sqrA
}
 
proc is_heronian {a b c} {
isqrt? [squarea $a $b $c]
}
 
proc primitive_triangles {db max} {
for {set a 1} {$a <= $max} {incr a} {
for {set b $a} {$b <= $max} {incr b} {
let maxc = min($a+$b,$max)
for {set c $b} {$c <= $maxc} {incr c} {
set area [is_heronian $a $b $c]
if {$area && [coprime $a $b $c]} {
set perimiter [expr {$a + $b + $c}]
$db eval {insert into herons (area, perimiter, a, b, c) values ($area, $perimiter, $a, $b, $c)}
}
}
}
}
}
}
 
proc main {db} {
$db eval {create table herons (area int, perimiter int, a int, b int, c int)}
 
set max 200
puts "Calculating Primitive Heronian triangles up to size length $max"
puts \t[time {Hero::primitive_triangles $db $max} 1]
 
puts "Total Primitive Heronian triangles with side lengths <= $max:"
$db eval {select count(1) count from herons} {
puts "\t$count"
}
 
puts "First ten when ordered by increasing area, perimiter, max side length:"
$db eval {select * from herons order by area, perimiter, c limit 10} {
puts "\t($a, $b, $c) perimiter = $perimiter; area = $area"
}
 
puts "All of area 210:"
$db eval {select * from herons where area=210 order by area, perimiter, c} {
puts "\t($a, $b, $c) perimiter = $perimiter; area = $area"
}
}
 
 
package require sqlite3
sqlite3 db :memory:
main db
</syntaxhighlight>
{{out}}
<pre>
Calculating Primitive Heronian triangles up to size length 200
11530549 microseconds per iteration
Total Primitive Heronian triangles with side lengths <= 200:
517
First ten when ordered by increasing area, perimiter, max side length:
(3, 4, 5) perimiter = 12; area = 6
(5, 5, 6) perimiter = 16; area = 12
(5, 5, 8) perimiter = 18; area = 12
(4, 13, 15) perimiter = 32; area = 24
(5, 12, 13) perimiter = 30; area = 30
(9, 10, 17) perimiter = 36; area = 36
(3, 25, 26) perimiter = 54; area = 36
(7, 15, 20) perimiter = 42; area = 42
(10, 13, 13) perimiter = 36; area = 60
(8, 15, 17) perimiter = 40; area = 60
All of area 210:
(17, 25, 28) perimiter = 70; area = 210
(20, 21, 29) perimiter = 70; area = 210
(12, 35, 37) perimiter = 84; area = 210
(17, 28, 39) perimiter = 84; area = 210
(7, 65, 68) perimiter = 140; area = 210
(3, 148, 149) perimiter = 300; area = 210
</pre>
 
=={{header|VBA}}==
{{trans|Phix}}<syntaxhighlight lang="vb">Function heroArea(a As Integer, b As Integer, c As Integer) As Double
s = (a + b + c) / 2
On Error GoTo Err
heroArea = Sqr(s * (s - a) * (s - b) * (s - c))
Exit Function
Err:
heroArea = -1
End Function
Function hero(h As Double) As Boolean
hero = (h - Int(h) = 0) And h > 0
End Function
Public Sub main()
Dim list() As Variant, items As Integer
Dim a As Integer, b As Integer, c As Integer
Dim hArea As Double
Dim tries As Long
For a = 1 To 200
For b = 1 To a
For c = 1 To b
tries = tries + 1
If gcd(gcd(a, b), c) = 1 Then
hArea = heroArea(a, b, c)
If hero(hArea) Then
ReDim Preserve list(items)
list(items) = Array(CStr(hArea), CStr(a + b + c), CStr(a), CStr(b), CStr(c))
items = items + 1
End If
End If
Next c
Next b
Next a
list = sort(list)
Debug.Print "Primitive Heronian triangles with sides up to 200:"; UBound(list) + 1; "(of"; tries; "tested)"
Debug.Print
Debug.Print "First 10 ordered by area/perimeter/sides:"
Debug.Print "area perimeter sides"
For i = 0 To 9
Debug.Print Format(list(i)(0), "@@@"), Format(list(i)(1), "@@@"),
Debug.Print list(i)(2); "x"; list(i)(3); "x"; list(i)(4)
Next i
Debug.Print
Debug.Print "area = 210:"
Debug.Print "area perimeter sides"
For i = 0 To UBound(list)
If Val(list(i)(0)) = 210 Then
Debug.Print Format(list(i)(0), "@@@"), Format(list(i)(1), "@@@"),
Debug.Print list(i)(2); "x"; list(i)(3); "x"; list(i)(4)
End If
Next i
End Sub</syntaxhighlight>{{out}}
<pre>Primitive Heronian triangles with sides up to 200: 517 (of 1353400 tested)
 
First 10 ordered by area/perimeter/sides:
area perimeter sides
6 12 5x4x3
12 16 6x5x5
12 18 8x5x5
24 32 15x13x4
30 30 13x12x5
36 36 17x10x9
36 54 26x25x3
42 42 20x15x7
60 36 13x13x10
60 40 17x15x8
 
area = 210:
area perimeter sides
210 70 28x25x17
210 70 29x21x20
210 84 37x35x12
210 84 39x28x17
210 140 68x65x7
210 300 149x148x3</pre>
 
=={{header|Wren}}==
{{libheader|Wren-math}}
{{libheader|Wren-sort}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="wren">import "./math" for Int, Nums
import "./sort" for Sort
import "./fmt" for Fmt
 
var isInteger = Fn.new { |n| n is Num && n.isInteger }
 
var primHeronian = Fn.new { |a, b, c|
if (!(isInteger.call(a) && isInteger.call(b) && isInteger.call(c))) return [false, 0, 0]
if (Int.gcd(Int.gcd(a, b), c) != 1) return [false, 0, 0]
var p = a + b + c
var s = p / 2
var A = (s * (s - a) * (s - b) * (s - c)).sqrt
if (A > 0 && isInteger.call(A)) return [true, A, p]
return [false, 0, 0]
}
 
var ph = []
for (a in 1..200) {
for (b in a..200) {
for (c in b..200) {
var res = primHeronian.call(a, b, c)
if (res[0]) {
var sides = [a, b, c]
ph.add([sides, res[1], res[2], Nums.max(sides)])
}
}
}
}
System.print("There are %(ph.count) primitive Heronian trangles with sides <= 200.")
 
var cmp = Fn.new { |e1, e2|
if (e1[1] != e2[1]) return (e1[1] - e2[1]).sign
if (e1[2] != e2[2]) return (e1[2] - e2[2]).sign
return (e1[3] - e2[3]).sign
}
Sort.quick(ph, 0, ph.count-1, cmp)
System.print("\nThe first 10 such triangles in sorted order are:")
System.print(" Sides Area Perimeter Max Side")
for (t in ph.take(10)) {
var sides = Fmt.swrite("$2d x $2d x $2d", t[0][0], t[0][1], t[0][2])
Fmt.print("$-14s $2d $2d $2d", sides, t[1], t[2], t[3])
}
 
System.print("\nThe triangles in the previously sorted order with an area of 210 are:")
System.print(" Sides Area Perimeter Max Side")
for (t in ph.where { |e| e[1] == 210 }) {
var sides = Fmt.swrite("$2d x $3d x $3d", t[0][0], t[0][1], t[0][2])
Fmt.print("$-14s $3d $3d $3d", sides, t[1], t[2], t[3])
}</syntaxhighlight>
 
{{out}}
<pre>
There are 517 primitive Heronian trangles with sides <= 200.
 
The first 10 such triangles in sorted order are:
Sides Area Perimeter Max Side
3 x 4 x 5 6 12 5
5 x 5 x 6 12 16 6
5 x 5 x 8 12 18 8
4 x 13 x 15 24 32 15
5 x 12 x 13 30 30 13
9 x 10 x 17 36 36 17
3 x 25 x 26 36 54 26
7 x 15 x 20 42 42 20
10 x 13 x 13 60 36 13
8 x 15 x 17 60 40 17
 
The triangles in the previously sorted order with an area of 210 are:
Sides Area Perimeter Max Side
17 x 25 x 28 210 70 28
20 x 21 x 29 210 70 29
12 x 35 x 37 210 84 37
17 x 28 x 39 210 84 39
7 x 65 x 68 210 140 68
3 x 148 x 149 210 300 149
</pre>
 
=={{header|XPL0}}==
<syntaxhighlight lang "XPL0">include xpllib; \for Min, GCD, StrSort, StrNCmp, and Print
 
func Hero(A, B, C); \Return area squared of triangle with sides A, B, C
int A, B, C, S;
[S:= (A+B+C)/2;
if rem(0) = 1 then return 0; \return 0 if area is not an integer
return S*(S-A)*(S-B)*(S-C);
];
 
func Heronian(A, B, C); \Return area of triangle if sides and area are integers
int A, B, C, Area2, Area;
[Area2:= Hero(A, B, C);
Area:= sqrt(Area2);
return if Area*Area = Area2 then Area else 0;
];
 
def MaxSide = 200;
int A, B, C, Area, Count, I, J, K;
char Array(1000, 5*5);
[Format(5, 0);
Count:= 0;
for A:= 1 to MaxSide do
for B:= A to MaxSide do
for C:= B to Min(A+B-1, MaxSide) do
if GCD(GCD(B,C), A) = 1 then
[Area:= Heronian(A, B, C);
if Area > 0 then
[OpenO(8);
RlOut(8, float(Area));
RlOut(8, float(A+B+C));
RlOut(8, float(C));
RlOut(8, float(B));
RlOut(8, float(A));
OpenI(8);
for I:= 0 to 25-1 do Array(Count,I):= ChIn(8);
Count:= Count+1;
];
];
Print("Count = %d\n", Count);
StrSort(Array, Count);
Print(" A B C Perim Area\n");
for I:= 0 to 10-1 do
[for J:= 4 downto 0 do
Print("%5.5s", @Array(I, J*5+K));
Print("\n");
];
Print("\n");
for I:= 0 to Count-1 do
if StrNCmp(" 210", @Array(I,0), 5) = 0 then
[for J:= 4 downto 0 do
Print("%5.5s", @Array(I, J*5+K));
Print("\n");
];
]</syntaxhighlight>
{{out}}
<pre>
Count = 517
A B C Perim Area
3 4 5 12 6
5 5 6 16 12
5 5 8 18 12
4 13 15 32 24
5 12 13 30 30
9 10 17 36 36
3 25 26 54 36
7 15 20 42 42
10 13 13 36 60
8 15 17 40 60
 
17 25 28 70 210
20 21 29 70 210
12 35 37 84 210
17 28 39 84 210
7 65 68 140 210
3 148 149 300 210
</pre>
 
=={{header|zkl}}==
{{trans|Python}}
<langsyntaxhighlight lang="zkl">fcn hero(a,b,c){ //--> area (float)
s,a2:=(a + b + c).toFloat()/2, s*(s - a)*(s - b)*(s - c);
(a2 > 0) and a2.sqrt() or 0.0
Line 687 ⟶ 5,347:
A:=hero(a,b,c);
(A>0) and A.modf()[1].closeTo(0.0,1.0e-6) and A //--> area or False
}</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">const MAX_SIDE=200;
heros:=Sink(List);
foreach a,b,c in ([1..MAX_SIDE],[a..MAX_SIDE],[b..MAX_SIDE]){
Line 709 ⟶ 5,369:
println("Area Perimeter Sides");
heros.filter(fcn([(h,_)]){ h==210 })
.pump(fcn(phabc){ "%3s %8d %3dx%dx%d".fmt(phabc.xplode()).println() });</langsyntaxhighlight>
{{out}}
<pre>
Line 735 ⟶ 5,395:
210 300 3x148x149
</pre>
 
[[Category:Geometry]]
9,482

edits