Another update from ingydotnet^djgoku

This commit is contained in:
Ingy döt Net 2015-11-18 06:14:39 +00:00
parent 91df62d461
commit 948b86eafa
7604 changed files with 108452 additions and 22726 deletions

View file

@ -0,0 +1,66 @@
#!/bin/gawk -f
function sumprop(num, i,sum,root) {
if (num == 1) return 0
sum=1
root=sqrt(num)
for ( i=2; i < root; i++) {
if (num % i == 0 )
{
sum = sum + i + num/i
}
}
if (num % root == 0)
{
sum = sum + root
}
return sum
}
function class(k, oldk,newk,seq){
# first term
oldk = k
seq = " "
# second term
newk = sumprop(oldk)
oldk = newk
seq = seq " " newk
if (newk == 0) return "terminating " seq
if (newk == k) return "perfect " seq
# third term
newk = sumprop(oldk)
oldk = newk
seq = seq " " newk
if (newk == 0) return "terminating " seq
if (newk == k) return "amicable " seq
for (t=4; t<17; t++) {
newk = sumprop(oldk)
seq = seq " " newk
if (newk == 0) return "terminating " seq
if (newk == k) return "sociable (period " t-1 ") "seq
if (newk == oldk) return "aspiring " seq
if (index(seq," " newk " ") > 0) return "cyclic (at " newk ") " seq
if (newk > 140737488355328) return "non-terminating (term > 140737488355328) " seq
oldk = newk
}
return "non-terminating (after 16 terms) " seq
}
BEGIN{
print "Number classification sequence"
for (j=1; j < 11; j++)
{
print j,class(j)}
print 11,class(11)
print 12,class(12)
print 28,class(28)
print 496,class(496)
print 220,class(220)
print 1184,class(1184)
print 12496,class(12496)
print 1264460,class(1264460)
print 790,class(790)
print 909,class(909)
print 562,class(562)
print 1064,class(1064)
print 1488,class(1488)
print 15355717786080,class(15355717786080)
}

View file

