Heronian triangles
Hero's formula for the area of a triangle given the length of its three sides a, b, and c is given by:
- Failed to parse (SVG (MathML can be enabled via browser plugin): Invalid response ("Math extension cannot connect to Restbase.") from server "https://wikimedia.org/api/rest_v1/":): {\displaystyle A = \sqrt{s(s-a)(s-b)(s-c)},}
where s is half the perimeter of the triangle; that is,
- Failed to parse (SVG (MathML can be enabled via browser plugin): Invalid response ("Math extension cannot connect to Restbase.") from server "https://wikimedia.org/api/rest_v1/":): {\displaystyle s=\frac{a+b+c}{2}.}
Heronian triangles are triangles whose sides and area are all integers.
- An example is the triangle with sides 3, 4, 5 whose area is 6 (and whose perimeter is 12).
Note that any triangle whose sides are all an integer multiple of 3,4,5; such as 6,8,10, will also be a heronian triangle.
Define a Primitive Heronian triangle as a heronian triangle where the greatest common divisor of all three sides is 1. this will exclude, for example triangle 6,8,10
The task is to:
- Create a named function/method/proceedure/... that implements Hero's formula.
- Use the function to generate all the primitive heronian 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
Show all output here.
Note: when generating triangles it may help to restrict Failed to parse (SVG (MathML can be enabled via browser plugin): Invalid response ("Math extension cannot connect to Restbase.") from server "https://wikimedia.org/api/rest_v1/":): {\displaystyle a <= b <= c}
Perl 6
<lang perl6>sub hero($a, $b, $c) {
my $s = ($a + $b + $c) / 2; my $a2 = $s * ($s - $a) * ($s - $b) * ($s - $c); $a2.sqrt;
}
sub heronian-area($a, $b, $c) {
given hero $a, $b, $c { .floor == .ceiling ?? .floor !! 0 }
}
sub primitive-heronian-area($a, $b, $c) {
heronian-area $a, $b, $c if 1 == [gcd] $a, $b, $c;
}
sub show {
say " Area Perimeter Sides"; for @_ -> [$area, $perim, $c, $b, $a] {
printf "%6d %6d %12s\n", $area, $perim, "$a×$b×$c";
}
}
sub MAIN ($maxside = 200, $first = 10, $witharea = 210) {
my \h = sort gather for 1 .. $maxside -> $c { for 1 .. $c -> $b { for $c - $b + 1 .. $b -> $a { 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;
say "\nFirst $first:"; show h[^$first];
say "\nArea $witharea:"; show h.grep: *[0] == $witharea;
}</lang>
- Output:
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
Python
<lang python>from math import sqrt from fractions import gcd from itertools import product
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):
return gcd(gcd(x, y), z)
if __name__ == '__main__':
maxside = 200 h = [(a, b, c) for a,b,c in product(range(1, maxside + 1), repeat=3) if a <= b <= c and a + b > c and gcd3(a, b, c) == 1 and is_heronian(a, b, c)] h.sort(key = lambda x: (hero(*x), sum(x), x[::-1])) # By increasing area, perimeter, then sides 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>
- Output:
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