Perfect numbers: Difference between revisions

→‎{{header|REXX}}: added optimized versions. -- ~~~~
m (→‎{{header|COBOL}}: perfect prototype is not needed.)
(→‎{{header|REXX}}: added optimized versions. -- ~~~~)
Line 1,232:
<lang rexx>/*REXX program tests if a number (or a range of numbers) is/are perfect.*/
parse arg low high . /*obtain the specified number(s).*/
if high=='' & low=='' then high=34000000 /*if no args, use a range.*/
if low=='' then low=1 then low=1 /*if no LOW, then assume unity.*/
if high=='' then high=low then high=low /*if no HIGH, then assume LOW. */
w=length(high) /*use W for formatting output. */
numeric digits max(9,w+2) /*ensure enough digits to handle#*/
 
do i=low to high /*process the single # or range. */
if isperfect(i) then say right(i,w) 'is a perfect number.'
end /*i*/
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────ISPERFECT subroutine────────────────*/
isperfect: procedure; parse arg x /*get the number to be tested. */
if x<6 then return 0 /*perfect numbers can't be < six.*/
sums=1 /*the first factor of X. */
do j=2 while j*j<=x /*starting at 2, find factors ≤√X*/
if x//j\==0 then iterate /*J isn't dividesa factor of X evenly, so skip... */
s sum=sum s + j + x%j /*...··· add it and the other factor*/
if sums>x then return 0 /*Sum too big? It ain't perfect.*/
end /*j*/ /*(above) is marginally faster. */
return sums==x /*if the sum matches X, perfect! */</lang>
'''output''' using the defaults
<pre>
Line 1,260:
33550336 is a perfect number.
</pre>
===optimized using digital root===
<lang rexx>/*REXX program tests if a number (or a range of numbers) is/are perfect.*/
parse arg low high . /*obtain the specified number(s).*/
if high=='' & low=='' then high=34000000 /*if no args, use a range.*/
if low=='' then low=1 /*if no LOW, then assume unity.*/
if high=='' then high=low /*if no HIGH, then assume LOW. */
w=length(high) /*use W for formatting output. */
numeric digits max(9,w+2) /*ensure enough digits to handle#*/
 
do i=low to high /*process the single # or range. */
if isperfect(i) then say right(i,w) 'is a perfect number.'
end /*i*/
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────ISPERFECT subroutine────────────────*/
isperfect: procedure; parse arg x 1 y /*get the number to be tested. */
if x==6 then return 1 /*handle special case of six. */
if x<28 then return 0 /*now, perfect numbers must be>27*/
 
do until length(y)==1 /*find the digital root of Y. */
parse var y 1 r 2; do k=2 for length(y)-1; r=r+substr(y,k,1); end
y=r /*find digital root of dig root. */
end /*DO until*/ /*wash, rinse, repeat ··· */
 
if r\==1 then return 0 /*is dig root ¬1? Then ¬perfect.*/
s=1 /*the first factor of X. */
do j=2 while j*j<=x /*starting at 2, find factors ≤√X*/
if x//j\==0 then iterate /*J isn't a factor of X, so skip.*/
s = s + j + x%j /*··· add it and the other factor*/
if s>x then return 0 /*Sum too big? It ain't perfect.*/
end /*j*/ /*(above) is marginally faster. */
return s==x /*if the sum matches X, perfect! */</lang>
'''output''' is the same as version 1.
===optimized using only even numbers===
<lang rexx>/*REXX program tests if a number (or a range of numbers) is/are perfect.*/
parse arg low high . /*obtain the specified number(s).*/
if high=='' & low=='' then high=34000000 /*if no args, use a range.*/
if low=='' then low=1 /*if no LOW, then assume unity.*/
if high=='' then high=low /*if no HIGH, then assume LOW. */
w=length(high) /*use W for formatting output. */
numeric digits max(9,w+2) /*ensure enough digits to handle#*/
 
do i=low to high /*process the single # or range. */
if isperfect(i) then say right(i,w) 'is a perfect number.'
end /*i*/
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────ISPERFECT subroutine────────────────*/
isperfect: procedure; parse arg x 1 y /*get the number to be tested. */
if x//2 then return 0 /*handle special cases of odd #s.*/
if x==6 then return 1 /*handle special case of six. */
if x<28 then return 0 /*now, perfect numbers must be>27*/
 
do until length(y)==1 /*find the digital root of Y. */
parse var y 1 r 2; do k=2 for length(y)-1; r=r+substr(y,k,1); end
y=r /*find digital root of dig root. */
end /*DO until*/ /*wash, rinse, repeat ··· */
 
if r\==1 then return 0 /*is dig root ¬1? Then ¬perfect.*/
s=1 /*the first factor of X. */
do j=2 while j*j<=x /*starting at 2, find factors ≤√X*/
if x//j\==0 then iterate /*J isn't a factor of X, so skip.*/
s = s + j + x%j /*··· add it and the other factor*/
if s>x then return 0 /*Sum too big? It ain't perfect.*/
end /*j*/ /*(above) is marginally faster. */
return s==x /*if the sum matches X, perfect! */</lang>
'''output''' is the same as version 1.
===Lucas-Lehmer method===
This version uses memoization to implement a fast version of Lucas-Lehmer test,
Line 1,265 ⟶ 1,330:
<lang rexx>/*REXX program tests if a number (or a range of numbers) is/are perfect.*/
parse arg low high . /*obtain the specified number(s).*/
if high=='' & low=='' then high=34000000 /*if no args, use a range.*/
if low=='' then low=1 then low=1 /*if no LOW, then assume unity.*/
if high=='' then high=low then high=low /*if no HIGH, then assume LOW. */
w=length(high) /*use W for formatting output. */
numeric digits max(9,w+2) /*ensure enough digits to handle#*/
@.=0; @.1=2 /*highest magic # and its index.*/
do i=low to high /*process the single # or range. */
if isperfect(i) then say right(i,w) 'is a perfect number.'
end /*i*/
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────ISPERFECT subroutine────────────────*/
isperfect: procedure expose @.; parse arg x /*get the # to be tested.*/
if x//2==1 then return 0 /*if it's an odd number, it ain't*/
/*Lucas-Lehmer know that perfect */
/* numbers can be expressed as: */
Line 1,285 ⟶ 1,350:
end /*@.1*/ /*uses memoization for formula. */
 
if @.x==0 then return 0 /*Didn't pass Lucas-Lehmer test? */
sums=3+x%2 /*we know the following factors: */
/* 1 ('cause Mama said so.)*/
/* 2 ('cause it's even.) */
/* x÷2 " " " */
do j=3 while j*j<=x /*starting at 3, find factors ≤√X*/
if x//j\==0 then iterate /*J divides X evenly, so ... */
s sum=sum s + j + x%j /*...··· add it and the other factor*/
if sums>x then return 0 /*Sum too big? It ain't perfect.*/
end /*j*/ /*(above) is marginally faster. */
return sums==x /*if the sum matches X, perfect! */</lang>
'''output''' usingis the defaultssame as version 1.
<prebr><br>
6 is a perfect number.
28 is a perfect number.
496 is a perfect number.
8128 is a perfect number.
33550336 is a perfect number.
</pre>
 
=={{header|Ruby}}==