Update all new Tasks

This commit is contained in:
Ingy döt Net 2015-02-20 09:02:09 -05:00
parent 00a190b0a6
commit 91df62d461
5697 changed files with 93386 additions and 804 deletions

View file

@ -0,0 +1,29 @@
[[wp:Heron's formula|Hero's formula]] for the area of a triangle given the length of its three sides
''a'', ''b'', and ''c'' is given by:
:<math>A = \sqrt{s(s-a)(s-b)(s-c)},</math>
where ''s'' is half the perimeter of the triangle; that is,
:<math>s=\frac{a+b+c}{2}.</math>
'''[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 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/procedure/... 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.
<small>'''Note''': when generating triangles it may help to restrict <math>a <= b <= c</math></small>

View file

@ -0,0 +1,45 @@
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 {
immutable s = (a + b + c) / 2.0;
immutable a2 = s * (s - a) * (s - b) * (s - c);
return (a2 > 0) ? a2.sqrt : 0.0;
}
bool isHeronian(in uint a, in uint b, in uint c) pure nothrow @safe @nogc {
immutable h = hero(a, b, c);
return h > 0 && h.floor == h.ceil;
}
T gcd3(T)(in T x, in T y, in T z) pure nothrow @safe @nogc {
return gcd(gcd(x, y), z);
}
void main() /*@safe*/ {
enum uint maxSide = 200;
// Sort by increasing area, perimeter, then sides.
//auto h = cartesianProduct!3(iota(1, maxSide + 1))
auto r = iota(1, maxSide + 1);
const h = cartesianProduct(r, r, r)
//.filter!({a, b, c} => ...
.filter!(t => t[0] <= t[1] && t[1] <= t[2] &&
t[0] + t[1] > t[2] &&
t[].gcd3 == 1 && t[].isHeronian)
.array
.schwartzSort!(t => tuple(t[].hero, t[].only.sum, t.reverse))
.release;
static void showTriangles(R)(R ts) @safe {
"Area Perimeter Sides".writeln;
foreach (immutable t; ts)
writefln("%3s %8d %3dx%dx%d", t[].hero, t[].only.sum, t[]);
}
writefln("Primitive Heronian triangles with sides up to %d: %d", maxSide, h.length);
"\nFirst ten when ordered by increasing area, then perimeter,then maximum sides:".writeln;
showTriangles(h.take(10));
"\nAll with area 210 subject to the previous ordering:".writeln;
showTriangles(h.filter!(t => t[].hero == 210));
}

View file

@ -0,0 +1,63 @@
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

View file

@ -0,0 +1,9 @@
a=:0&{"1
b=:1&{"1
c=:2&{"1
s=:(a+b+c)%2:
A=:2 %: s*(s-a)*(s-b)*(s-c)
P=:+/"1
isprimhero=:(0&~:*(=<.@+))@A*1=a+.b+.c
tri=: (/: A,.P,.{:"1) (#~ isprimhero)~./:"1~1+200 200 200#:i.200^3

View file

@ -0,0 +1,22 @@
#tri
517
10{.(,._,.A,.P) tri
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
(#~210=A) (,._,.A,.P) tri
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

View file

@ -0,0 +1,57 @@
import java.util.ArrayList;
public class Heron {
public static void main(String[] args) {
ArrayList<int[]> list = new ArrayList<int[]>();
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)
list.add(new int[]{a, b, c, a + b + c, (int)heronArea(a, b, c)});
}
}
}
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;
}
}
}
}
}

View file

@ -0,0 +1,23 @@
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

View file

@ -0,0 +1,50 @@
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;
}
}
}
}
}

View file

@ -0,0 +1,23 @@
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

View file

@ -0,0 +1,42 @@
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) {
$_ 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 {
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;
}

View file

@ -0,0 +1,63 @@
use strict;
use warnings;
use List::Util qw(max);
sub gcd { $_[1] == 0 ? $_[0] : gcd($_[1], $_[0] % $_[1]) }
sub hero {
my ($a, $b, $c) = @_[0,1,2];
my $s = ($a + $b + $c) / 2;
sqrt $s*($s - $a)*($s - $b)*($s - $c);
}
sub heronian_area {
my $hero = hero my ($a, $b, $c) = @_[0,1,2];
sprintf("%.0f", $hero) eq $hero ? $hero : 0
}
sub primitive_heronian_area {
my ($a, $b, $c) = @_[0,1,2];
heronian_area($a, $b, $c) if 1 == gcd $a, gcd $b, $c;
}
sub show {
print " Area Perimeter Sides\n";
for (@_) {
my ($area, $perim, $c, $b, $a) = @$_;
printf "%7d %9d %d×%d×%d\n", $area, $perim, $a, $b, $c;
}
}
sub main {
my $maxside = shift // 200;
my $first = shift // 10;
my $witharea = shift // 210;
my @h;
for my $c (1 .. $maxside) {
for my $b (1 .. $c) {
for my $a ($c - $b + 1 .. $b) {
if (my $area = primitive_heronian_area $a, $b, $c) {
push @h, [$area, $a+$b+$c, $c, $b, $a];
}
}
}
}
@h = sort {
$a->[0] <=> $b->[0]
or
$a->[1] <=> $b->[1]
or
max(@$a[2,3,4]) <=> max(@$b[2,3,4])
} @h;
printf "Primitive Heronian triangles with sides up to %d: %d\n",
$maxside,
scalar @h;
print "First:\n";
show @h[0 .. $first - 1];
print "Area $witharea:\n";
show grep { $_->[0] == $witharea } @h;
}
&main();

View file

@ -0,0 +1,47 @@
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){
for($b = 1; $b -le $c; $b++){
for($a = 1; $a -le $b; $a++){
if((Get-Gcd $c (Get-Gcd $b $a)) -eq 1 -and (Is-Heron(Get-HeronArea $a $b $c))){
$result += @(,@($a, $b, $c,($a + $b + $c), (Get-HeronArea $a $b $c)))
}
}
}
}
$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"
for($i = 0; $i -lt 10; $i++){
"$($result[$i][0])`t$($result[$i][1])`t$($result[$i][2])`t`t`t$($result[$i][3])`t`t`t$($result[$i][4])"
}
"`nArea = 210`nSides`t`t`t`tPerimeter`tArea"
foreach($i in $result){
if($i[4] -eq 210){
"$($i[0])`t$($i[1])`t$($i[2])`t`t`t$($i[3])`t`t`t$($i[4])"
}
}

View file

@ -0,0 +1,23 @@
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
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

View file

@ -0,0 +1,33 @@
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))

View file

@ -0,0 +1 @@
Data source: http://rosettacode.org/wiki/Heronian_triangles

View file

@ -0,0 +1,53 @@
/*REXX pgm generates primitive Heronian triangles by side length & area.*/
parse arg N first area . /*get optional N (sides). */
if N=='' | N==',' then N=200 /*maybe use the default. */
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*/
call Heron /*invoke Heron subroutine. */
say # ' primitive Heronian triangles found with sides up to ' N " (inclusive)."
call show , 'listing of the first ' first ' primitive Heronian triangles:'
call show area, 'listing of the (above) found primitive Heronian triangles with an area of ' area
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────HERON subroutine────────────────────*/
Heron: @.=.; #=0; minP=9e9; maxP=0; minA=9e9; maxA=0; Ln=length(N)
#.=0; #.2=1 #.3=1; #.7=1; #.8=1 /*¬good √.*/
do a=3 to N /*start at a minimum side length.*/
ev= \ (a//2); inc=1+ev /*if A is even, B & C must be odd*/
do b=a+ev to N by inc; ab=a+b /*AB: is used for summing below.*/
do c=b to N by inc; p=ab+c; s=p/2 /*calc Perimeter, S*/
_=s*(s-a)*(s-b)*(s-c); if _<=0 then iterate /*_ isn't positive.*/
if pos(.,_)\==0 then iterate /*not an integer. */
parse var _ '' -1 q ; if #.q then iterate /*not good square. */
ar=iSQRT(_); if ar*ar\==_ then iterate /*area not integer.*/
if hGCD(a,b,c)\==1 then iterate /*GCD of sides ¬1. */
#=#+1 /*got prim. H. tri.*/
minP=min( p,minP); maxP=max( p,maxP); Lp=length(maxP)
minA=min(ar,minA); maxA=max(ar,maxA); La=length(maxA); @.ar=
if @.ar.p.0==. then @.ar.p.0=0; _=@.ar.p.0+1 /*bump triangle ctr*/
@.ar.p.0=_; @.ar.p._=right(a,Ln) right(b,Ln) right(c,Ln) /*unique*/
end /*c*/ /* [↑] keep each unique P items.*/
end /*b*/
end /*a*/
return # /*return # of Heronian triangles.*/
/*──────────────────────────────────HGCD subroutine─────────────────────*/
hGCD: procedure; parse arg x; do j=2 for 2 /*sub handles exactly 3 args*/
y=arg(j); do until y==0; parse value x//y y with y x; end; end; return x
/*──────────────────────────────────ISQRT subroutine────────────────────*/
iSQRT: procedure; parse arg x; x=x%1; if x==0 | x==1 then return x; q=1
do while q<=x; q=q*4; end; r=0 /*Q will be > X at loop end.*/
do while q>1 ; q=q%4; _=x-r-q; r=r%2; if _>=0 then do;x=_;r=r+q;end; end
return r /* R is a postive integer. */
/*──────────────────────────────────SHOW subroutine─────────────────────*/
show: m=0; say; say; parse arg ae; say arg(2); if ae\=='' then first=9e9
say; y=left('',9) /* [↓] skip the nothings. */
do i=minA to maxA; if @.i==. then iterate
if ae\=='' & i\==ae then iterate /*Area specified? Then check*/
do j=minP to maxP until m>=first /*only list FIRST entries.*/
if @.i.j.0==. then iterate /*Not defined? Then skip it.*/
do k=1 for @.i.j.0; m=m+1 /*visit each perimeter entry*/
say right(m,9) y'area:' right(i,La) y"perimeter:" right(j,Lp) y'sides:' @.i.j.k
end /*k*/
end /*j*/ /* [↑] use known perimeters*/
end /*i*/ /* [↑] show found triangles*/
return

View file

@ -0,0 +1,55 @@
#lang racket
(require xml/xml data/order)
;; Returns the area of triangle sides a, b, c
(define (A a b c)
(define s (/ (+ a b c) 2)) ; where s=\frac{a+b+c}{2}.
(sqrt (* s (- s a) (- s b) (- s c)))) ; A = \sqrt{s(s-a)(s-b)(s-c)}
;; Returns same as A iff a, b, c and A are integers; #f otherwise
(define (heronian?-area a b c)
(and (integer? a) (integer? b) (integer? c)
(let ((h (A a b c))) (and (integer? h) h))))
;; Returns same as heronian?-area, with the additional condition that (gcd a b c) = 1
(define (primitive-heronian?-area a b c)
(and (= 1 (gcd a b c))
(heronian?-area a b c)))
(define (generate-heronian-triangles max-side)
(for*/list
((a (in-range 1 (add1 max-side)))
(b (in-range 1 (add1 a)))
(c (in-range 1 (add1 b)))
#:when (< a (+ b c))
(h (in-value (primitive-heronian?-area 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<? t1 t2)
(eq? '< (datum-order t1 t2)))
(define triangle->tds (match-lambda [`#(,h ,p ,s) `((td ,(~a s)) (td ,(~a p)) (td ,(~a h)))]))
(define (triangles->table ts)
`(table
(tr (th "#") (th "sides") (th "perimiter") (th "area")) "\n"
,@(for/list ((i (in-naturals 1)) (t ts)) `(tr (td ,(~a i)) ,@(triangle->tds t) "\n"))))
(define (sorted-triangles-table triangles)
(triangles->table (sort triangles tri<?)))
(module+ main
(define ts (generate-heronian-triangles 200))
(define div-out
`(div
(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 (sort ts tri<?) 10)) "\n"
;; Show a similar ordered table for those triangles with area = 210
,(sorted-triangles-table (sort (filter (match-lambda [(vector 210 _ _) #t] [_ #f]) ts) tri<?))))
(displayln (xexpr->string div-out)))

View file

@ -0,0 +1,46 @@
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'), perimeter, area]
end
end
max, area = 200, 210
prim_triangles = []
1.upto(max) do |a|
a.upto(max) do |b|
b.upto(max) do |c|
next if a.gcd(b).gcd(c) > 1
prim_triangles << Triangle.new(a, b, c) if Triangle.valid?(a, b, c)
end
end
end
sorted = prim_triangles.select(&:heronian?).sort
puts "Primitive heronian triangles with sides upto #{max}: #{sorted.size}"
puts "\nsides perim. area"
puts sorted.first(10).map(&:to_s)
puts "\nTriangles with an area of: #{area}"
sorted.each{|tr| puts tr if tr.area == area}