@ -0,0 +1,123 @@
MODULE FACTORSTUFF !This protocol evades the need for multiple parameters, or COMMON, or one shapeless main line...
Concocted by R.N.McLean, MMXV.
c INTEGER*4 I4LIMIT
c PARAMETER (I4LIMIT = 2147483647)
INTEGER*8 TOOBIG !Some bounds.
PARAMETER (TOOBIG = 2**47) !Computer arithmetic is not with real numbers.
INTEGER LOTS !Nor is computer storage infinite.
PARAMETER (LOTS = 10000) !So there can't be all that many of these.
INTEGER*8 KNOWNSUM(LOTS) !If multiple references are expected, it is worthwhile calculating these.
CONTAINS !Assistants.
INTEGER*8 FUNCTION SUMF(N) !Sum of the proper divisors of N.
INTEGER*8 N !The number in question.
INTEGER*8 F,F2 !Candidate factor, and its square.
INTEGER*8 S,INC,BOOST !Assistants.
IF (N.LE.LOTS) THEN !If we're within reach,
SUMF = KNOWNSUM(N) !The result is to hand.
ELSE !Otherwise, some on-the-spot effort ensues.
Could use SUMF in place of S, but some compilers have been confused by such usage.
S = 1 !1 is always a factor of N, but N is deemed not proper.
F = 1 !Prepare a crude search for factors.
INC = 1 !One by plodding one.
IF (MOD(N,2) .EQ. 1) INC = 2!Ah, but an odd number cannot have an even number as a divisor.
1 F = F + INC !So half the time we can doubleplod.
F2 = F*F !Up to F2 < N rather than F < SQRT(N) and worries over inexact arithmetic.
IF (F2 .LT. N) THEN !F2 = N handled below.
IF (MOD(N,F) .EQ. 0) THEN !Does F divide N?
BOOST = F + N/F !Yes. The divisor and its counterpart.
IF (S .GT. TOOBIG - BOOST) GO TO 666 !Would their augmentation cause an overflow?
S = S + BOOST !No, so count in the two divisors just discovered.
END IF !So much for a divisor discovered.
GO TO 1 !Try for another.
END IF !So much for N = p*q style factors.
IF (F2 .EQ. N) THEN !Special case: N may be a perfect square, not necessarily of a prime number.
IF (S .GT. TOOBIG - F) GO TO 666 !It is. And it too might cause overflow.
S = S + F !But if not, count F once only.
END IF !All done.
SUMF = S !This is the result.
END IF !Whichever way obtained,
RETURN !Done.
Cannot calculate the sum, because it exceeds the INTEGER*8 limit.
666 SUMF = -666 !An expression of dismay that the caller will notice.
END FUNCTION SUMF !Alternatively, find the prime factors, and combine them...
SUBROUTINE PREPARESUMF !Initialise the KNOWNSUM array.
Convert the Sieve of Eratoshenes to have each slot contain the sum of the proper divisors of its slot number.
Changes to instead count the number of factors, or prime factors, etc. would be simple enough.
INTEGER*8 F !A factor for numbers such as 2F, 3F, 4F, 5F, ...
KNOWNSUM(1) = 0 !Proper divisors of N do not include N.
KNOWNSUM(2:LOTS) = 1 !So, although 1 divides all N without remainder, 1 is excluded for itself.
DO F = 2,LOTS/2 !Step through all the possible divisors of numbers not exceeding LOTS.
FORALL(I = F + F:LOTS:F) KNOWNSUM(I) = KNOWNSUM(I) + F !And augment each corresponding slot.
END DO !Different divisors can hit the same slot. For instance, 6 by 2 and also by 3.
END SUBROUTINE PREPARESUMF !Could alternatively generate all products of prime numbers.
SUBROUTINE CLASSIFY(N) !Traipse along the SumF trail.
INTEGER*8 N !The starter.
INTEGER ROPE !The size of my memory is not so great..
PARAMETER(ROPE = 16) !Indeed, this is strictly limited.
INTEGER*8 TRAIL(ROPE) !But the numbers can be large.
INTEGER*8 SF !The working sum of proper divisors.
INTEGER I,L !Indices, merely.
CHARACTER*28 THIS !A perfect scratchpad for remarks.
L = 1 !Every journey starts with its first step.
TRAIL(1) = N !Which is this.
SF = N !Syncopation.
10 SF = SUMF(SF) !Step onwards.
IF (SF .LT. 0) THEN !Trouble?
WRITE (THIS,11) L,"overflows!" !Yes. Too big a number.
11 FORMAT ("After ",I0,", ",A) !Describe the situation.
CALL REPORT(ADJUSTR(THIS)) !And give the report.
ELSE IF (SF .EQ. 0) THEN !Otherwise, a finish?
WRITE (THIS,11) L,"terminates!" !Yay!
CALL REPORT(ADJUSTR(THIS)) !This sequence is finished.
ELSE IF (ANY(TRAIL(1:L) .EQ. SF)) THEN !Otherwise, is there an echo somewhere?
IF (L .EQ. 1) THEN !Yes!
CALL REPORT("Perfect!") !Are we at the start?
ELSE IF (L .EQ. 2) THEN !Or perhaps not far along.
CALL REPORT("Amicable:") !These are held special.
ELSE !Otherwise, we've wandered further along.
I = MINLOC(ABS(TRAIL(1:L) - SF),DIM=1) !Damnit, re-scan the array to finger the first matching element.
IF (I .EQ. 1) THEN !If all the way back to the start,
WRITE (THIS,12) L !Then there are this many elements in the sociable ring.
12 FORMAT ("Sociable ",I0,":") !Computers are good at counting.
CALL REPORT(ADJUSTR(THIS)) !So, perform an added service.
ELSE IF (I .EQ. L) THEN !Perhaps we've hit a perfect number!
CALL REPORT("Aspiring:") !A cycle of length one.
ELSE !But otherwise,
WRITE (THIS,13) L - I + 1,SF !A longer cycle. Amicable, or sociable.
13 FORMAT ("Cyclic end ",I0,", to ",I0,":") !Name the flashback value too.
CALL REPORT(ADJUSTR(THIS)) !Thus.
END IF !So much for cycles.
END IF !So much for finding an echo.
ELSE !Otherwise, nothing special has happened.
IF (L .GE. ROPE) THEN !So, how long is a piece of string?
WRITE (THIS,11) L,"non-terminating?" !Not long enough!
CALL REPORT(ADJUSTR(THIS)) !So we give up.
ELSE !But if there is more scope,
L = L + 1 !Advance one more step.
TRAIL(L) = SF !Save the latest result.
GO TO 10 !And try for the next.
END IF !So much for continuing.
END IF !So much for the classification.
RETURN !Finished.
CONTAINS !Not quite.
SUBROUTINE REPORT(WHAT) !There is this service routine.
CHARACTER*(*) WHAT !Whatever the length of the text, the FORMAT's A28 shows 28 characters, right-aligned.
WRITE (6,1) WHAT,TRAIL(1:L)!Mysteriously, a fresh line after every twelve elements.
1 FORMAT (A28,1X,12(I0:",")) !And obviously, the : signifies "do not print what follows unless there is another number to go.
END SUBROUTINE REPORT !That was easy.
END SUBROUTINE CLASSIFY !Enough.
END MODULE FACTORSTUFF !Enough assistants.
PROGRAM CLASSIFYTHEM !Report on the nature of the sequence N, Sumf(N), Sumf(Sumf(N)), etc.
USE FACTORSTUFF !This should help.
INTEGER*8 I,N !Steppers.
INTEGER*8 THIS(14) !A testing collection.
DATA THIS/11,12,28,496,220,1184,12496,1264460,790,909, !Old-style continuation character in column six.
1 562,1064,1488,15355717786080/ !Monster value far exceeds the INTEGER*4 limit
CALL PREPARESUMF !Prepare for 1:LOTS, even though this test run will use only a few.
DO I = 1,10 !As specified, the first ten integers.
CALL CLASSIFY(I)
END DO
DO I = 1,SIZE(THIS) !Now for the specified list.
CALL CLASSIFY(THIS(I))
END DO
END !Done.

