function that counts...

Bryan bryanjugglercryptographer at yahoo.com
Fri May 21 19:41:53 EDT 2010


Peter Pearson wrote:
> If it's important for the function to execute quickly for large n,
> you might get a useful speedup by testing only every ninth integer,

Our standards for "quickly" and "large" seem kind of thin.

> I suspect that further applications of number theory would
> provide additional, substantial speedups, but this wanders
> away from the subject of Python.

I was thinking combinatorics more than number theory. I didn't find a
neat formula, but I came up with a recursive memo-izing algorithm that
handles 100-digit n's. I tested this against the initial algorithm
plus Peter Pearson's optimization for numbers up to several thousand,
and it agrees... well, after I fixed stuff that is.

-Bryan Olson

# -----------
_nds = {}
def ndsums(m, d):
    """ How many d-digit ints' digits sum to m?
    """
    assert m >= 0 and d >= 0
    if m > d * 9:
        return 0
    if m == 0 or d == 1:
        return 1
    if (m, d) not in _nds:
        _nds[(m, d)] = sum(ndsums(m - i, d - 1)
               for i in range(min(10, m + 1)))
    return _nds[(m, d)]


def prttn(m, n):
    assert m > 0 and n > 0
    def inner(m, dls):
        if not dls:
            return 1 if m == 0 else 0
        count = 0
        msd, rest = dls[0], dls[1:]
        for d in range(msd):
            if m >= d:
                count += ndsums(m - d, len(dls) - 1)
        count += inner(m - msd, dls[1:])
        return count
    return inner(m, [int(c) for c in str(n - 1)])

pi100 =
3141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067

print(prttn(500, pi100))





More information about the Python-list mailing list