Pythagorean triples: Difference between revisions
Walterpachl (talk | contribs) m →version 1: ptimatives -> primitives |
Walterpachl (talk | contribs) |
||
Line 1,785: | Line 1,785: | ||
if @.a.b.c then iterate |
if @.a.b.c then iterate |
||
trips=trips+1 /*eureka. */ |
trips=trips+1 /*eureka. */ |
||
prims=prims+1 /*count this |
prims=prims+1 /*count this primitive triple. */ |
||
do m=2; !a=a*m; !b=b*m; !c=c*m /*gen non- |
do m=2; !a=a*m; !b=b*m; !c=c*m /*gen non-primitives.*/ |
||
if !a+!b+!c>N then leave /*is this multiple a triple ? */ |
if !a+!b+!c>N then leave /*is this multiple a triple ? */ |
||
trips=trips+1 /*yuppers, then we found another.*/ |
trips=trips+1 /*yuppers, then we found another.*/ |
||
Line 1,798: | Line 1,798: | ||
say 'max perimeter = 'N, /*show a single line of output. */ |
say 'max perimeter = 'N, /*show a single line of output. */ |
||
left('',7) "Pythagorean triples =" trips, /*left('',0) = 7 blanks.*/ |
left('',7) "Pythagorean triples =" trips, /*left('',0) = 7 blanks.*/ |
||
left('',7) ' |
left('',7) 'primitives =' prims |
||
/*stick a fork in it, we're done.*/</lang> |
/*stick a fork in it, we're done.*/</lang> |
||
'''output''' is identical to version 1. |
'''output''' is identical to version 1. |
Revision as of 10:48, 13 September 2012
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
You are encouraged to solve this task according to the task description, using any language you may know.
A Pythagorean triple is defined as three positive integers where , and They are called primitive triples if are coprime, that is, if their pairwise greatest common divisors . Because of their relationship through the Pythagorean theorem, a, b, and c are coprime if a and b are coprime (). Each triple forms the length of the sides of a right triangle, whose perimeter is .
Task
The task is to determine how many Pythagorean triples there are with a perimeter no larger than 100 and the number of these that are primitive.
Extra credit: Deal with large values. Can your program handle a max perimeter of 1,000,000? What about 10,000,000? 100,000,000?
Note: the extra credit is not for you to demonstrate how fast your language is compared to others; you need a proper algorithm to solve them in a timely manner.
- Cf
Ada
Translation of efficient method from C, see the WP article. Compiles on gnat/gcc.
<lang Ada>with Ada.Text_IO;
procedure Pythagorean_Triples is
type Large_Natural is range 0 .. 2**63-1; -- this is the maximum for gnat
procedure New_Triangle(A, B, C: Large_Natural; Max_Perimeter: Large_Natural; Total_Cnt, Primitive_Cnt: in out Large_Natural) is Perimeter: constant Large_Natural := A + B + C; begin if Perimeter <= Max_Perimeter then Primitive_Cnt := Primitive_Cnt + 1; Total_Cnt := Total_Cnt + Max_Perimeter / Perimeter; New_Triangle(A-2*B+2*C, 2*A-B+2*C, 2*A-2*B+3*C, Max_Perimeter, Total_Cnt, Primitive_Cnt); New_Triangle(A+2*B+2*C, 2*A+B+2*C, 2*A+2*B+3*C, Max_Perimeter, Total_Cnt, Primitive_Cnt); New_Triangle(2*B+2*C-A, B+2*C-2*A, 2*B+3*C-2*A, Max_Perimeter, Total_Cnt, Primitive_Cnt); end if; end New_Triangle;
T_Cnt, P_Cnt: Large_Natural;
begin
for I in 1 .. 9 loop T_Cnt := 0; P_Cnt := 0; New_Triangle(3,4,5, 10**I, Total_Cnt => T_Cnt, Primitive_Cnt => P_Cnt); Ada.Text_IO.Put_Line("Up to 10 **" & Integer'Image(I) & " :" & Large_Natural'Image(T_Cnt) & " Triples," & Large_Natural'Image(P_Cnt) & " Primitives"); end loop;
end Pythagorean_Triples;</lang>
Output:
Up to 10 ** 1 : 0 Triples, 0 Primitives Up to 10 ** 2 : 17 Triples, 7 Primitives Up to 10 ** 3 : 325 Triples, 70 Primitives Up to 10 ** 4 : 4858 Triples, 703 Primitives Up to 10 ** 5 : 64741 Triples, 7026 Primitives Up to 10 ** 6 : 808950 Triples, 70229 Primitives Up to 10 ** 7 : 9706567 Triples, 702309 Primitives Up to 10 ** 8 : 113236940 Triples, 7023027 Primitives Up to 10 ** 9 : 1294080089 Triples, 70230484 Primitives
Bracmat
<lang bracmat>(pythagoreanTriples=
total prim max-peri U
. (.(1,-2,2) (2,-1,2) (2,-2,3))
(.(1,2,2) (2,1,2) (2,2,3)) (.(-1,2,2) (-2,1,2) (-2,2,3)) : ?U & ( new-tri = i t p Urows Urow Ucols , a b c loop A B C . !arg:(,?a,?b,?c) & !a+!b+!c:~>!max-peri:?p & 1+!prim:?prim & div$(!max-peri.!p)+!total:?total & !U:?Urows & ( loop = !Urows:(.?Urow) ?Urows & !Urow:?Ucols & :?t & whl ' ( !Ucols:(?A,?B,?C) ?Ucols & (!t,!a*!A+!b*!B+!c*!C):?t ) & new-tri$!t & !loop ) & !loop | ) & ( Main = seed . (,3,4,5):?seed & 10:?max-peri & whl ' ( 0:?total:?prim & new-tri$!seed & out $ ( str $ ( "Up to " !max-peri ": " !total " triples, " !prim " primitives." ) ) & !max-peri*10:~>10000000:?max-peri ) ) & Main$
);
pythagoreanTriples$; </lang>
Output (under Linux):
Up to 10: 0 triples, 0 primitives. Up to 100: 17 triples, 7 primitives. Up to 1000: 325 triples, 70 primitives. Up to 10000: 4858 triples, 703 primitives. Up to 100000: 64741 triples, 7026 primitives. Up to 1000000: 808950 triples, 70229 primitives. Up to 10000000: 9706567 triples, 702309 primitives. Up to 100000000: 113236940 triples, 7023027 primitives.
Under Windows XP Command prompt the last result is unattainable due to stack overflow.
With very few changes we can get rid of the stack exhausting recursion. Instead of calling new-tri
recursively, be push the triples to test onto a stack and return to the Main
function. In the innermost loop we pop a triple from the stack and call new-tri
. The memory overhead is only a few megabytes for a max perimeter of 100,000,000. On my Windows XP box the whole computation takes at least 15 minutes! Given enough time (and memory), the program can compute results for larger perimeters.
<lang bracmat>(pythagoreanTriples=
total prim max-peri U stack
. (.(1,-2,2) (2,-1,2) (2,-2,3))
(.(1,2,2) (2,1,2) (2,2,3)) (.(-1,2,2) (-2,1,2) (-2,2,3)) : ?U & ( new-tri = i t p Urows Urow Ucols Ucol , a b c loop A B C . !arg:(,?a,?b,?c) & !a+!b+!c:~>!max-peri:?p & 1+!prim:?prim & div$(!max-peri.!p)+!total:?total & !U:?Urows & ( loop = !Urows:(.?Urow) ?Urows & !Urow:?Ucols & :?t & whl ' ( !Ucols:(?A,?B,?C) ?Ucols & (!t,!a*!A+!b*!B+!c*!C):?t ) & !t !stack:?stack & !loop ) & !loop | ) & ( Main = seed . 10:?max-peri & whl ' ( 0:?total:?prim & (,3,4,5):?stack & whl ' (!stack:%?seed ?stack&new-tri$!seed) & out $ ( str $ ( "Up to " !max-peri ": " !total " triples, " !prim " primitives." ) ) & !max-peri*10:~>100000000:?max-peri ) ) & Main$
);
pythagoreanTriples$;</lang>
C
Sample implemention; naive method, patentedly won't scale to larger numbers, despite the attempt to optimize it. Calculating up to 10000 is already a test of patience. <lang C>#include <stdio.h>
- include <stdlib.h>
typedef unsigned long long xint; typedef unsigned long ulong;
inline ulong gcd(ulong m, ulong n) { ulong t; while (n) { t = n; n = m % n; m = t; } return m; }
int main() { ulong a, b, c, pytha = 0, prim = 0, max_p = 100; xint aa, bb, cc;
for (a = 1; a <= max_p / 3; a++) { aa = (xint)a * a; printf("a = %lu\r", a); /* show that we are working */ fflush(stdout);
/* max_p/2: valid limit, because one side of triangle * must be less than the sum of the other two */ for (b = a + 1; b < max_p/2; b++) { bb = (xint)b * b; for (c = b + 1; c < max_p/2; c++) { cc = (xint)c * c; if (aa + bb < cc) break; if (a + b + c > max_p) break;
if (aa + bb == cc) { pytha++; if (gcd(a, b) == 1) prim++; } } } }
printf("Up to %lu, there are %lu triples, of which %lu are primitive\n", max_p, pytha, prim);
return 0; }</lang>output:<lang>Up to 100, there are 17 triples, of which 7 are primitive</lang> Efficient method, generating primitive triples only as described in the same WP article:<lang C>#include <stdio.h>
- include <stdlib.h>
- include <stdint.h>
/* should be 64-bit integers if going over 1 billion */ typedef unsigned long xint;
- define FMT "%lu"
xint total, prim, max_peri; xint U[][9] = {{ 1, -2, 2, 2, -1, 2, 2, -2, 3}, { 1, 2, 2, 2, 1, 2, 2, 2, 3}, {-1, 2, 2, -2, 1, 2, -2, 2, 3}};
void new_tri(xint in[]) { int i; xint t[3], p = in[0] + in[1] + in[2];
if (p > max_peri) return;
prim ++;
/* for every primitive triangle, its multiples would be right-angled too; * count them up to the max perimeter */ total += max_peri / p;
/* recursively produce next tier by multiplying the matrices */ for (i = 0; i < 3; i++) { t[0] = U[i][0] * in[0] + U[i][1] * in[1] + U[i][2] * in[2]; t[1] = U[i][3] * in[0] + U[i][4] * in[1] + U[i][5] * in[2]; t[2] = U[i][6] * in[0] + U[i][7] * in[1] + U[i][8] * in[2]; new_tri(t); } }
int main() { xint seed[3] = {3, 4, 5};
for (max_peri = 10; max_peri <= 100000000; max_peri *= 10) { total = prim = 0; new_tri(seed);
printf( "Up to "FMT": "FMT" triples, "FMT" primitives.\n", max_peri, total, prim); } return 0; }</lang>Output<lang>Up to 10: 0 triples, 0 primitives. Up to 100: 17 triples, 7 primitives. Up to 1000: 325 triples, 70 primitives. Up to 10000: 4858 triples, 703 primitives. Up to 100000: 64741 triples, 7026 primitives. Up to 1000000: 808950 triples, 70229 primitives. Up to 10000000: 9706567 triples, 702309 primitives. Up to 100000000: 113236940 triples, 7023027 primitives.</lang>
Same as above, but with loop unwound and third recursion eliminated: <lang c>#include <stdio.h>
- include <stdlib.h>
- include <stdint.h>
/* should be 64-bit integers if going over 1 billion */ typedef unsigned long xint;
- define FMT "%lu"
xint total, prim, max_peri;
void new_tri(xint in[]) { int i; xint t[3], p; xint x = in[0], y = in[1], z = in[2];
recur: p = x + y + z; if (p > max_peri) return;
prim ++; total += max_peri / p;
t[0] = x - 2 * y + 2 * z; t[1] = 2 * x - y + 2 * z; t[2] = t[1] - y + z; new_tri(t);
t[0] += 4 * y; t[1] += 2 * y; t[2] += 4 * y; new_tri(t);
z = t[2] - 4 * x; y = t[1] - 4 * x; x = t[0] - 2 * x; goto recur; }
int main() { xint seed[3] = {3, 4, 5};
for (max_peri = 10; max_peri <= 100000000; max_peri *= 10) { total = prim = 0; new_tri(seed);
printf( "Up to "FMT": "FMT" triples, "FMT" primitives.\n", max_peri, total, prim); } return 0; }</lang>
CoffeeScript
This algorithm scales linearly with the max perimeter. It uses two loops that are capped by the square root of the half-perimeter to examine/count provisional values of m and n, where m and n generate a, b, c, and p using simple number theory.
<lang coffeescript> gcd = (x, y) ->
return x if y == 0 gcd(y, x % y)
- m,n generate primitive Pythag triples
- preconditions:
- m, n are integers of different parity
- m > n
- gcd(m,n) == 1 (coprime)
- m, n generate: [m*m - n*n, 2*m*n, m*m + n*n]
- perimeter is 2*m*m + 2*m*n = 2 * m * (m+n)
count_triples = (max_perim) ->
num_primitives = 0 num_triples = 0 m = 2 upper_limit = Math.sqrt max_perim / 2 while m <= upper_limit n = m % 2 + 1 p = 2*m*m + 2*m*n delta = 4*m while n < m and p <= max_perim if gcd(m, n) == 1 num_primitives += 1 num_triples += Math.floor max_perim / p n += 2 p += delta m += 1 console.log num_primitives, num_triples
max_perim = Math.pow 10, 9 # takes under a minute count_triples(max_perim) </lang> output
time coffee pythag_triples.coffee 70230484 1294080089 real 0m45.989s
Common Lisp
<lang lisp>(defun mmul (a b)
(loop for x in a collect
(loop for y in x for z in b sum (* y z))))
(defun count-tri (lim)
(let ((prim 0) (cnt 0)) (labels ((count1 (tr) (let ((peri (apply #'+ tr)))
(when (<= peri lim) (incf prim) (incf cnt (truncate lim peri)) (count1 (mmul '(( 1 -2 2) ( 2 -1 2) ( 2 -2 3)) tr)) (count1 (mmul '(( 1 2 2) ( 2 1 2) ( 2 2 3)) tr)) (count1 (mmul '((-1 2 2) (-2 1 2) (-2 2 3)) tr))))))
(count1 '(3 4 5)) (format t "~a: ~a prim, ~a all~%" lim prim cnt))))
(loop for p from 2 do (count-tri (expt 10 p)))</lang>output<lang>100: 7 prim, 17 all 1000: 70 prim, 325 all 10000: 703 prim, 4858 all 100000: 7026 prim, 64741 all 1000000: 70229 prim, 808950 all 10000000: 702309 prim, 9706567 all ...</lang>
D
Shorter Version
<lang d>import std.stdio, std.range, std.algorithm;
ulong[2] tri(ulong lim, ulong a=3, ulong b=4, ulong c=5) {
const ulong l = a + b + c; if (l > lim) return [0, 0]; ulong[2] r = [1, lim / l]; r[] += tri(lim, a - 2*b + 2*c, 2*a - b + 2*c, 2*a - 2*b + 3*c)[]; r[] += tri(lim, a + 2*b + 2*c, 2*a + b + 2*c, 2*a + 2*b + 3*c)[]; r[] += tri(lim, -a + 2*b + 2*c, -2*a + b + 2*c, -2*a + 2*b + 3*c)[]; return r;
}
void main() {
foreach (p; 1 .. 8) writeln(10 ^^ p, " ", tri(10 ^^ p));
}</lang>
- Output:
10 [0, 0] 100 [7, 17] 1000 [70, 325] 10000 [703, 4858] 100000 [7026, 64741] 1000000 [70229, 808950] 10000000 [702309, 9706567]
Faster Version
<lang d>import std.stdio;
alias uint xuint; // ulong if going over 1 billion.
__gshared xuint nTriples, nPrimitives, limit;
void countTriples(xuint x, xuint y, xuint z) nothrow {
while (true) { immutable xuint p = x + y + z; if (p > limit) return;
nPrimitives++; nTriples += limit / p;
xuint t0 = x - 2 * y + 2 * z; xuint t1 = 2 * x - y + 2 * z; xuint t2 = t1 - y + z; countTriples(t0, t1, t2);
t0 += 4 * y; t1 += 2 * y; t2 += 4 * y; countTriples(t0, t1, t2);
z = t2 - 4 * x; y = t1 - 4 * x; x = t0 - 2 * x; }
}
void main() {
foreach (p; 1 .. 9) { limit = (cast(xuint)10) ^^ p; nTriples = nPrimitives = 0; countTriples(3, 4, 5); writefln("Up to %11d: %11d triples, %9d primitives.", limit, nTriples, nPrimitives); }
}</lang>
- Output:
Up to 10: 0 triples, 0 primitives. Up to 100: 17 triples, 7 primitives. Up to 1000: 325 triples, 70 primitives. Up to 10000: 4858 triples, 703 primitives. Up to 100000: 64741 triples, 7026 primitives. Up to 1000000: 808950 triples, 70229 primitives. Up to 10000000: 9706567 triples, 702309 primitives. Up to 100000000: 113236940 triples, 7023027 primitives.
Using the power p up to 11, using ulong for xuint, and compiling with the dmd -L/STACK:10000000
switch to increase the stack size to about 10MB:
Up to 10: 0 triples, 0 primitives. Up to 100: 17 triples, 7 primitives. Up to 1000: 325 triples, 70 primitives. Up to 10000: 4858 triples, 703 primitives. Up to 100000: 64741 triples, 7026 primitives. Up to 1000000: 808950 triples, 70229 primitives. Up to 10000000: 9706567 triples, 702309 primitives. Up to 100000000: 113236940 triples, 7023027 primitives. Up to 1000000000: 1294080089 triples, 70230484 primitives. Up to 10000000000: 14557915466 triples, 702304875 primitives.
Total run-time up to 10_000_000_000: about 63 seconds.
Waiting less than half an hour:
Up to 10: 0 triples, 0 primitives. Up to 100: 17 triples, 7 primitives. Up to 1000: 325 triples, 70 primitives. Up to 10000: 4858 triples, 703 primitives. Up to 100000: 64741 triples, 7026 primitives. Up to 1000000: 808950 triples, 70229 primitives. Up to 10000000: 9706567 triples, 702309 primitives. Up to 100000000: 113236940 triples, 7023027 primitives. Up to 1000000000: 1294080089 triples, 70230484 primitives. Up to 10000000000: 14557915466 triples, 702304875 primitives. Up to 100000000000: 161750315680 triples, 7023049293 primitives.
Erlang
<lang Erlang>%% %% Pythagorian triples in Erlang, J.W. Luiten %% -module(triples). -export([main/1]).
%% Transformations t1, t2 and t3 to generate new triples t1(A, B, C) ->
{A-2*B+2*C, 2*A-B+2*C, 2*A-2*B+3*C}.
t2(A, B, C) ->
{A+2*B+2*C, 2*A+B+2*C, 2*A+2*B+3*C}.
t3(A, B, C) ->
{2*B+2*C-A, B+2*C-2*A, 2*B+3*C-2*A}.
%% Generation of triples count_triples(A, B, C, Tot_acc, Cnt_acc, Max_perimeter) when (A+B+C) =< Max_perimeter ->
Tot1 = Tot_acc + Max_perimeter div (A+B+C), {A1, B1, C1} = t1(A, B, C), {Tot2, Cnt2} = count_triples(A1, B1, C1, Tot1, Cnt_acc+1, Max_perimeter),
{A2, B2, C2} = t2(A, B, C), {Tot3, Cnt3} = count_triples(A2, B2, C2, Tot2, Cnt2, Max_perimeter),
{A3, B3, C3} = t3(A, B, C), {Tot4, Cnt4} = count_triples(A3, B3, C3, Tot3, Cnt3, Max_perimeter), {Tot4, Cnt4};
count_triples(_A, _B, _C, Tot_acc, Cnt_acc, _Max_perimeter) ->
{Tot_acc, Cnt_acc}.
count_triples(A, B, C, Pow) ->
Max = trunc(math:pow(10, Pow)), {Tot, Prim} = count_triples(A, B, C, 0, 0, Max), {Pow, Tot, Prim}.
count_triples(Pow) ->
count_triples(3, 4, 5, Pow).
%% Display a single result. display_result({Pow, Tot, Prim}) ->
io:format("Up to 10 ** ~w : ~w triples, ~w primitives~n", [Pow, Tot, Prim]).
main(Max) ->
L = lists:seq(1, Max), Answer = lists:map(fun(X) -> count_triples(X) end, L), lists:foreach(fun(Result) -> display_result(Result) end, Answer).</lang>
Output:
Up to 10 ** 1 : 0 triples, 0 primitives Up to 10 ** 2 : 17 triples, 7 primitives Up to 10 ** 3 : 325 triples, 70 primitives Up to 10 ** 4 : 4858 triples, 703 primitives Up to 10 ** 5 : 64741 triples, 7026 primitives Up to 10 ** 6 : 808950 triples, 70229 primitives Up to 10 ** 7 : 9706567 triples, 702309 primitives Up to 10 ** 8 : 113236940 triples, 7023027 primitives Up to 10 ** 9 : 1294080089 triples, 70230484 primitives Up to 10 ** 10 : 14557915466 triples, 702304875 primitives Up to 10 ** 11 : 161750315680 triples, 7023049293 primitives
Euphoria
<lang euphoria>function tri(atom lim, sequence in)
sequence r atom p p = in[1] + in[2] + in[3] if p > lim then return {0, 0} end if r = {1, floor(lim / p)} r += tri(lim, { in[1]-2*in[2]+2*in[3], 2*in[1]-in[2]+2*in[3], 2*in[1]-2*in[2]+3*in[3]}) r += tri(lim, { in[1]+2*in[2]+2*in[3], 2*in[1]+in[2]+2*in[3], 2*in[1]+2*in[2]+3*in[3]}) r += tri(lim, {-in[1]+2*in[2]+2*in[3], -2*in[1]+in[2]+2*in[3], -2*in[1]+2*in[2]+3*in[3]}) return r
end function
atom max_peri max_peri = 10 while max_peri <= 100000000 do
printf(1,"%d: ", max_peri) ? tri(max_peri, {3, 4, 5}) max_peri *= 10
end while</lang>
Output:
10: {0,0} 100: {7,17} 1000: {70,325} 10000: {703,4858} 100000: {7026,64741} 1000000: {70229,808950} 10000000: {702309,9706567} 100000000: {7023027,113236940}
Factor
Pretty slow (100 times slower than C)...
<lang factor>USING: accessors arrays formatting kernel literals math math.functions math.matrices math.ranges sequences ; IN: rosettacode.pyth
CONSTANT: T1 {
{ 1 2 2 } { -2 -1 -2 } { 2 2 3 }
} CONSTANT: T2 {
{ 1 2 2 } { 2 1 2 } { 2 2 3 }
} CONSTANT: T3 {
{ -1 -2 -2 } { 2 1 2 } { 2 2 3 }
}
CONSTANT: base { 3 4 5 }
TUPLE: triplets-count primitives total ;
- <0-triplets-count> ( -- a ) 0 0 \ triplets-count boa ;
- next-triplet ( triplet T -- triplet' ) [ 1array ] [ m. ] bi* first ;
- candidates-triplets ( seed -- candidates )
${ T1 T2 T3 } [ next-triplet ] with map ;
- add-triplets ( current-triples limit triplet -- stop )
sum 2dup > [ /i [ + ] curry change-total [ 1 + ] change-primitives drop t ] [ 3drop f ] if ;
- all-triplets ( current-triples limit seed -- triplets )
3dup add-triplets [ candidates-triplets [ all-triplets ] with swapd reduce ] [ 2drop ] if ;
- count-triplets ( limit -- count )
<0-triplets-count> swap base all-triplets ;
- pprint-triplet-count ( limit count -- )
[ total>> ] [ primitives>> ] bi "Up to %d: %d triples, %d primitives.\n" printf ;
- pyth ( -- )
8 [1,b] [ 10^ dup count-triplets pprint-triplet-count ] each ;</lang>
Up to 10: 0 triples, 0 primitives. Up to 100: 17 triples, 7 primitives. Up to 1000: 325 triples, 70 primitives. Up to 10000: 4858 triples, 703 primitives. Up to 100000: 64741 triples, 7026 primitives. Up to 1000000: 808950 triples, 70229 primitives. Up to 10000000: 9706567 triples, 702309 primitives. Up to 100000000: 113236940 triples, 7023027 primitives. Running time: 57.968821207 seconds
Fortran
<lang fortran>module triples
implicit none integer :: max_peri, prim, total integer :: u(9,3) = reshape((/ 1, -2, 2, 2, -1, 2, 2, -2, 3, & 1, 2, 2, 2, 1, 2, 2, 2, 3, & -1, 2, 2, -2, 1, 2, -2, 2, 3 /), & (/ 9, 3 /))
contains
recursive subroutine new_tri(in)
integer, intent(in) :: in(:) integer :: i integer :: t(3), p
p = sum(in) if (p > max_peri) return
prim = prim + 1 total = total + max_peri / p do i = 1, 3 t(1) = sum(u(1:3, i) * in) t(2) = sum(u(4:6, i) * in) t(3) = sum(u(7:9, i) * in) call new_tri(t); end do
end subroutine new_tri end module triples
program Pythagorean
use triples implicit none
integer :: seed(3) = (/ 3, 4, 5 /) max_peri = 10 do total = 0 prim = 0 call new_tri(seed) write(*, "(a, i10, 2(i10, a))") "Up to", max_peri, total, " triples", prim, " primitives" if(max_peri == 100000000) exit max_peri = max_peri * 10 end do
end program Pythagorean</lang>
Output:
Up to 10 0 triples 0 primitives Up to 100 17 triples 7 primitives Up to 1000 325 triples 70 primitives Up to 10000 4858 triples 703 primitives Up to 100000 64741 triples 7026 primitives Up to 1000000 808950 triples 70229 primitives Up to 10000000 9706567 triples 702309 primitives Up to 100000000 113236940 triples 7023027 primitives
Go
<lang go>package main
import "fmt"
var total, prim, maxPeri int64
func newTri(s0, s1, s2 int64) {
if p := s0 + s1 + s2; p <= maxPeri { prim++ total += maxPeri / p newTri(+1*s0-2*s1+2*s2, +2*s0-1*s1+2*s2, +2*s0-2*s1+3*s2) newTri(+1*s0+2*s1+2*s2, +2*s0+1*s1+2*s2, +2*s0+2*s1+3*s2) newTri(-1*s0+2*s1+2*s2, -2*s0+1*s1+2*s2, -2*s0+2*s1+3*s2) }
}
func main() {
for maxPeri = 100; maxPeri <= 1e11; maxPeri *= 10 { prim = 0 total = 0 newTri(3, 4, 5) fmt.Printf("Up to %d: %d triples, %d primitives\n", maxPeri, total, prim) }
}</lang> Output:
Up to 100: 17 triples, 7 primitives Up to 1000: 325 triples, 70 primitives Up to 10000: 4858 triples, 703 primitives Up to 100000: 64741 triples, 7026 primitives Up to 1000000: 808950 triples, 70229 primitives Up to 10000000: 9706567 triples, 702309 primitives Up to 100000000: 113236940 triples, 7023027 primitives Up to 1000000000: 1294080089 triples, 70230484 primitives Up to 10000000000: 14557915466 triples, 702304875 primitives Up to 100000000000: 161750315680 triples, 7023049293 primitives
Icon and Unicon
This uses the elegant formula (#IV) from Formulas for generating Pythagorean triples
<lang Icon> link numbers link printf
procedure main(A) # P-triples
plimit := (0 < integer(\A[1])) | 100 # get perimiter limit nonprimitiveS := set() # record unique non-primitives triples primitiveS := set() # record unique primitive triples u := 0 while (g := (u +:= 1)^2) + 3 * u + 2 < plimit / 2 do { every v := seq(1) do { a := g + (i := 2*u*v) b := (h := 2*v^2) + i c := g + h + i if (p := a + b + c) > plimit then break insert( (gcd(u,v)=1 & u%2=1, primitiveS) | nonprimitiveS, memo(a,b,c)) every k := seq(2) do { # k is for larger non-primitives if k*p > plimit then break insert(nonprimitiveS,memo(a*k,b*k,c*k) ) } } }
printf("Under perimiter=%d: Pythagorean Triples=%d including primitives=%d\n",
plimit,*nonprimitiveS+*primitiveS,*primitiveS)
every put(gcol := [] , &collections) printf("Time=%d, Collections: total=%d string=%d block=%d",&time,gcol[1],gcol[3],gcol[4]) end
procedure memo(x[]) #: return a csv string of arguments in sorted order
every (s := "") ||:= !sort(x) do s ||:= ","
return s[1:-1]
end</lang>
numbers.icn provides gcd printf.icn provides printf
The output from some sample runs with BLKSIZE=500000000 and STRSIZE=50000000 is below. It starts getting very slow after 10M at about 9 minutes (times are shown in ms. I suspect there may be faster gcd algorithms that would speed this up.
Output:
Under perimiter=10: Pythagorean Triples=0 including primitives=0 Time=3, Collections: total=0 string=0 block=0 Under perimiter=100: Pythagorean Triples=17 including primitives=7 Time=3, Collections: total=0 string=0 block=0 Under perimiter=1000: Pythagorean Triples=325 including primitives=70 Time=6, Collections: total=0 string=0 block=0 Under perimiter=10000: Pythagorean Triples=4858 including primitives=703 Time=57, Collections: total=0 string=0 block=0 Under perimiter=100000: Pythagorean Triples=64741 including primitives=7026 Time=738, Collections: total=0 string=0 block=0 Under perimiter=1000000: Pythagorean Triples=808950 including primitives=70229 Time=12454, Collections: total=0 string=0 block=0 Under perimiter=10000000: Pythagorean Triples=9706567 including primitives=702309 Time=560625, Collections: total=16 string=8 block=8
Haskell
<lang haskell>pytr n = filter (\(_, a, b, c) -> a+b+c <= n) [(prim a b c, a, b, c) | a <- [1..n], b <- [1..n], c <- [1..n], a < b && b < c, a^2 + b^2 == c^2]
where prim a b _ = gcd a b == 1
main = putStrLn $ "Up to 100 there are " ++ (show $ length xs) ++ " triples, of which " ++ (show $ length $ filter (\(x,_,_,_) -> x == True) xs) ++ " are primitive."
where xs = pytr 100
</lang>
Up to 100 there are 17 triples, of which 7 are primitive.
Recursive primitive generation: <lang haskell>triangles :: Int -> Int triangles max_peri = if max_peri < 12 then [] else concat tiers where tiers = 3,4,5 : more tiers more (a:as) | null tier = [] | otherwise = tier : more as where tier = concat (map (filter ((<=max_peri).sum).tmul) a) where tmul t = map (map (sum . zipWith (*) t)) $ [[[ 1,-2,2],[ 2,-1,2],[ 2,-2,3]], [[ 1, 2,2],[ 2, 1,2],[ 2, 2,3]], [[-1, 2,2],[-2, 1,2],[-2, 2,3]]]
triangle_count max_p = (length t, sum $ map ((max_p `div`).sum) t) where t = triangles max_p
main = mapM_ putStrLn $ map (\n -> show n ++ " " ++ show (triangle_count n)) $ map (10^) [1..]</lang>
- Output:
10 (0,0) 100 (7,17) 1000 (70,325) 10000 (703,4858) 100000 (7026,64741) 1000000 (70229,808950) 10000000 (702309,9706567) ...
J
Brute force approach:
<lang j>pytr=: 3 :0
r=. i. 0 3 for_a. 1 + i. <.(y-1)%3 do. b=. 1 + a + i. <.(y%2)-3*a%2 c=. a +&.*: b keep=. (c = <.c) *. y >: a+b+c if. 1 e. keep do. r=. r, a,.b ,.&(keep&#) c end. end. (,.~ prim"1)r
)
prim=: 1 = 2 +./@{. |:</lang>
Example use:
First column indicates whether the triple is primitive, and the remaining three columns are a, b and c.
<lang j> pytr 100 1 3 4 5 1 5 12 13 0 6 8 10 1 7 24 25 1 8 15 17 0 9 12 15 1 9 40 41 0 10 24 26 0 12 16 20 1 12 35 37 0 15 20 25 0 15 36 39 0 16 30 34 0 18 24 30 1 20 21 29 0 21 28 35 0 24 32 40
(# , [: {. +/) pytr 10
0 0
(# , [: {. +/) pytr 100
17 7
(# , [: {. +/) pytr 1000
325 70
(# , [: {. +/) pytr 10000
4858 703</lang>
pytr 10000 takes 4 seconds on this laptop, and time to complete grows with square of perimeter, so pytr 1e6 should take something like 11 hours using this algorithm on this machine.
A slightly smarter approach:
<lang j>trips=:3 :0
'm n'=. |:(#~ 1 = 2 | +/"1)(#~ >/"1) ,/ ,"0/~ }. i. <. %: y prim=. (#~ 1 = 2 +./@{. |:) (#~ y >: +/"1)m (-&*: ,. +:@* ,. +&*:) n /:~ ; <@(,.~ # {. 1:)@(*/~ 1 + y i.@<.@% +/)"1 prim
)</lang>
usage for trips is the same as for pytr. Thus:
<lang j> (# , 1 {. +/) trips 10 0 0
(# , 1 {. +/) trips 100
17 7
(# , 1 {. +/) trips 1000
325 70
(# , 1 {. +/) trips 10000
4858 703
(# , 1 {. +/) trips 100000
64741 7026
(# , 1 {. +/) trips 1000000
808950 70229
(# , 1 {. +/) trips 10000000
9706567 702309</lang>
The last line took about 16 seconds.
That said, we do not actually have to generate all the triples, we just need to count them. Thus:
<lang j>trc=:3 :0
'm n'=. |:(#~ 1 = 2 | +/"1)(#~ >/"1) ,/ ,"0/~ }. i. <. %: y <.y%+/"1 (#~ 1 = 2 +./@{. |:) (#~ y >: +/"1)m (-&*: ,. +:@* ,. +&*:) n
)</lang>
The result is a list of positive integers, one number for each primitive triple which fits within the limit, giving the number of triples which are multiples of that primitive triple whose perimeter is no greater than the limiting perimeter.
<lang> (#,+/)trc 1e8 7023027 113236940</lang>
But note that J's memory footprint reached 6.7GB during the computation, so to compute larger values the computation would have to be broken up into reasonable sized blocks.
Java
Brute force
Theoretically, this can go "forever", but it takes a while, so only the minimum is shown. Luckily, BigInteger
has a GCD method built in.
<lang java> import java.math.BigInteger; import static java.math.BigInteger.ONE;
public class PythTrip{
public static void main(String[] args){ long tripCount = 0, primCount = 0;
//change this to whatever perimeter limit you want;the RAM's the limit BigInteger periLimit = BigInteger.valueOf(100), peri2 = periLimit.divide(BigInteger.valueOf(2)), peri3 = periLimit.divide(BigInteger.valueOf(3));
for(BigInteger a = ONE; a.compareTo(peri3) < 0; a = a.add(ONE)){ BigInteger aa = a.multiply(a); for(BigInteger b = a.add(ONE); b.compareTo(peri2) < 0; b = b.add(ONE)){ BigInteger bb = b.multiply(b); BigInteger ab = a.add(b); BigInteger aabb = aa.add(bb); for(BigInteger c = b.add(ONE); c.compareTo(peri2) < 0; c = c.add(ONE)){
int compare = aabb.compareTo(c.multiply(c)); //if a+b+c > periLimit if(ab.add(c).compareTo(periLimit) > 0){ break; } //if a^2 + b^2 != c^2 if(compare < 0){ break; }else if (compare == 0){ tripCount++; System.out.print(a + ", " + b + ", " + c);
//does binary GCD under the hood if(a.gcd(b).equals(ONE)){ System.out.print(" primitive"); primCount++; } System.out.println(); } } } } System.out.println("Up to a perimeter of " + periLimit + ", there are " + tripCount + " triples, of which " + primCount + " are primitive."); }
}</lang> Output:
3, 4, 5 primitive 5, 12, 13 primitive 6, 8, 10 7, 24, 25 primitive 8, 15, 17 primitive 9, 12, 15 9, 40, 41 primitive 10, 24, 26 12, 16, 20 12, 35, 37 primitive 15, 20, 25 15, 36, 39 16, 30, 34 18, 24, 30 20, 21, 29 primitive 21, 28, 35 24, 32, 40 Up to a perimeter of 100, there are 17 triples, of which 7 are primitive.
Brute force primitives with scaling
Pythagorean triples/Java/Brute force primitives
Parent/child
(with limited modification for saving a few BigInteger operations)
This can also go "forever" theoretically. Letting it go to another order of magnitude overflowed the stack on the computer this was tested on. This version also does not show the triples as it goes, it only counts them. <lang java5>import java.math.BigInteger;
public class Triples{
public static BigInteger LIMIT; public static final BigInteger TWO = BigInteger.valueOf(2); public static final BigInteger THREE = BigInteger.valueOf(3); public static final BigInteger FOUR = BigInteger.valueOf(4); public static final BigInteger FIVE = BigInteger.valueOf(5); public static long primCount = 0; public static long tripCount = 0;
//I don't know Japanese :p public static void parChild(BigInteger a, BigInteger b, BigInteger c){ BigInteger perim = a.add(b).add(c); if(perim.compareTo(LIMIT) > 0) return; primCount++; tripCount += LIMIT.divide(perim).longValue(); BigInteger a2 = TWO.multiply(a), b2 = TWO.multiply(b), c2 = TWO.multiply(c), c3 = THREE.multiply(c); parChild(a.subtract(b2).add(c2), a2.subtract(b).add(c2), a2.subtract(b2).add(c3)); parChild(a.add(b2).add(c2), a2.add(b).add(c2), a2.add(b2).add(c3)); parChild(a.negate().add(b2).add(c2), a2.negate().add(b).add(c2), a2.negate().add(b2).add(c3)); }
public static void main(String[] args){ for(long i = 100; i <= 10000000; i*=10){ LIMIT = BigInteger.valueOf(i); primCount = tripCount = 0; parChild(THREE, FOUR, FIVE); System.out.println(LIMIT + ": " + tripCount + " triples, " + primCount + " primitive."); } }
}</lang> Output:
100: 17 triples, 7 primitive. 1000: 325 triples, 70 primitive. 10000: 4858 triples, 703 primitive. 100000: 64741 triples, 7026 primitive. 1000000: 808950 triples, 70229 primitive. 10000000: 9706567 triples, 702309 primitive.
Liberty BASIC
<lang lb> print time$()
for power =1 to 6
perimeterLimit =10^power upperBound =int( 1 +perimeterLimit^0.5) primitives =0 triples =0 extras =0 ' will count the in-range multiples of any primitive
for m =2 to upperBound for n =1 +( m mod 2 =1) to m -1 step 2 term1 =2 *m *n term2 =m *m -n *n term3 =m *m +n *n perimeter =term1 +term2 +term3
if perimeter <=perimeterLimit then triples =triples +1
a =term1 b =term2
do r = a mod b a =b b =r loop until r <=0
if ( a =1) and ( perimeter <=perimeterLimit) then 'we've found a primitive triple if a =1, since hcf =1. And it is inside perimeter range. Save it in an array primitives =primitives +1 if term1 >term2 then temp =term1: term1 =term2: term2 =temp 'swap so in increasing order of side length nEx =int( perimeterLimit /perimeter) 'We have the primitive & removed any multiples. Now calculate ALL the multiples in range. extras =extras +nEx end if
scan next n next m
print " Number of primitives having perimeter below "; 10^power, " was "; primitives, " & "; extras, " non-primitive triples." print time$()
next power
print "End" end </lang>
17:59:34 Number of primitives having perimeter below 10 was 0 & 0 non-primitive triples. 17:59:34 Number of primitives having perimeter below 100 was 7 & 17 non-primitive triples. 17:59:34 Number of primitives having perimeter below 1000 was 70 & 325 non-primitive triples. 17:59:34 Number of primitives having perimeter below 10000 was 703 & 4858 non-primitive triples. 17:59:35 Number of primitives having perimeter below 100000 was 7026 & 64741 non-primitive triples. 17:59:42 Number of primitives having perimeter below 1000000 was 70229 & 808950 non-primitive triples. 18:01:30 End
MATLAB / Octave
<lang Matlab>N= 100;
a = 1:N; b = a(ones(N,1),:).^2; b = b+b'; b = sqrt(b); [y,x]=find(b==fix(b)); % test % here some alternative tests % b = b.^(1/k); [y,x]=find(b==fix(b)); % test 2 % [y,x]=find(b==(fix(b.^(1/k)).^k)); % test 3 % b=b.^(1/k); [y,x]=find(abs(b - round(b)) <= 4*eps*b); z = sqrt(x.^2+y.^2); ix = (z+x+y<100) & (x < y) & (y < z); p = find(gcd(x(ix),y(ix))==1); % find primitive triples
printf('There are %i Pythagorean Triples and %i primitive triples with a perimeter smaller than %i.\n',... sum(ix), length(p), N); </lang>
Output:
There are 17 Pythagorean Triples and 7 primitive triples with a perimeter smaller than 100.
Modula-3
Note that this code only works on 64bit machines (where INTEGER is 64 bits). Modula-3 provides a LONGINT type, which is 64 bits on 32 bit systems, but there is a bug in the implementation apparently. <lang modula3>MODULE PyTriple64 EXPORTS Main;
IMPORT IO, Fmt;
VAR tcnt, pcnt, max, i: INTEGER;
PROCEDURE NewTriangle(a, b, c: INTEGER; VAR tcount, pcount: INTEGER) =
VAR perim := a + b + c; BEGIN IF perim <= max THEN pcount := pcount + 1; tcount := tcount + max DIV perim; NewTriangle(a-2*b+2*c, 2*a-b+2*c, 2*a-2*b+3*c, tcount, pcount); NewTriangle(a+2*b+2*c, 2*a+b+2*c, 2*a+2*b+3*c, tcount, pcount); NewTriangle(2*b+2*c-a, b+2*c-2*a, 2*b+3*c-2*a, tcount, pcount); END; END NewTriangle;
BEGIN
i := 100; REPEAT max := i; tcnt := 0; pcnt := 0; NewTriangle(3, 4, 5, tcnt, pcnt); IO.Put(Fmt.Int(i) & ": " & Fmt.Int(tcnt) & " Triples, " & Fmt.Int(pcnt) & " Primitives\n"); i := i * 10; UNTIL i = 10000000;
END PyTriple64.</lang>
Output:
100: 17 Triples, 7 Primitives 1000: 325 Triples, 70 Primitives 10000: 4858 Triples, 703 Primitives 100000: 64741 Triples, 7026 Primitives 1000000: 808950 Triples, 70229 Primitives
OCaml
<lang OCaml>let isqrt n =
let rec iter t = let d = n - t*t in if (0 <= d) && (d < t+t+1) (* t*t <= n < (t+1)*(t+1) *) then t else iter ((t+(n/t))/2) in iter 1
let rec gcd a b =
let t = a mod b in if t = 0 then b else gcd b t
let coprime a b = gcd a b = 1
let num_to ms =
let ctr = ref 0 in let prim_ctr = ref 0 in let max_m = isqrt (ms/2) in for m = 2 to max_m do for j = 0 to (m/2) - 1 do let n = m-(2*j+1) in if coprime m n then let s = 2*m*(m+n) in if s <= ms then (ctr := !ctr + (ms/s); incr prim_ctr) done done; (!ctr, !prim_ctr)
let show i =
let s, p = num_to i in Printf.printf "For perimeters up to %d there are %d total and %d primitive\n%!" i s p;;
List.iter show [ 100; 1000; 10000; 100000; 1000000; 10000000; 100000000 ]</lang> Output:
For perimeters up to 100 there are 17 total and 7 primitive For perimeters up to 1000 there are 325 total and 70 primitive For perimeters up to 10000 there are 4858 total and 703 primitive For perimeters up to 100000 there are 64741 total and 7026 primitive For perimeters up to 1000000 there are 808950 total and 70229 primitive For perimeters up to 10000000 there are 9706567 total and 702309 primitive For perimeters up to 100000000 there are 113236940 total and 7023027 primitive
PARI/GP
This version is reasonably efficient and can handle inputs like a million quickly. <lang parigp>do(lim)={
my(prim,total); lim\=1; for(m=2,sqrtint(lim-1), forstep(n=1+m%2,min(sqrtint(lim-m^2),m-1),2, if(gcd(m,n)==1, prim++; total+=lim\(m^2+n^2) ) ) ); [prim,total]
}; do(100)</lang>
Pascal
<lang pascal>Program PythagoreanTriples (output);
var
total, prim, maxPeri: int64;
procedure newTri(s0, s1, s2: int64);
var p: int64; begin p := s0 + s1 + s2; if p <= maxPeri then begin inc(prim); total := total + maxPeri div p; newTri( s0 + 2*(-s1+s2), 2*( s0+s2) - s1, 2*( s0-s1+s2) + s2); newTri( s0 + 2*( s1+s2), 2*( s0+s2) + s1, 2*( s0+s1+s2) + s2); newTri(-s0 + 2*( s1+s2), 2*(-s0+s2) + s1, 2*(-s0+s1+s2) + s2); end; end;
begin
maxPeri := 100; while maxPeri <= 1e10 do begin prim := 0; total := 0; newTri(3, 4, 5); writeln('Up to ', maxPeri, ': ', total, ' triples, ', prim, ' primitives.'); maxPeri := maxPeri * 10; end;
end.</lang> Output (on Core2Duo 2GHz laptop):
time ./PythagoreanTriples Up to 100: 17 triples, 7 primitives. Up to 1000: 325 triples, 70 primitives. Up to 10000: 4858 triples, 703 primitives. Up to 100000: 64741 triples, 7026 primitives. Up to 1000000: 808950 triples, 70229 primitives. Up to 10000000: 9706567 triples, 702309 primitives. Up to 100000000: 113236940 triples, 7023027 primitives. Up to 1000000000: 1294080089 triples, 70230484 primitives. Up to 10000000000: 14557915466 triples, 702304875 primitives. 109.694u 0.094s 1:50.43 99.4% 0+0k 0+0io 0pf+0w
Perl 6
First up is a fairly naive brute force implementation that is not really practical for large perimeter limits. 100 is no problem. 1000 is slow. 10000 is glacial.
Works with Rakudo 2011.06.
<lang perl6>my %triples; my $limit = 100;
for 3 .. $limit/2 -> $c {
for 1 .. $c -> $a { my $b = ($c * $c - $a * $a).sqrt; last if $c + $a + $b > $limit; last if $a > $b; if $b == $b.Int { my $key = "$a $b $c"; %triples{$key} = ([gcd] $c, $a, $b.Int) > 1 ?? 0 !! 1; say $key, %triples{$key} ?? ' - primitive' !! ; } }
}
say "There are {+%triples.keys} Pythagorean Triples with a perimeter <= $limit,"
~"\nof which {[+] %triples.values} are primitive.";</lang>
3 4 5 - primitive 6 8 10 5 12 13 - primitive 9 12 15 8 15 17 - primitive 12 16 20 7 24 25 - primitive 15 20 25 10 24 26 20 21 29 - primitive 18 24 30 16 30 34 21 28 35 12 35 37 - primitive 15 36 39 24 32 40 9 40 41 - primitive There are 17 Pythagorean Triples with a perimeter <= 100, of which 7 are primitive.
Here's a much faster version. Hint, "oyako" is Japanese for "parent/child". :-)
<lang perl6>sub triples($limit) {
my $primitive = 0; my $civilized = 0; sub oyako($a, $b, $c) { my $perim = $a + $b + $c; return if $perim > $limit;
++$primitive; $civilized += $limit div $perim;
oyako( $a - 2*$b + 2*$c, 2*$a - $b + 2*$c, 2*$a - 2*$b + 3*$c); oyako( $a + 2*$b + 2*$c, 2*$a + $b + 2*$c, 2*$a + 2*$b + 3*$c); oyako(-$a + 2*$b + 2*$c, -2*$a + $b + 2*$c, -2*$a + 2*$b + 3*$c); } oyako(3,4,5); "$limit => ($primitive $civilized)";
}
for 10,100,1000 ... * -> $limit {
say triples $limit;
}</lang> Output:
10 => (0 0) 100 => (7 17) 1000 => (70 325) 10000 => (703 4858) 100000 => (7026 64741) 1000000 => (70229 808950) 10000000 => (702309 9706567) 100000000 => (7023027 113236940) 1000000000 => (70230484 1294080089) ^C
The geometric sequence of limits will continue on forever, so eventually when you get tired of waiting (about a billion on my computer), you can just stop it. Another efficiency trick of note: we avoid passing the limit in as a parameter to the inner helper routine, but instead supply the limit via the lexical scope. Likewise, the accumulators are referenced lexically, so only the triples themselves need to be passed downward, and nothing needs to be returned.
Here is an alternate version that avoids naming any scalars that can be handled by vector processing instead: <lang perl6>constant @coeff = [[+1, -2, +2], [+2, -1, +2], [+2, -2, +3]],
[[+1, +2, +2], [+2, +1, +2], [+2, +2, +3]], [[-1, +2, +2], [-2, +1, +2], [-2, +2, +3]];
sub triples($limit) {
sub oyako(@trippy) { my $perim = [+] @trippy; return if $perim > $limit; take (1 + ($limit div $perim)i); for @coeff -> @nine { oyako (map -> @three { [+] @three »*« @trippy }, @nine); } return; }
my $complex = 0i + [+] gather oyako([3,4,5]); "$limit => ({$complex.re, $complex.im})";
}
for 10,100,1000 ... * -> $limit {
say triples $limit;
}</lang> Using vectorized ops allows a bit more potential for parallelization, though this is probably not as big a win in this case, especially since we do a certain amount of multiplying by 1 that the scalar version doesn't need to do. Note the cute trick of adding complex numbers to add two numbers in parallel. The use of gather/take allows the summation to run in a different thread than the helper function, at least in theory...
In practice, this solution runs considerably slower than the previous one, due primarily to passing gather/take values up many levels of dynamic scope. Eventually this may be optimized. Also, this solution currently chews up gigabytes of memory, while the previous solution stays at a quarter gig or so. This likely indicates a memory leak somewhere in niecza.
PicoLisp
<lang PicoLisp>(for (Max 10 (>= 100000000 Max) (* Max 10))
(let (Total 0 Prim 0 In (3 4 5)) (recur (In) (let P (apply + In) (when (>= Max P) (inc 'Prim) (inc 'Total (/ Max P)) (for Row (quote (( 1 -2 2) ( 2 -1 2) ( 2 -2 3)) (( 1 2 2) ( 2 1 2) ( 2 2 3)) ((-1 2 2) (-2 1 2) (-2 2 3)) ) (recurse (mapcar '((U) (sum * U In)) Row) ) ) ) ) ) (prinl "Up to " Max ": " Total " triples, " Prim " primitives.") ) )</lang>
Output:
Up to 10: 0 triples, 0 primitives. Up to 100: 17 triples, 7 primitives. Up to 1000: 325 triples, 70 primitives. Up to 10000: 4858 triples, 703 primitives. Up to 100000: 64741 triples, 7026 primitives. Up to 1000000: 808950 triples, 70229 primitives. Up to 10000000: 9706567 triples, 702309 primitives. Up to 100000000: 113236940 triples, 7023027 primitives.
PureBasic
<lang purebasic>
Procedure.i ConsoleWrite(t.s) ; compile using /CONSOLE option
OpenConsole() PrintN (t.s) CloseConsole() ProcedureReturn 1
EndProcedure
Procedure.i StdOut(t.s) ; compile using /CONSOLE option
OpenConsole() Print(t.s) CloseConsole() ProcedureReturn 1
EndProcedure
Procedure.i gcDiv(n,m) ; greatest common divisor if n=0:ProcedureReturn m:endif while m <> 0
if n > m n - m else m - n endif
wend ProcedureReturn n EndProcedure
st=ElapsedMilliseconds()
nmax =10000 power =8
dim primitiveA(power) dim alltripleA(power) dim pmaxA(power)
x=1 for i=1 to power
x*10:pmaxA(i)=x/2
next
for n=1 to nmax
for m=(n+1) to (nmax+1) step 2 ; assure m-n is odd d=gcDiv(n,m) p=m*m+m*n for i=1 to power if p<=pmaxA(i) if d =1 primitiveA(i)+1 ; right here we have the primitive perimeter "seed" 'p' k=1:q=p*k ; set k to one to include p : use q as the 'p*k' while q<=pmaxA(i) alltripleA(i)+1 ; accumulate multiples of this perimeter while q <= pmaxA(i) k+1:q=p*k wend endif endif next next
next
for i=1 to power
t.s="Up to "+str(pmaxA(i)*2)+": " t.s+str(alltripleA(i))+" triples, " t.s+str(primitiveA(i))+" primitives." ConsoleWrite(t.s)
next ConsoleWrite("") et=ElapsedMilliseconds()-st:ConsoleWrite("Elapsed time = "+str(et)+" milliseconds") </lang>
- Output
>cmd /c "C:\_sys\temp\PythagoreanTriples.exe" Up to 10: 0 triples, 0 primitives. Up to 100: 17 triples, 7 primitives. Up to 1000: 325 triples, 70 primitives. Up to 10000: 4858 triples, 703 primitives. Up to 100000: 64741 triples, 7026 primitives. Up to 1000000: 808950 triples, 70229 primitives. Up to 10000000: 9706567 triples, 702309 primitives. Up to 100000000: 113236940 triples, 7023027 primitives. Elapsed time = 5163 milliseconds >Exit code: 0
Python
Two methods, the second of which is much faster <lang python>from fractions import gcd
def pt1(maxperimeter=100):
- Naive method
trips = [] for a in range(1, maxperimeter): aa = a*a for b in range(a, maxperimeter-a+1): bb = b*b for c in range(b, maxperimeter-b-a+1): cc = c*c if a+b+c > maxperimeter or cc > aa + bb: break if aa + bb == cc: trips.append((a,b,c, gcd(a, b) == 1)) return trips
def pytrip(trip=(3,4,5),perim=100, prim=1):
a0, b0, c0 = a, b, c = sorted(trip) t, firstprim = set(), prim>0 while a + b + c <= perim: t.add((a, b, c, firstprim>0)) a, b, c, firstprim = a+a0, b+b0, c+c0, False # t2 = set() for a, b, c, firstprim in t: a2, a5, b2, b5, c2, c3, c7 = a*2, a*5, b*2, b*5, c*2, c*3, c*7 if a5 - b5 + c7 <= perim: t2 |= pytrip(( a - b2 + c2, a2 - b + c2, a2 - b2 + c3), perim, firstprim) if a5 + b5 + c7 <= perim: t2 |= pytrip(( a + b2 + c2, a2 + b + c2, a2 + b2 + c3), perim, firstprim) if -a5 + b5 + c7 <= perim: t2 |= pytrip((-a + b2 + c2, -a2 + b + c2, -a2 + b2 + c3), perim, firstprim) return t | t2
def pt2(maxperimeter=100):
- Parent/child relationship method:
- http://en.wikipedia.org/wiki/Formulas_for_generating_Pythagorean_triples#XI.
trips = pytrip((3,4,5), maxperimeter, 1) return trips
def printit(maxperimeter=100, pt=pt1):
trips = pt(maxperimeter) print(" Up to a perimeter of %i there are %i triples, of which %i are primitive" % (maxperimeter, len(trips), len([prim for a,b,c,prim in trips if prim])))
for algo, mn, mx in ((pt1, 250, 2500), (pt2, 500, 20000)):
print(algo.__doc__) for maxperimeter in range(mn, mx+1, mn): printit(maxperimeter, algo)
</lang>
- Output
# Naive method Up to a perimeter of 250 there are 56 triples, of which 18 are primitive Up to a perimeter of 500 there are 137 triples, of which 35 are primitive Up to a perimeter of 750 there are 227 triples, of which 52 are primitive Up to a perimeter of 1000 there are 325 triples, of which 70 are primitive Up to a perimeter of 1250 there are 425 triples, of which 88 are primitive Up to a perimeter of 1500 there are 527 triples, of which 104 are primitive Up to a perimeter of 1750 there are 637 triples, of which 123 are primitive Up to a perimeter of 2000 there are 744 triples, of which 140 are primitive Up to a perimeter of 2250 there are 858 triples, of which 156 are primitive Up to a perimeter of 2500 there are 969 triples, of which 175 are primitive # Parent/child relationship method: # http://en.wikipedia.org/wiki/Formulas_for_generating_Pythagorean_triples#XI. Up to a perimeter of 500 there are 137 triples, of which 35 are primitive Up to a perimeter of 1000 there are 325 triples, of which 70 are primitive Up to a perimeter of 1500 there are 527 triples, of which 104 are primitive Up to a perimeter of 2000 there are 744 triples, of which 140 are primitive Up to a perimeter of 2500 there are 969 triples, of which 175 are primitive Up to a perimeter of 3000 there are 1204 triples, of which 211 are primitive Up to a perimeter of 3500 there are 1443 triples, of which 245 are primitive Up to a perimeter of 4000 there are 1687 triples, of which 280 are primitive Up to a perimeter of 4500 there are 1931 triples, of which 314 are primitive Up to a perimeter of 5000 there are 2184 triples, of which 349 are primitive Up to a perimeter of 5500 there are 2442 triples, of which 385 are primitive Up to a perimeter of 6000 there are 2701 triples, of which 422 are primitive Up to a perimeter of 6500 there are 2963 triples, of which 457 are primitive Up to a perimeter of 7000 there are 3224 triples, of which 492 are primitive Up to a perimeter of 7500 there are 3491 triples, of which 527 are primitive Up to a perimeter of 8000 there are 3763 triples, of which 560 are primitive Up to a perimeter of 8500 there are 4029 triples, of which 597 are primitive Up to a perimeter of 9000 there are 4304 triples, of which 631 are primitive Up to a perimeter of 9500 there are 4577 triples, of which 667 are primitive Up to a perimeter of 10000 there are 4858 triples, of which 703 are primitive Up to a perimeter of 10500 there are 5138 triples, of which 736 are primitive Up to a perimeter of 11000 there are 5414 triples, of which 770 are primitive Up to a perimeter of 11500 there are 5699 triples, of which 804 are primitive Up to a perimeter of 12000 there are 5980 triples, of which 839 are primitive Up to a perimeter of 12500 there are 6263 triples, of which 877 are primitive Up to a perimeter of 13000 there are 6559 triples, of which 913 are primitive Up to a perimeter of 13500 there are 6843 triples, of which 949 are primitive Up to a perimeter of 14000 there are 7129 triples, of which 983 are primitive Up to a perimeter of 14500 there are 7420 triples, of which 1019 are primitive Up to a perimeter of 15000 there are 7714 triples, of which 1055 are primitive Up to a perimeter of 15500 there are 8004 triples, of which 1089 are primitive Up to a perimeter of 16000 there are 8304 triples, of which 1127 are primitive Up to a perimeter of 16500 there are 8595 triples, of which 1159 are primitive Up to a perimeter of 17000 there are 8884 triples, of which 1192 are primitive Up to a perimeter of 17500 there are 9189 triples, of which 1228 are primitive Up to a perimeter of 18000 there are 9484 triples, of which 1264 are primitive Up to a perimeter of 18500 there are 9791 triples, of which 1301 are primitive Up to a perimeter of 19000 there are 10088 triples, of which 1336 are primitive Up to a perimeter of 19500 there are 10388 triples, of which 1373 are primitive Up to a perimeter of 20000 there are 10689 triples, of which 1408 are primitive
Barebone minimum for this task:<lang Python>from sys import setrecursionlimit setrecursionlimit(2000) # 2000 ought to be big enough for everybody
def triples(lim, a = 3, b = 4, c = 5): l = a + b + c if l > lim: return (0, 0) return reduce(lambda x, y: (x[0] + y[0], x[1] + y[1]), [ (1, lim / l), triples(lim, a - 2*b + 2*c, 2*a - b + 2*c, 2*a - 2*b + 3*c), triples(lim, a + 2*b + 2*c, 2*a + b + 2*c, 2*a + 2*b + 3*c), triples(lim, -a + 2*b + 2*c, -2*a + b + 2*c, -2*a + 2*b + 3*c) ])
for peri in [10 ** e for e in range(1, 8)]: print peri, triples(peri)</lang>Output:<lang>10 (0, 0) 100 (7, 17) 1000 (70, 325) 10000 (703, 4858) 100000 (7026, 64741) 1000000 (70229, 808950) 10000000 (702309, 9706567)</lang>
REXX
version 1
A brute force approach. <lang rexx>/*REXX pgm counts number of Pythagorean triples that exist given a max */ /* perimeter of N, and also counts how many of them are primitives.*/ trips=0; prims=0 parse arg N .; if N== then n=100 /*get "N". If none, then assume.*/
do a=3 to N%3; aa=a*a /*limit side to 1/3 of perimeter.*/
do b=a+1 /*triangle can't be isosceles. */ ab=a+b /*compute partial perimeter. */ if ab>=n then iterate a /*a+b>perimeter? Try different A*/ aabb=aa+b*b /*compute sum of a² + b² (cheat)*/
do c=b+1; cc=c*c /*3rd side: also compute c² */ if ab+c>n then iterate a /*a+b+c > perimeter? Try diff A.*/ if cc>aabb then iterate b /*c² > a²+b² ? Try different B.*/ if cc\==aabb then iterate /*c² ¬= a²+b² ? Try different C.*/ trips=trips+1 /*eureka. */ prims=prims+(gcd(a,b)==1) /*is this triple a primative ? */ end /*a*/ end /*b*/ end /*c*/
say 'max perimeter = 'N, /*show a single line of output. */
left(,7) "Pythagorean triples =" trips, /*left(,0) ≡ 7 blanks.*/ left(,7) 'primitives =' prims
exit /*stick a fork in it, we're done.*/ /*──────────────────────────────────GCD subroutine──────────────────────*/ gcd: procedure; arg x,y; do until _==0; _=x//y; x=y; y=_; end; return x</lang> output when using the default input of 100
max perimeter = 100 Pythagorean triples = 17 primitives = 7
output when using the input of: 1000
max perimeter = 1000 Pythagorean triples = 325 primitives = 70
version 2
Also a brute force approach.
This REXX version takes advantage that primitive Pythagorean triples must have one and only one even number.
Non-primitive Pythagorean triples are generated after a primitive triple is found.
<lang rexx>/*REXX pgm counts number of Pythagorean triples that exist given a max */
/* perimeter of N, and also counts how many of them are primatives.*/
@.=0; trips=0; prims=0
parse arg N .; if N== then n=100 /*get "N". If none, then assume.*/
do a=3 to N%3; aa=a*a /*limit side to 1/3 of perimeter.*/ aEven=a//2==0
do b=a+1 by 1+aEven /*triangle can't be isosceles. */ ab=a+b /*compute partial perimeter. */ if ab>=n then iterate a /*a+b>perimeter? Try different A*/ aabb=aa+b*b /*compute sum of a² + b² (cheat)*/
do c=b+1; cc=c*c /*3rd side: also compute c² */ if aEven then if c//2==0 then iterate if ab+c>n then iterate a /*a+b+c > perimeter? Try diff A.*/ if cc>aabb then iterate b /*c² > a²+b² ? Try different B.*/ if cc\==aabb then iterate /*c² ¬= a²+b² ? Try different C.*/ if @.a.b.c then iterate trips=trips+1 /*eureka. */ prims=prims+1 /*count this primitive triple. */
do m=2; !a=a*m; !b=b*m; !c=c*m /*gen non-primitives.*/ if !a+!b+!c>N then leave /*is this multiple a triple ? */ trips=trips+1 /*yuppers, then we found another.*/ if m//2 then @.!a.!b.!c=1 /*don't mark if an even multiple.*/ end /*m*/ end /*d*/ end /*b*/ end /*a*/
say 'max perimeter = 'N, /*show a single line of output. */
left(,7) "Pythagorean triples =" trips, /*left(,0) = 7 blanks.*/ left(,7) 'primitives =' prims /*stick a fork in it, we're done.*/</lang>
output is identical to version 1.
Ruby
<lang ruby>class PythagoranTriplesCounter
def initialize(limit) @limit = limit @total = 0 @primatives = 0 generate_triples(3, 4, 5) end attr_reader :total, :primatives private def generate_triples(a, b, c) perim = a + b + c return if perim > @limit
@primatives += 1 @total += @limit / perim
generate_triples( a-2*b+2*c, 2*a-b+2*c, 2*a-2*b+3*c) generate_triples( a+2*b+2*c, 2*a+b+2*c, 2*a+2*b+3*c) generate_triples(-a+2*b+2*c,-2*a+b+2*c,-2*a+2*b+3*c) end
end
perim = 10 while perim <= 100_000_000
c = PythagoranTriplesCounter.new perim p [perim, c.total, c.primatives] perim *= 10
end</lang>
output
[10, 0, 0] [100, 17, 7] [1000, 325, 70] [10000, 4858, 703] [100000, 64741, 7026] [1000000, 808950, 70229] [10000000, 9706567, 702309] [100000000, 113236940, 7023027]
Seed7
The example below uses bigInteger numbers:
<lang seed7>$ include "seed7_05.s7i";
include "bigint.s7i";
var bigInteger: total is 0_; var bigInteger: prim is 0_; var bigInteger: max_peri is 10_;
const proc: new_tri (in bigInteger: a, in bigInteger: b, in bigInteger: c) is func
local var bigInteger: p is 0_; begin p := a + b + c; if p <= max_peri then incr(prim); total +:= max_peri div p; new_tri( a - 2_*b + 2_*c, 2_*a - b + 2_*c, 2_*a - 2_*b + 3_*c); new_tri( a + 2_*b + 2_*c, 2_*a + b + 2_*c, 2_*a + 2_*b + 3_*c); new_tri(-a + 2_*b + 2_*c, -2_*a + b + 2_*c, -2_*a + 2_*b + 3_*c); end if; end func;
const proc: main is func
begin while max_peri <= 100000000_ do total := 0_; prim := 0_; new_tri(3_, 4_, 5_); writeln("Up to " <& max_peri <& ": " <& total <& " triples, " <& prim <& " primitives."); max_peri *:= 10_; end while; end func;</lang>
Output:
Up to 10: 0 triples, 0 primitives. Up to 100: 17 triples, 7 primitives. Up to 1000: 325 triples, 70 primitives. Up to 10000: 4858 triples, 703 primitives. Up to 100000: 64741 triples, 7026 primitives. Up to 1000000: 808950 triples, 70229 primitives. Up to 10000000: 9706567 triples, 702309 primitives. Up to 100000000: 113236940 triples, 7023027 primitives.
Tcl
Using the efficient method based off the Wikipedia article: <lang tcl>proc countPythagoreanTriples {limit} {
lappend q 3 4 5 set idx [set count [set prim 0]] while {$idx < [llength $q]} {
set a [lindex $q $idx] set b [lindex $q [incr idx]] set c [lindex $q [incr idx]] incr idx if {$a + $b + $c <= $limit} { incr prim for {set i 1} {$i*$a+$i*$b+$i*$c <= $limit} {incr i} { incr count } lappend q \ [expr {$a + 2*($c-$b)}] [expr {2*($a+$c) - $b}] [expr {2*($a-$b) + 3*$c}] \ [expr {$a + 2*($b+$c)}] [expr {2*($a+$c) + $b}] [expr {2*($a+$b) + 3*$c}] \ [expr {2*($b+$c) - $a}] [expr {2*($c-$a) + $b}] [expr {2*($b-$a) + 3*$c}] }
} return [list $count $prim]
} for {set i 10} {$i <= 10000000} {set i [expr {$i*10}]} {
lassign [countPythagoreanTriples $i] count primitive puts "perimeter limit $i => $count triples, $primitive primitive"
}</lang> Output:
perimeter limit 10 => 0 triples, 0 primitive perimeter limit 100 => 17 triples, 7 primitive perimeter limit 1000 => 325 triples, 70 primitive perimeter limit 10000 => 4858 triples, 703 primitive perimeter limit 100000 => 64741 triples, 7026 primitive perimeter limit 1000000 => 808950 triples, 70229 primitive perimeter limit 10000000 => 9706567 triples, 702309 primitive
- Programming Tasks
- Solutions by Programming Task
- Ada
- Bracmat
- C
- CoffeeScript
- Common Lisp
- D
- Erlang
- Euphoria
- Factor
- Fortran
- Go
- Icon
- Unicon
- Icon Programming Library
- Haskell
- J
- Java
- Arbitrary precision
- Liberty BASIC
- MATLAB
- Octave
- Modula-3
- OCaml
- PARI/GP
- Pascal
- Perl 6
- PicoLisp
- PureBasic
- Python
- REXX
- Ruby
- Seed7
- Tcl
- Pages that use a deprecated format of the math tags