View file

@ -0,0 +1,24 @@
function aliquotclassifier{T<:Integer}(n::T)
a = T[n]
b = divisorsum(a[end])
len = 1
while len < 17 && !(b in a) && 0 < b && b < 2^47+1
push!(a, b)
b = divisorsum(a[end])
len += 1
end
if b in a
1 < len || return ("Perfect", a)
if b == a[1]
2 < len || return ("Amicable", a)
return ("Sociable", a)
elseif b == a[end]
return ("Aspiring", a)
else
return ("Cyclic", push!(a, b))
end
end
push!(a, b)
b != 0 || return ("Terminating", a)
return ("Non-terminating", a)
end

View file

@ -0,0 +1,17 @@
function pcontrib{T<:Integer}(p::T, a::T)
n = one(T)
pcon = one(T)
for i in 1:a
n *= p
pcon += n
end
return pcon
end
function divisorsum{T<:Integer}(n::T)
dsum = one(T)
for (p, a) in factor(n)
dsum *= pcontrib(p, a)
end
dsum -= n
end

View file

@ -0,0 +1,6 @@
println("Classification Tests:")
tests = [1:12, 28, 496, 220, 1184, 12496, 1264460, 790, 909, 562, 1064, 1488]
for i in tests
(class, a) = aliquotclassifier(i)
println(@sprintf("%8d => ", i), @sprintf("%16s, ", class), a)
end

View file

