コード例 #1
0
ファイル: sums.py プロジェクト: siegelzero/rosemary
def euler_phi_weighted_sum(n):
    """Returns the value of the sum of k*euler_phi(k) for k = 1, 2, ..., n.

    Parameters
        * n: int (n > 0)

    Returns:
        * s: int

    Raises:
        * ValueError: If n <= 0.

    Examples:
        >>> euler_phi_weighted_sum(100)
        203085
        >>> sum(k*euler_phi(k) for k in xrange(1, 101))
        203085
        >>> euler_phi_weighted_sum(0)
        Traceback (most recent call last):
        ...
        ValueError: euler_phi_weighted_sum: Must have n > 0.

    Details:
        Let T(n) = \sum_{k = 1}^{n} k*euler_phi(k). We use the relationship
        \sum_{d = 1}^{n} d*T(n/d) = n*(n + 1)*(2*n + 1) / 6 to form a recurrence
        for T(n). Using a form of Dirichlet's hyperbola method and memoizing the
        recursion gives us a sublinear runtime.
    """
    if n <= 0:
        raise ValueError("euler_phi_weighted_sum: Must have n > 0.")

    sqrt = int(n**(0.5))
    totients = lists.euler_phi_list(sqrt)

    # for i <= sqrt(n), compute the sum directly
    cache = {1: 1}
    for i in xrange(2, sqrt + 1):
        cache[i] = cache[i - 1] + i*totients[i]

    def T(n):
        if n in cache:
            return cache[n]

        sqrt_n = int(n**(0.5)) + 1
        s1 = sum(d*totients[d]*(n//d - d + 1)*(n//d + d)//2 for d in xrange(1, sqrt_n))
        s2 = sum(d*(T(n//d) - T(d - 1)) for d in xrange(2, sqrt_n))
        s3 = sum(d*d*totients[d] for d in xrange(1, sqrt_n))

        cache[n] = n*(n + 1)*(2*n + 1)//6 - (s1 + s2 - s3)
        return cache[n]

    return T(n)
コード例 #2
0
ファイル: test_lists.py プロジェクト: siegelzero/rosemary
    def test_euler_phi_list(self):
        self.assertRaisesRegexp(ValueError, "euler_phi_list: Must have n > 0.", euler_phi_list, 0)

        values = [
            0, 1, 1, 2, 2, 4, 2, 6, 4, 6, 4, 10, 4, 12, 6, 8, 8, 16, 6, 18, 8, 12, 10, 22, 8, 20, 12, 18, 12, 28, 8, 30,
            16, 20, 16, 24, 12, 36, 18, 24, 16, 40, 12, 42, 20, 24, 22, 46, 16, 42, 20, 32, 24, 52, 18, 40, 24, 36, 28,
            58, 16, 60, 30, 36, 32, 48, 20, 66, 32, 44, 24, 70, 24, 72, 36, 40, 36, 60, 24, 78, 32, 54, 40, 82, 24, 64,
            42, 56, 40, 88, 24, 72, 44, 60, 46, 72, 32, 96, 42, 60, 40, 100, 32, 102, 48, 48, 52, 106, 36, 108, 40, 72,
            48, 112, 36, 88, 56, 72, 58, 96, 32, 110, 60, 80, 60, 100, 36, 126, 64, 84, 48, 130, 40, 108, 66, 72, 64,
            136, 44, 138, 48, 92, 70, 120, 48, 112, 72, 84, 72, 148, 40, 150, 72, 96, 60, 120, 48, 156, 78, 104, 64,
            132, 54, 162, 80, 80, 82, 166, 48, 156, 64, 108, 84, 172, 56, 120, 80, 116, 88, 178, 48, 180, 72, 120, 88,
            144, 60, 160, 92, 108, 72, 190, 64, 192, 96, 96, 84, 196, 60, 198, 80
        ]

        self.assertEqual(euler_phi_list(200), values)
コード例 #3
0
ファイル: sums.py プロジェクト: siegelzero/rosemary
def euler_phi_sum(n):
    r"""Returns the value of the sum of euler_phi(k) for k = 1, 2, ..., n.

    Parameters
    ----------
    n : int (n > 0)

    Returns
    -------
    s : int

    Raises
    ------
    ValueError
        If n <= 0.

    Notes
    -----
    Let S(n) = \sum_{k = 1}^{n} \phi(k). We use the identity S(n) = n*(n +
    1)/2 - \sum_{d = 2}^{n} S(n/d) to compute the value. By applying a
    variant of Dirichlet's Hyperbola Method, we are able to cut the limits
    of summation, and by memoizing the recursion, we are able to achieve a
    sublinear runtime. See Section 4.2 of "The Prime Numbers and Their
    Distribution" by Mendes, et al for the Hyperbola Method. See section
    4.9 equation 4.60 in "Concrete Mathematics" by Graham, et al for a
    proof of the identity for S(n).

    Examples
    --------
    >>> euler_phi_sum(10)
    32
    >>> sum(lists.euler_phi_list(10))
    32
    >>> euler_phi_sum(10**5)
    3039650754
    >>> euler_phi_sum(0)
    Traceback (most recent call last):
    ...
    ValueError: euler_phi_sum: Must have n > 0.
    """
    if n <= 0:
        raise ValueError("euler_phi_sum: Must have n > 0.")

    sqrt = int(n**(0.5))
    phi_list = lists.euler_phi_list(sqrt)

    # for i <= sqrt(n), compute the sum directly
    cache = {1: 1}
    for i in xrange(2, sqrt + 1):
        cache[i] = cache[i - 1] + phi_list[i]

    def S(n):
        if n in cache:
            return cache[n]

        sqrt_n = int(n**(0.5))
        value = n - sqrt_n*cache[sqrt_n]

        for d in xrange(2, sqrt_n + 1):
            value += (S(n//d) + phi_list[d]*(n//d))

        cache[n] = n*(n + 1)//2 - value
        return cache[n]

    return S(n)