Heronian triangles: Difference between revisions

Content added Content deleted
(Added Factor)
m (→‎{{header|REXX}}: simplified some statements, added/changed comments and whitespace, optimized both REXX versions..)
Line 3,708: Line 3,708:
exit /*stick a fork in it, we're all done. */
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
Heron: @.=0; minP=9e9; maxP=0; maxA=0; minA=9e9; Ln=length(N) /* __*/
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 √ */
#=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. */
do a=3 to N /*start at a minimum side length of 3. */
even= a//2==0 /*if A is even, B and C must be odd.*/
Aeven= a//2==0 /*if A is even, B and C must be odd.*/
do b=a+even to N by 1+even; ab=a + b /*AB: is a "shortcut" sum. */
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 /*B is even? Then C is odd. */
if b//2==0 then bump= 1 /*Is B even? Then C is odd. */
else if even then bump=0 /*A is even? " " " " */
else if Aeven then bump= 0 /*Is A even? " " " " */
else bump=1 /*A & B odd, then biz as usual. */
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 ½ of the perimeter: S */
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*/
_= 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*/
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*/
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*/
if hGCD(a, b, c) \== 1 then iterate /*GCD of sides not equal 1? Skip it*/
#=#+1; p=ab+c /*primitive Heronian triangle. */
#= # + 1; p= ab + c /*primitive Heronian triangle. */
minP=min( p, minP); maxP=max( p, maxP); Lp=length(maxP)
minP= min( p, minP); maxP= max( p, maxP); Lp= length(maxP)
minA=min(ar, minA); maxA=max(ar, maxA); La=length(maxA)
minA= min(ar, minA); maxA= max(ar, maxA); La= length(maxA)
_=@.ar.p.0 + 1 /*bump Heronian triangle counter. */
_=@.ar.p.0 + 1 /*bump Heronian triangle counter. */
@.ar.p.0=_; @.ar.p._=right(a, Ln) right(b, Ln) right(c, Ln) /*unique. */
@.ar.p.0= _; @.ar.p._= right(a, Ln) right(b, Ln) right(c, Ln) /*unique.*/
end /*c*/ /* [↑] keep each unique perimeter#*/
end /*c*/ /* [↑] keep each unique perimeter#*/
end /*b*/
end /*b*/
end /*a*/; return # /*return # of Heronian triangles. */
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; end; return x
/*────────────────────────────────────────────────────────────────────────────────────────────────────────────────*/
hGCD: procedure; parse arg x; do j=2 for 2; y=arg(j); do until y==0; parse value x//y y with y x; end; end; return x
/*──────────────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
hIsqrt: procedure; parse arg x; q=1; r=0; do while q<=x; q=q*4; end; do while q>1
hIsqrt: procedure; parse arg x; q=1; r=0; do while q<=x; q=q*4; end; do while q>1
q=q%4; _=x-r-q; r=r%2; if _>=0 then parse value _ r+q with x r; end; return r
q=q%4; _=x-r-q; r=r%2; if _>=0 then parse value _ r+q with x r; end; return r
/*──────────────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
show: m=0; say; say; parse arg ae; say arg(2); if ae\=='' then first=9e9
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*/
say; $=left('',9); $a= $"area:"; $p= $'perimeter:'; $s= $"sides:" /*literals*/
do i=minA to maxA; if ae\=='' & i\==ae then iterate /*= area? */
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 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. */
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
say right(m, 9) $a right(i, La) $p right(j, Lp) $s @.i.j.k
end /*k*/
end /*k*/
end /*j*/ /* [↑] use the known perimeters. */
end /*j*/ /* [↑] use the known perimeters. */
end /*i*/ /* [↑] show any found triangles. */
end /*i*/; return /* [↑] show any found triangles. */</lang>
return</lang>
{{out|output|text=&nbsp; when using the default inputs:}}
{{out|output|text=&nbsp; when using the default inputs:}}
<pre>
<pre>
Line 3,782: Line 3,780:
<lang rexx>/*REXX program generates & displays primitive Heronian triangles by side length and area*/
<lang rexx>/*REXX program generates & displays primitive Heronian triangles by side length and area*/
parse arg N first area . /*obtain optional arguments from the CL*/
parse arg N first area . /*obtain optional arguments from the CL*/
if N=='' | N=="," then N=200 /*Not specified? Then use the default.*/
if N=='' | N=="," then N= 200 /*Not specified? Then use the default.*/
if first=='' | first=="," then first= 10 /* " " " " " " */
if first=='' | first=="," then first= 10 /* " " " " " " */
if area=='' | area=="," then area=210 /* " " " " " " */
if area=='' | area=="," then area= 210 /* " " " " " " */
numeric digits 99; numeric digits max(9, 1+length(N**5)) /*ensure 'nuff decimal digits.*/
numeric digits 99; numeric digits max(9, 1+length(N**5)) /*ensure 'nuff decimal digits.*/
call Heron; HT= 'Heronian triangles' /*invoke the Heron subroutine. */
call Heron; HT= 'Heronian triangles' /*invoke the Heron subroutine. */
Line 3,792: Line 3,790:
exit /*stick a fork in it, we're all done. */
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
Heron: @.=0; #=0; !.=.; minP=9e9; maxA=0; maxP=0; minA=9e9; Ln=length(N) /* __ */
Heron: @.= 0; #= 0; !.= .; minP= 9e9; maxA= 0; maxP= 0; minA= 9e9; Ln= length(N)
do i=5 to N**2%2; _=i*i; !._=i; end /*pre-calculate a fast */
do i=5 to N**2 % 2; _= i*i; !._= i /* __ */
do a=3 to N /*start at a minimum side length of 3. */
end /*i*/ /* [↑] pre─calculate some fast */
even= (a//2==0) /*if A is even, B and C must be odd.*/
do a=3 to N /*start at a minimum side length of 3. */
do b=a+even to N by 1+even; ab=a + b /*AB: is a shortcut sum. */
Aeven= a//2==0 /*if A is even, B and C must be odd.*/
if b//2==0 then bump=1 /*B is even? Then C is odd. */
do b=a+Aeven to N by 1+Aeven; ab= a + b /*AB: a shortcut for the sum of A & B. */
else if even then bump=0 /*A is even? " " " " */
if b//2==0 then bump= 1 /*Is B even? Then C is odd. */
else bump=1 /*A & B odd, biz as usual. */
else if Aeven then bump= 0 /*Is A even? " " " " */
do c=b+bump to N by 2; s=(ab + c) % 2 /*calculate perimeter: S. */
else bump= 1 /*A and B are both odd, biz as usual.*/
_=s*(s-a)*(s-b)*(s-c); if !._==. then iterate /*Is _ not a square? Skip.*/
do c=b+bump to N by 2; s= (ab + c) % 2 /*calculate triangle's perimeter: S. */
ar=!._; if ar*ar\==_ then iterate /*Area not an integer? Skip.*/
_= 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.*/
if hGCD(a,b,c) \== 1 then iterate /*GCD of sides not 1? Skip.*/
#=# + 1; p=ab + c /*primitive Heronian triangle*/
#= # + 1; p= ab + c; ar= !._ /*primitive Heronian triangle*/
minP=min( p, minP); maxP=max( p, maxP); Lp=length(maxP)
minP= min( p, minP); maxP= max( p, maxP); Lp= length(maxP)
minA=min(ar, minA); maxA=max(ar, maxA); La=length(maxA); @.ar=
minA= min(ar, minA); maxA= max(ar, maxA); La= length(maxA); @.ar=
_=@.ar.p.0 + 1 /*bump the triangle counter. */
_= @.ar.p.0 + 1 /*bump the triangle counter. */
@.ar.p.0=_; @.ar.p._=right(a, Ln) right(b, Ln) right(c, Ln) /*unique.*/
@.ar.p.0= _; @.ar.p._= right(a, Ln) right(b, Ln) right(c, Ln) /*unique*/
end /*c*/ /* [↑] keep each unique perimeter #. */
end /*c*/ /* [↑] keep each unique perimeter #. */
end /*b*/
end /*b*/
end /*a*/; return # /*return number of Heronian triangles. */
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; end; return x
/*────────────────────────────────────────────────────────────────────────────────────────────────────────────────*/
hGCD: procedure; parse arg x; do j=2 for 2; y=arg(j); do until y==0; parse value x//y y with y x; end; end; return x
/*──────────────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
show: m=0; say; say; parse arg ae; say arg(2); if ae\=='' then first=9e9
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*/
say; $=left('',9); $a= $"area:"; $p= $'perimeter:'; $s= $"sides:" /*literals*/
do i=minA to maxA; if ae\=='' & i\==ae then iterate /*= area? */
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 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. */
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
say right(m, 9) $a right(i, La) $p right(j, Lp) $s @.i.j.k
end /*k*/
end /*k*/
end /*j*/ /* [↑] use the known perimeters. */
end /*j*/ /* [↑] use the known perimeters. */
end /*i*/ /* [↑] show any found triangles. */
end /*i*/; return /* [↑] show any found triangles. */</lang>
return</lang>
{{out|output|text=&nbsp; is identical to the 1<sup>st</sup> REXX version.}} <br><br>
{{out|output|text=&nbsp; is identical to the 1<sup>st</sup> REXX version.}} <br><br>