@ -0,0 +1,19 @@
seq[n_] :=
NestList[If[# == 0, 0,
DivisorSum[#, # &, Function[div, div != #]]] &, n, 16];
class[seq_] :=
Which[Length[seq] < 2, "Non-terminating", MemberQ[seq, 0],
"Terminating", seq[[1]] == seq[[2]], "Perfect",
Length[seq] > 2 && seq[[1]] == seq[[3]], "Amicable",
Length[seq] > 3 && MemberQ[seq[[4 ;;]], seq[[1]]], "Sociable",
MatchQ[class[Rest[seq]], "Perfect" | "Aspiring"], "Aspiring",
MatchQ[class[Rest[seq]], "Amicable" | "Sociable" | "Cyclic"],
"Cyclic", True, "Non-terminating"];
notate[seq_] :=
Which[seq == {}, {},
MemberQ[Rest[seq],
seq[[1]]], {Prepend[TakeWhile[Rest[seq], # != seq[[1]] &],
seq[[1]]]}, True, Prepend[notate[Rest[seq]], seq[[1]]]];
Print[{#, class[seq[#]], notate[seq[#]] /. {0} -> 0}] & /@ {1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 28, 496, 220, 1184, 12496, 1264460, 790, 909,
562, 1064, 1488, 15355717786080};

View file

@ -13,13 +13,13 @@ multi quality ($,$n) { "cyclic-$n" }
sub aliquotidian ($x) {
my %seen;
my @seq := $x, &propdivsum ... *;
my @seq = $x, &propdivsum ... *;
for 0..16 -> $to {
my $this = @seq[$to] or return "$x terminating [@seq[^$to]]";
my $this = @seq[$to] or return "$x\tterminating\t[@seq[^$to]]";
last if $this > 140737488355328;
if %seen{$this}:exists {
my $from = %seen{$this};
return "$x &quality($from, $to-$from) [@seq[^$to]]";
return "$x\t&quality($from, $to-$from)\t[@seq[^$to]]";
}
%seen{$this} = $to;
}
@ -27,7 +27,7 @@ sub aliquotidian ($x) {
}
aliquotidian($_).say for
aliquotidian($_).say for flat
1..10,
11, 12, 28, 496, 220, 1184, 12496, 1264460,
790, 909, 562, 1064, 1488,

View file

@ -1,62 +1,63 @@
/*REXX pgm classifies various positive integers for aliquot sequences. */
parse arg low high L /*get optional arguments*/
/*REXX program classifies various positive integers for aliquot sequences. */
parse arg low high L /*get some optional arguments.*/
high=word(high low 10,1); low=word(low 1,1) /*get the LOW and HIGH. */
if L='' then L=11 12 28 496 220 1184 12496 1264460 790 909 562 1064 1488
big=2**47; NTlimit=16+1 /*limit: non-terminating*/
numeric digits max(9, 1+length(big)) /*be able to handle // */
@.=.; @.0=0; @.1=0 /*proper divisor sums. */
if L='' then L=11 12 28 496 220 1184 12496 1264460 790 909 562 1064 1488 15355717786080
big=2**47; NTlimit=16+1 /*seq. non─terminating limit. */
numeric digits max(9, 1+length(big)) /*be able to handle // oper.*/
#.=.; #.0=0; #.1=0 /*#. are proper divisor sums.*/
say center('numbers from ' low " to " high, 79, "")
do n=low to high /*process probably some low nums.*/
call classify_aliquot n /*call subroutine to classify it.*/
end /*n*/ /* [↑] process a range of ints.*/
do n=low to high /*process (probably) some low numbers. */
call classify_aliquot n /*call a subroutine to classify number.*/
end /*n*/ /* [↑] process a range of integers. */
say
say center('first numbers for each classification', 79, "")
b.=0 /* [↓] ensure one of each class.*/
do q=1 until b.sociable \== 0 /*only one that has to be counted*/
call classify_aliquot -q /*the minus sign indicates ¬tell.*/
b._=b._+1; if b._==1 then call show_class q,$ /*show 1st found.*/
end /*q*/ /* [↑] until all classes found. */
b.=0 /* [↓] ensure one number of each class*/
do q=1 until b.sociable \== 0 /*the only one that has to be counted. */
call classify_aliquot -q /*the minus (-) sign indicates ¬ tell. */
_=what; upper _; b._=b._+1 /*bump the counter for this seq. class.*/
if b._==1 then call show_class q,$ /*show the first occurrence only.*/
end /*q*/ /* [↑] process until all classes found*/
say
say center('classifications for specific numbers', 79, "")
do i=1 for words(L) /*L is a list of "special numbers*/
call classify_aliquot word(L,i) /*call subroutine to classify it.*/
end /*i*/ /* [↑] process a list of numbers*/
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────CLASSIFY_ALIQUOT subroutine─────────*/
classify_aliquot: parse arg a 1 aa; a=abs(a) /*get what # to be used.*/
if @.a\==. then s=@.a /*Was number been summed before? */
else s=SPdivs(a) /*No, then do it the hard way. */
@.a=s; $=s /*define sum of the proper DIVs. */
what='terminating' /*assume this classification kind*/
c.=0; c.s=1 /*clear all cyclic seqs, set 1st.*/
if $==a then what='perfect' /*check for "perfect" number. */
else do t=1 while s\==0 /*loop until sum isn't 0 or >big.*/
m=word($, words($)) /*obtain the last number in seq. */
if @.m==. then s=SPdivs(m) /*if ¬defined, then sum Pdivs.*/
else s=@.m /*use the previously found number*/
if m==s & m\==0 then do; what='aspiring' ; leave; end
if word($,2)==a then do; what='amicable' ; leave; end
$=$ s /*append a sum to number sequence*/
if s==a & t>3 then do; what='sociable' ; leave; end
if c.s & m\==0 then do; what='cyclic' ; leave; end
c.s=1 /*assign another possible cyclic.*/
/* [↓] Rosetta Code's limit: >16*/
if t>NTlimit then do; what='non-terminating'; leave; end
if s>big then do; what='NON-TERMINATING'; leave; end
end /*t*/ /* [↑] only permit within reason*/
if aa>0 then call show_class a,$ /*only display if A is positive.*/
do i=1 for words(L) /*L is a list of "special numbers". */
call classify_aliquot word(L,i) /*call a subroutine to classify number.*/
end /*i*/ /* [↑] process a list of integers. */
exit /*stick a fork in it, we're all done. */
/*────────────────────────────────────────────────────────────────────────────*/
classify_aliquot: parse arg a 1 aa; a=abs(a) /*get what number is to be used.*/
if #.a\==. then s=#.a /*Was this number been summed before? */
else s=sigma(a) /*No, then classify number the hard way*/
#.a=s; $=s /*define sum of the proper divisors. */
what='terminating' /*assume this kind of classification. */
c.=0; c.s=1 /*clear all cyclic sequences; set 1st.*/
if $==a then what='perfect' /*check for a "perfect" number. */
else do t=1 while s\==0 /*loop until sum isn't 0 or > big.*/
m=word($, words($)) /*obtain the last number in sequence. */
if #.m==. then s=sigma(m) /*if not defined, then sum proper divs.*/
else s=#.m /*use the previously found integer. */
if m==s & m\==0 then do; what='aspiring' ; leave; end
if word($,2)==a then do; what='amicable' ; leave; end
$=$ s /*append a sum to the integer sequence.*/
if s==a & t>3 then do; what='sociable' ; leave; end
if c.s & m\==0 then do; what='cyclic' ; leave; end
c.s=1 /*assign another possible cyclic number*/
/* [↓] Rosetta Code task's limit: >16 */
if t>NTlimit then do; what='non-terminating'; leave; end
if s>big then do; what='NON-TERMINATING'; leave; end
end /*t*/ /* [↑] only permit within reason. */
if aa>0 then call show_class a,$ /*only display if A is positive. */
return
/*──────────────────────────────────SHOW_CLASS subroutine───────────────*/
show_class: say right(arg(1),digits()) 'is' center(what,15) arg(2); return
/*──────────────────────────────────SPDIVS subroutine───────────────────*/
SPdivs: procedure expose @.; parse arg x; if x<2 then return 0; odd=x//2
s=1 /* [↓] use only EVEN|ODD integers*/
do j=2+odd by 1+odd while j*j<x /*divide by all integers up to √x*/
if x//j==0 then s=s+j+ x%j /*add the two divisors to the sum*/
end /*j*/ /* [↑] % is REXX integer divide*/
/* [↓] adjust for square. _ */
if j*j==x then s=s+j /*Was X a square? If so, add √x.*/
@.x=s /*define the sum for the arg X. */
return s /*return divisors (both lists). */
/*────────────────────────────────────────────────────────────────────────────*/
show_class: say right(arg(1),digits()) 'is' center(what,15) arg(2); return
/*────────────────────────────────────────────────────────────────────────────*/
sigma: procedure expose #.; parse arg x; if x<2 then return 0; odd=x//2
s=1 /* [↓] use only EVEN|ODD ints. ___*/
do j=2+odd by 1+odd while j*j<x /*divide by all the integers up to √ X */
if x//j==0 then s=s+j+ x%j /*add the two divisors to the sum. */
end /*j*/ /* [↑] % is the REXX integer division*/
/* [↓] adjust for square. ___ */
if j*j==x then s=s+j /*Was X a square? If so, add √ X */
#.x=s /*define the sum for the argument X. */
return s /*return the sum of the divisors of X.*/

View file

@ -0,0 +1,45 @@
#[derive(Debug)]
enum AliquotType { Terminating, Perfect, Amicable, Sociable, Aspiring, Cyclic, NonTerminating }
fn classify_aliquot(num: i64) -> (AliquotType, Vec<i64>) {
let limit = 1i64 << 47; //140737488355328
let mut terms = Some(num).into_iter().collect::<Vec<_>>();
for i in 0..16 {
let n = terms[i];
let divsum = (1..(n + 1) / 2 + 1).filter(|&x| n % x == 0 && n != x).fold(0, |sum, x| sum + x);
let classification = if divsum == 0 {
Some(AliquotType::Terminating)
}
else if divsum > limit {
Some(AliquotType::NonTerminating)
}
else if let Some(prev_idx) = terms.iter().position(|&x| x == divsum) {
let cycle_len = terms.len() - prev_idx;
Some(if prev_idx == 0 {
match cycle_len {
1 => AliquotType::Perfect,
2 => AliquotType::Amicable,
_ => AliquotType::Sociable
}
}
else {
if cycle_len == 1 {AliquotType::Aspiring} else {AliquotType::Cyclic}
})
}
else {
None
};
terms.push(divsum);
if let Some(result) = classification {
return (result, terms);
}
}
(AliquotType::NonTerminating, terms)
}
fn main() {
let nums = [1i64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 28, 496, 220, 1184, 12496, 1264460, 790, 909, 562, 1064, 1488/*, 15355717786080*/];
for num in &nums {
println!("{} {:?}", num, classify_aliquot(*num));
}
}

View file

@ -0,0 +1,73 @@
proc ProperDivisors {n} {
if {$n == 1} {return 0}
set divs 1
set sum 1
for {set i 2} {$i*$i <= $n} {incr i} {
if {! ($n % $i)} {
lappend divs $i
incr sum $i
if {$i*$i<$n} {
lappend divs [set d [expr {$n / $i}]]
incr sum $d
}
}
}
list $sum $divs
}
proc al_iter {n} {
yield [info coroutine]
while {$n} {
yield $n
lassign [ProperDivisors $n] n
}
yield 0
return -code break
}
proc al_classify {n} {
coroutine iter al_iter $n
set items {}
try {
set type "non-terminating"
while {[llength $items] < 16} {
set i [iter]
if {$i == 0} {
set type "terminating"
}
set ix [lsearch -exact $items $i]
set items [linsert $items 0 $i]
switch $ix {
-1 { continue }
0 { throw RESULT "perfect" }
1 { throw RESULT "amicable" }
default { throw RESULT "sociable" }
}
}
} trap {RESULT} {type} {
rename iter {}
set map {
perfect aspiring
amicable cyclic
sociable cyclic
}
if {$ix != [llength $items]-2} {
set type [dict get $map $type]
}
}
list $type [lreverse $items]
}
for {set i 1} {$i <= 10} {incr i} {
puts [format "%8d -> %-16s : %s" $i {*}[al_classify $i]]
}
foreach i {11 12 28 496 220 1184 12496 1264460 790 909 562 1064 1488 } {
puts [format "%8d -> %-16s : %s" $i {*}[al_classify $i]]
}
;# stretch goal .. let's time it:
set i 15355717786080
puts [time {
puts [format "%8d -> %-16s : %s" $i {*}[al_classify $i]]
}]