Zumkeller numbers are the set of numbers whose divisors can be partitioned into two disjoint sets that sum to the same value. Each sum must contain divisor values that are not in the other sum, and all of the divisors must be in one or the other. There are no restrictions on how the divisors are partitioned, only that the two partition sums are equal.



E.G.
 6 is a Zumkeller number; The divisors {1 2 3 6} can be partitioned into two groups {1 2 3} and {6} that both sum to 6.
 10 is not a Zumkeller number; The divisors {1 2 5 10} can not be partitioned into two groups in any way that will both sum to the same value.
 12 is a Zumkeller number; The divisors {1 2 3 4 6 12} can be partitioned into two groups {1 3 4 6} and {2 12} that both sum to 14.


Even Zumkeller numbers are common; odd Zumkeller numbers are much less so. For values below 10^6, there is at least one Zumkeller number in every 12 consecutive integers, and the vast majority of them are even. The odd Zumkeller numbers are very similar to the list from the task Abundant odd numbers; they are nearly the same except for the further restriction that the abundance (A(n) = sigma(n) - 2n), must be even: A(n) mod 2 == 0



Task

 Write a routine (function, procedure, whatever) to find Zumkeller numbers.
 Use the routine to find and display here, on this page, the first 220 Zumkeller numbers.
 Use the routine to find and display here, on this page, the first 40 odd Zumkeller numbers.
 Optional, stretch goal: Use the routine to find and display here, on this page, the first 40 odd Zumkeller numbers that don't end with 5.


See Also

 OEIS:A083207 - Zumkeller numbers to get an impression of different partitions OEIS:A083206 Zumkeller partitions
 OEIS:A174865 - Odd Zumkeller numbers


Related Tasks

 Abundant odd numbers
 Abundant, deficient and perfect number classifications
 Proper divisors , Factors of an integer
-- Sum n's proper divisors.
on aliquotSum(n)
    if (n < 2) then return 0
    set sum to 1
    set sqrt to n ^ 0.5
    set limit to sqrt div 1
    if (limit = sqrt) then
        set sum to sum + limit
        set limit to limit - 1
    end if
    repeat with i from 2 to limit
        if (n mod i is 0) then set sum to sum + i + n div i
    end repeat
 
    return sum
end aliquotSum
 
-- Return n's proper divisors.
on properDivisors(n)
    set output to {}
 
    if (n > 1) then
        set sqrt to n ^ 0.5
        set limit to sqrt div 1
        if (limit = sqrt) then
            set end of output to limit
            set limit to limit - 1
        end if
        repeat with i from limit to 2 by -1
            if (n mod i is 0) then
                set beginning of output to i
                set end of output to n div i
            end if
        end repeat
        set beginning of output to 1
    end if
 
    return output
end properDivisors
 
-- Does a subset of the given list of numbers add up to the target value?
on subsetOf:numberList sumsTo:target
    script o
        property lst : numberList
        property someNegatives : false
 
        on ssp(target, i)
            repeat while (i > 1)
                set n to item i of my lst
                set i to i - 1
                if ((n = target) or (((n < target) or (someNegatives)) and (ssp(target - n, i)))) then return true
            end repeat
            return (target = beginning of my lst)
        end ssp
    end script
    -- The search can be more efficient if it's known the list contains no negatives.
    repeat with n in o's lst
        if (n < 0) then
            set o's someNegatives to true
            exit repeat
        end if
    end repeat
 
    return o's ssp(target, count o's lst)
end subsetOf:sumsTo:
 
-- Is n a Zumkeller number?
on isZumkeller(n)
    -- Yes if its aliquot sum is greater than or equal to it, the difference between them is even, and
    -- either n is odd or a subset of its proper divisors sums to half the sum of the divisors and it.
    -- Using aliquotSum() to get the divisor sum and then calling properDivisors() too if a list's actually
    -- needed is generally faster than using properDivisors() in the first place and summing the result.
    set sum to aliquotSum(n)
    return ((sum ≥ n) and ((sum - n) mod 2 = 0) and ¬
        ((n mod 2 = 1) or (my subsetOf:(properDivisors(n)) sumsTo:((sum + n) div 2))))
end isZumkeller
 
-- Task code:
-- Find and return q Zumkeller numbers, starting the search at n and continuing at the
-- given interval, applying the Zumkeller test only to numbers passing the given filter.
on zumkellerNumbers(q, n, interval, filter)
    script o
        property zumkellers : {}
    end script
 
    set counter to 0
    repeat until (counter = q)
        if ((filter's OK(n)) and (isZumkeller(n))) then
            set end of o's zumkellers to n
            set counter to counter + 1
        end if
        set n to n + interval
    end repeat
 
    return o's zumkellers
end zumkellerNumbers
 
on joinText(textList, delimiter)
    set astid to AppleScript's text item delimiters
    set AppleScript's text item delimiters to delimiter
    set txt to textList as text
    set AppleScript's text item delimiters to astid
 
    return txt
end joinText
 
on formatForDisplay(resultList, heading, resultsPerLine, separator)
    script o
        property input : resultList
        property output : {heading}
    end script
 
    set len to (count o's input)
    repeat with i from 1 to len by resultsPerLine
        set j to i + resultsPerLine - 1
        if (j > len) then set j to len
        set end of o's output to joinText(items i thru j of o's input, separator)
    end repeat
 
    return joinText(o's output, linefeed)
end formatForDisplay
 
on doTask(cheating)
    set output to {}
    script noFilter
        on OK(n)
            return true
        end OK
    end script
    set header to "1st 220 Zumkeller numbers:"
    set end of output to formatForDisplay(zumkellerNumbers(220, 1, 1, noFilter), header, 20, "  ")
    set header to "1st 40 odd Zumkeller numbers:"
    set end of output to formatForDisplay(zumkellerNumbers(40, 1, 2, noFilter), header, 10, "  ")
 
    -- Stretch goal:
    set header to "1st 40 odd Zumkeller numbers not ending with 5:"
    script no5Multiples
        on OK(n)
            return (n mod 5 > 0)
        end OK
    end script
    if (cheating) then
        -- Knowing that the HCF of the first 203 odd Zumkellers not ending with 5
        -- is 63, just check 63 and each 126th number thereafter.
        -- For the 204th - 907th such numbers, the HCF reduces to 21, so adjust accordingly.
        -- (See Horsth's comments on the Talk page.)
        set zumkellers to zumkellerNumbers(40, 63, 126, no5Multiples)
    else
        -- Otherwise check alternate numbers from 1.
        set zumkellers to zumkellerNumbers(40, 1, 2, no5Multiples)
    end if
    set end of output to formatForDisplay(zumkellers, header, 10, "  ")
 
    return joinText(output, linefeed & linefeed)
end doTask
 
local cheating
set cheating to false
doTask(cheating)