Fungsi totient Super cepat

22

Tujuannya sederhana: hitung fungsi totient untuk sebanyak mungkin angka dalam 10 detik dan jumlahkan jumlahnya.

Anda harus mencetak hasil Anda di akhir dan Anda harus benar-benar menghitungnya. Tidak ada fungsi totient otomatis yang diizinkan, tetapi perpustakaan bignum diperbolehkan. Anda harus mulai dari 1 dan menghitung semua bilangan bulat secara berurutan. Anda tidak diizinkan melewati angka.

Skor Anda adalah berapa banyak angka yang dapat dihitung program Anda di mesin Anda / berapa banyak program saya yang bisa dihitung di mesin Anda . Kode saya adalah program sederhana dalam C ++ (optimisasi tidak aktif), semoga Anda dapat menjalankannya.

Properti penting yang dapat Anda gunakan!

  • jika gcd(m,n) = 1, phi(mn) = phi(m) * phi(n)
  • jika pprima, phi(p) = p - 1(untuk p < 10^20)
  • jika ngenap,phi(2n) = 2 phi(n)
  • yang lain tercantum di tautan pertama

Kode saya

#include <iostream>
using namespace std;

int gcd(int a, int b)
{
    while (b != 0)
    {
        int c = a % b;
        a = b;
        b = c;
    }
    return a;
}

int phi(int n)
{
    int x = 0;
    for (int i=1; i<=n; i++)
    {
        if (gcd(n, i) == 1)
            x++;
    }
    return x;
}

int main()
{
    unsigned int sum = 0;
    for (int i=1; i<19000; i++) // Change this so it runs in 10 seconds
    {
        sum += phi(i);
    }
        cout << sum << endl;
        return 0;
}
qwr
sumber
2
Mungkin Anda mungkin ingin menambahkan bahwa angka input harus bilangan bulat berturut-turut. Kalau tidak, saya mungkin tergoda untuk menghitung fungsi totient untuk kekuatan 2 saja.
Howard
Bisakah saya melakukan 1, 3, 5, 2, 4atau sejenisnya?
Leaky Nun

Jawaban:

14

Nimrod: ~ 38.667 (580.000.000 / 15.000)

Jawaban ini menggunakan pendekatan yang cukup sederhana. Kode ini menggunakan ayakan bilangan prima sederhana yang menyimpan bilangan prima dari bilangan prima terkecil di setiap slot untuk bilangan komposit (nol untuk bilangan prima), kemudian menggunakan pemrograman dinamis untuk membangun fungsi totient pada rentang yang sama, kemudian menjumlahkan hasilnya. Program menghabiskan hampir seluruh waktunya untuk membuat ayakan, kemudian menghitung fungsi total dalam waktu yang singkat. Sepertinya itu turun untuk membangun saringan yang efisien (dengan sedikit twist yang satu juga harus dapat mengekstrak faktor utama untuk nomor komposit dari hasil dan harus menjaga penggunaan memori pada tingkat yang masuk akal).

Pembaruan: Peningkatan kinerja dengan mengurangi jejak memori dan meningkatkan perilaku cache. Dimungkinkan untuk memeras kinerja 5% -10% lebih banyak, tetapi peningkatan kompleksitas kode tidak sepadan. Pada akhirnya, algoritma ini terutama melatih bottleneck von Neumann dari CPU, dan ada sangat sedikit penyesuaian algoritme yang dapat mengatasi itu.

Juga memperbarui pembagi kinerja karena kode C ++ tidak dimaksudkan untuk dikompilasi dengan semua optimasi dan tidak ada orang lain yang melakukannya. :)

Pembaruan 2: Operasi ayakan yang dioptimalkan untuk peningkatan akses memori. Sekarang menangani bilangan prima kecil dalam jumlah besar melalui memcpy () (~ 5% speedup) dan melompati kelipatan 2, 3, dan 5 saat menyaring bilangan prima yang lebih besar (~ 10% speedup).

Kode C ++: 9,9 detik (dengan g ++ 4,9)

Kode Nimrod: 9,9 detik (dengan -d: rilis, backend gcc 4,9)

proc handleSmallPrimes(sieve: var openarray[int32], m: int) =
  # Small primes are handled as a special case through what is ideally
  # the system's highly optimized memcpy() routine.
  let k = 2*3*5*7*11*13*17
  var sp = newSeq[int32](k div 2)
  for i in [3,5,7,11,13,17]:
    for j in countup(i, k, 2*i):
      sp[j div 2] = int32(i)
  for i in countup(0, sieve.high, len(sp)):
    if i + len(sp) <= len(sieve):
      copyMem(addr(sieve[i]), addr(sp[0]), sizeof(int32)*len(sp))
    else:
      copyMem(addr(sieve[i]), addr(sp[0]), sizeof(int32)*(len(sieve)-i))
  # Fixing up the numbers for values that are actually prime.
  for i in [3,5,7,11,13,17]:
    sieve[i div 2] = 0

proc constructSieve(m: int): seq[int32] =
  result = newSeq[int32](m div 2 + 1)
  handleSmallPrimes(result, m)
  var i = 19
  # Having handled small primes, we only consider candidates for
  # composite numbers that are relatively prime with 31. This cuts
  # their number almost in half.
  let steps = [ 1, 7, 11, 13, 17, 19, 23, 29, 31 ]
  var isteps: array[8, int]
  while i * i <= m:
    if result[i div 2] == 0:
      for j in 0..7: isteps[j] = i*(steps[j+1]-steps[j])
      var k = 1 # second entry in "steps mod 30" list.
      var j = 7*i
      while j <= m:
        result[j div 2] = int32(i)
        j += isteps[k]
        k = (k + 1) and 7 # "mod 30" list has eight elements.
    i += 2

proc calculateAndSumTotients(sieve: var openarray[int32], n: int): int =
  result = 1
  for i in 2'i32..int32(n):
    var tot: int32
    if (i and 1) == 0:
      var m = i div 2
      var pp: int32 = 2
      while (m and 1) == 0:
        pp *= 2
        m = m div 2
      if m == 1:
        tot = pp div 2
      else:
        tot = (pp div 2) * sieve[m div 2]
    elif sieve[i div 2] == 0: # prime?
      tot = i - 1
      sieve[i div 2] = tot
    else:
      # find and extract the first prime power pp.
      # It's relatively prime with i/pp.
      var p = sieve[i div 2]
      var m = i div p
      var pp = p
      while m mod p == 0 and m != p:
        pp *= p
        m = m div p
      if m == p: # is i a prime power?
        tot = pp*(p-1)
      else:
        tot = sieve[pp div 2] * sieve[m div 2]
      sieve[i div 2] = tot
    result += tot

proc main(n: int) =
  var sieve = constructSieve(n)
  let totSum = calculateAndSumTotients(sieve, n)
  echo totSum

main(580_000_000)
Reimer Behrends
sumber
Epik! +1. Nimrod mulai menjadi lebih populer; 3
cjfaure
Tunggu. Wow. Saya membatalkan jawaban Anda yang lain. : P
cjfaure
1
Apakah Nimrod merupakan persilangan antara Python dan C?
mbomb007
Nimrod baru-baru ini diganti namanya menjadi Nim; Meskipun meminjam gaya sintaksis Python, semantiknya berbeda, dan tidak seperti C, memori-aman (kecuali jika Anda menggunakan fitur yang tidak aman) dan memiliki pengumpulan sampah.
Reimer Behrends
9

Java, skor ~ 24.000 (360.000.000 / 15.000)

Kode java di bawah ini melakukan perhitungan fungsi totient dan ayakan utama secara bersamaan. Perhatikan bahwa tergantung pada mesin Anda, Anda harus meningkatkan ukuran tumpukan awal / maksimum (pada laptop saya yang agak lambat saya harus naik ke -Xmx3g -Xms3g).

public class Totient {

    final static int size = 360000000;
    final static int[] phi = new int[size];

    public static void main(String[] args) {
        long time = System.currentTimeMillis();
        long sum = 0;

        phi[1] = 1;
        for (int i = 2; i < size; i++) {
            if (phi[i] == 0) {
                phi[i] = i - 1;
                for (int j = 2; i * j < size; j++) {
                    if (phi[j] == 0)
                        continue;

                    int q = j;
                    int f = i - 1;
                    while (q % i == 0) {
                        f *= i;
                        q /= i;
                    }
                    phi[i * j] = f * phi[q];
                }
            }
            sum += phi[i];
        }
        System.out.println(System.currentTimeMillis() - time);
        System.out.println(sum);
    }
}
Howard
sumber
9

Nimrod: ~ 2.333.333 (42.000.000.000 / 18.000)

Ini menggunakan pendekatan yang sama sekali berbeda dari jawaban saya sebelumnya. Lihat komentar untuk detailnya. The longintmodul dapat ditemukan di sini .

import longint

const max = 500_000_000

var ts_mem: array[1..max, int]

# ts(n, d) is defined as the number of pairs (a,b)
# such that 1 <= a <= b <= n and gcd(a,b) = d.
#
# The following equations hold:
#
# ts(n, d) = ts(n div d, 1)
# sum for i in 1..n of ts(n, i) = n*(n+1)/2
#
# This leads to the recurrence:
# ts(n, 1) = n*(n+1)/2 - sum for i in 2..n of ts(n, i)
#
# or, where ts(n) = ts(n, 1):
# ts(n) = n*(n+1)/2 - sum for i in 2..n of ts(n div i)
#
# Note that the large numbers that we deal with can
# overflow 64-bit integers.

proc ts(n, gcd: int): int =
  if n == 0:
    result = 0
  elif n == 1 and gcd == 1:
    result = 1
  elif gcd == 1:
    result = n*(n+1) div 2
    for i in 2..n:
      result -= ts(n, i)
  else:
    result = ts(n div gcd, 1)

# Below is the optimized version of the same algorithm.

proc ts(n: int): int =
  if n == 0:
    result = 0
  elif n == 1:
    result = 1
  else:
    if n <= max and ts_mem[n] > 0:
      return ts_mem[n]
    result = n*(n+1) div 2
    var p = n
    var k = 2
    while k < n div k:
      let pold = p
      p = n div k
      k += 1
      let t = ts(n div pold)
      result -= t * (pold-p)
    while p >= 2:
      result -= ts(n div p)
      p -= 1
    if n <= max:
      ts_mem[n] = result

proc ts(n: int128): int128 =
  if n <= 2_000_000_000:
    result = ts(n.toInt)
  else:
    result = n*(n+1) div 2
    var p = n
    var k = 2
    while k < n div k:
      let pold = p
      p = n div k
      k += 1
      let t = ts(n div pold)
      result = result - t * (pold-p)
    while p >= 2:
      result = result - ts(n div p)
      p = p - 1

echo ts(42_000_000_000.toInt128)
Reimer Behrends
sumber
Hadirin sekalian, ini yang saya sebut sihir.
Anna Jokela
2
Pendekatan yang bagus untuk menghitung jumlah secara langsung, tetapi sayangnya itu tidak menghitung fungsi total untuk sebanyak mungkin angka yang merupakan tantangan yang diberikan di atas. Kode Anda benar-benar menghitung hasil (bahkan bukan hasil dari fungsi totient) hanya beberapa ribu angka (rata-rata 2*sqrt(n)) yang menghasilkan skor yang jauh lebih rendah.
Howard
7

C #: 49.000 (980.000.000 / 20.000)

/codegolf//a/26800 "kode Howard".
Tetapi dimodifikasi, nilai phi dihitung untuk bilangan bulat ganjil.

using System;
using sw = System.Diagnostics.Stopwatch;
class Program
{
    static void Main()
    {
        sw sw = sw.StartNew();
        Console.Write(sumPhi(980000000) + " " + sw.Elapsed);
        sw.Stop(); Console.Read();
    }

    static long sumPhi(int n)  // sum phi[i] , 1 <= i <= n
    {
        long s = 0; int[] phi;
        if (n < 1) return 0; phi = buildPhi(n + 1);
        for (int i = 1; i <= n; i++) s += getPhi(i, phi);
        return s;
    }

    static int getPhi(int i, int[] phi)
    {
        if ((i & 1) > 0) return phi[i >> 1];
        if ((i & 3) > 0) return phi[i >> 2];
        int z = ntz(i); return phi[i >> z >> 1] << z - 1;
    }

    static int[] buildPhi(int n)  // phi[i >> 1] , i odd , i < n
    {
        int i, j, y, x, q, r, f; int[] phi;
        if (n < 2) return new int[] { 0 };
        phi = new int[n / 2]; phi[0] = 1;
        for (j = 2, i = 3; i < n; i *= 3, j *= 3) phi[i >> 1] = j;
        for (x = 4, i = 5; i <= n >> 1; i += x ^= 6)
        {
            if (phi[i >> 1] > 0) continue; phi[i >> 1] = i ^ 1;
            for (j = 3, y = 3 * i; y < n; y += i << 1, j += 2)
            {
                if (phi[j >> 1] == 0) continue; q = j; f = i ^ 1;
                while ((r = q) == i * (q /= i)) f *= i;
                phi[y >> 1] = f * phi[r >> 1];
            }
        }
        for (; i < n; i += x ^= 6)  // primes > n / 2 
            if (phi[i >> 1] == 0)
                phi[i >> 1] = i ^ 1;
        return phi;
    }

    static int ntz(int i)  // number of trailing zeros
    {
        int z = 1;
        if ((i & 0xffff) == 0) { z += 16; i >>= 16; }
        if ((i & 0x00ff) == 0) { z += 08; i >>= 08; }
        if ((i & 0x000f) == 0) { z += 04; i >>= 04; }
        if ((i & 0x0003) == 0) { z += 02; i >>= 02; }
        return z - (i & 1);
    }
}

Skor baru: 61.000 (1.220.000.000 / 20.000)
Di "App.config" Saya harus menambahkan "gcAllowVeryLargeObjects enabled = true".

    static long sumPhi(int n)
    {
        int i1, i2, i3, i4, z; long s1, s2, s3, s4; int[] phi;
        if (n < 1) return 0; phi = buildPhi(n + 1); n -= 4; z = 2;
        i1 = 1; i2 = 2; i3 = 3; i4 = 4; s1 = s2 = s3 = s4 = 0;
        if (n > 0)
            for (; ; )
            {
                s1 += phi[i1 >> 1];
                s2 += phi[i2 >> 2];
                s3 += phi[i3 >> 1];
                s4 += phi[i4 >> z >> 1] << z - 1;
                i1 += 4; i2 += 4; i3 += 4; i4 += 4;
                n -= 4; if (n < 0) break;
                if (z == 2)
                {
                    z = 3; i4 >>= 3;
                    while ((i4 & 3) == 0) { i4 >>= 2; z += 2; }
                    z += i4 & 1 ^ 1;
                    i4 = i3 + 1;
                }
                else z = 2;
            }
        if (n > -4) s1 += phi[i1 >> 1];
        if (n > -3) s2 += phi[i2 >> 2];
        if (n > -2) s3 += phi[i3 >> 1];
        if (n > -1) s4 += phi[i4 >> z >> 1] << z - 1;
        return s1 + s2 + s3 + s4;
    }

    static int[] buildPhi(int n)
    {
        int i, j, y, x, q0, q1, f; int[] phi;
        if (n < 2) return new int[] { 0 };
        phi = new int[n / 2]; phi[0] = 1;
        for (uint u = 2, v = 3; v < n; v *= 3, u *= 3) phi[v >> 1] = (int)u;
        for (x = 4, i = 5; i <= n >> 1; i += x ^= 6)
        {
            if (phi[i >> 1] > 0) continue; phi[i >> 1] = i ^ 1;
            for (j = 3, y = 3 * i; y < n; y += i << 1, j += 2)
            {
                if (phi[j >> 1] == 0) continue; q0 = j; f = i ^ 1;
                while ((q1 = q0) == i * (q0 /= i)) f *= i;
                phi[y >> 1] = f * phi[q1 >> 1];
            }
        }
        for (; i < n; i += x ^= 6)
            if (phi[i >> 1] == 0)
                phi[i >> 1] = i ^ 1;
        return phi;
    }
P_P
sumber
4

Python 3: ~ 24000 (335.000.000 / 14.000)

Versi saya adalah port Python dari algoritma Howard . Fungsi asli saya adalah modifikasi dari algoritma yang diperkenalkan di blogpost ini .

Saya menggunakan modul Numpy dan Numba untuk mempercepat waktu eksekusi. Perhatikan bahwa biasanya Anda tidak perlu mendeklarasikan jenis variabel lokal (saat menggunakan Numba), tetapi dalam hal ini saya ingin memeras waktu eksekusi sebanyak mungkin.

Sunting: fungsi constructsieve dan summarum gabungan menjadi satu fungsi.

C ++: 9.99s (n = 14.000); Python 3: 9.94s (n = 335.000.000)

import numba as nb
import numpy as np
import time

n = 335000000

@nb.njit("i8(i4[:])", locals=dict(
    n=nb.int32, s=nb.int64, i=nb.int32,
    j=nb.int32, q=nb.int32, f=nb.int32))

def summarum(phi):
    s = 0

    phi[1] = 1

    i = 2
    while i < n:
        if phi[i] == 0:
            phi[i] = i - 1

            j = 2

            while j * i < n:
                if phi[j] != 0:
                    q = j
                    f = i - 1

                    while q % i == 0:
                        f *= i
                        q //= i

                    phi[i * j] = f * phi[q]
                j += 1
        s += phi[i]
        i += 1
    return s

if __name__ == "__main__":
    s1 = time.time()
    a = summarum(np.zeros(n, np.int32))
    s2 = time.time()

    print(a)
    print("{}s".format(s2 - s1))
Anna Jokela
sumber
1
Anda harus memberikan kredit yang tepat ketika Anda menyalin kode dari pengguna lain.
Howard
Diperbarui dengan kredit yang tepat!
Anna Jokela
3

Berikut ini adalah implementasi Python saya yang tampaknya mampu mengeluarkan ~ 60000 angka dalam 10 detik. Saya memfaktorkan angka menggunakan algoritma pollard rho dan menggunakan uji primitif Rabin miller.

from Queue import Queue
import random

def gcd ( a , b ):
    while b != 0: a, b = b, a % b
    return a

def rabin_miller(p):
    if(p<2): return False
    if(p!=2 and p%2==0): return False
    s=p-1
    while(s%2==0): s>>=1
    for _ in xrange(10):
        a=random.randrange(p-1)+1
        temp=s
        mod=pow(a,temp,p)
        while(temp!=p-1 and mod!=1 and mod!=p-1):
            mod=(mod*mod)%p
            temp=temp*2
        if(mod!=p-1 and temp%2==0): return False
    return True

def pollard_rho(n):
    if(n%2==0): return 2;
    x=random.randrange(2,1000000)
    c=random.randrange(2,1000000)
    y=x
    d=1
    while(d==1):
        x=(x*x+c)%n
        y=(y*y+c)%n
        y=(y*y+c)%n
        d=gcd(x-y,n)
        if(d==n): break;
    return d;

def primeFactorization(n):
    if n <= 0: raise ValueError("Fucked up input, n <= 0")
    elif n == 1: return []
    queue = Queue()
    factors=[]
    queue.put(n)
    while(not queue.empty()):
        l=queue.get()
        if(rabin_miller(l)):
            factors.append(l)
            continue
        d=pollard_rho(l)
        if(d==l):queue.put(l)
        else:
            queue.put(d)
            queue.put(l/d)
    return factors

def phi(n):

    if rabin_miller(n): return n-1
    phi = n
    for p in set(primeFactorization(n)):
        phi -= (phi/p)
    return phi

if __name__ == '__main__':

  n = 1
  s = 0

  while n < 60000:
    n += 1
    s += phi(n)
  print(s)
will.fiset
sumber
2

φ (2 n ) = 2 n - 1
Σ φ (2 i ) = 2 i - 1 untuk saya dari 1 hingga n

Pertama, sesuatu untuk menemukan waktu:

import os
from time import perf_counter

SEARCH_LOWER = -1
SEARCH_HIGHER = 1

def integer_binary_search(start, lower=None, upper=None, big_jump=1):
    if lower is not None and lower == upper:
        raise StopIteration # ?

    result = yield start

    if result == SEARCH_LOWER:
        if lower is None:
            yield from integer_binary_search(
                start=start - big_jump,
                lower=None,
                upper=start - 1,
                big_jump=big_jump * 2)
        else:
            yield from integer_binary_search(
                start=(lower + start) // 2,
                lower=lower,
                upper=start - 1)
    elif result == SEARCH_HIGHER:
        if upper is None:
            yield from integer_binary_search(
                start=start + big_jump,
                lower=start + 1,
                upper=None,
                big_jump=big_jump * 2)
        else:
            yield from integer_binary_search(
                start=(start + upper) // 2,
                lower=start + 1,
                upper=upper)
    else:
        raise ValueError('Expected SEARCH_LOWER or SEARCH_HIGHER.')

search = integer_binary_search(start=1000, lower=1, upper=None, big_jump=2500)
n = search.send(None)

while True:
    print('Trying with %d iterations.' % (n,))

    os.spawnlp(
        os.P_WAIT,
        'g++', 'g++', '-Wall', '-Wextra', '-pedantic', '-O0', '-o', 'reference',
        '-DITERATIONS=%d' % (n,),
        'reference.cpp')

    start = perf_counter()
    os.spawnl(os.P_WAIT, './reference', './reference')
    end = perf_counter()
    t = end - start

    if t >= 10.1:
        n = search.send(SEARCH_LOWER)
    elif t <= 9.9:
        n = search.send(SEARCH_HIGHER)
    else:
        print('%d iterations in %f seconds!' % (n, t))
        break

Untuk kode referensi, bagi saya, itu:

...
Mencoba dengan 14593 iterasi.
64724364
14593 iterasi dalam 9,987747 detik!

Sekarang, Haskell:

import System.Environment (getArgs)

phiSum :: Integer -> Integer
phiSum n = 2 ^ n - 1

main :: IO ()
main = getArgs >>= print . phiSum . (2^) . read . head

Itu membuat sesuatu dengan 2525224 digit dalam 0,718 detik. Dan sekarang saya hanya memperhatikan komentar @ Howard.

Ry-
sumber
Bisakah Anda memposting skor dengan jumlah angka berurutan mulai dari 1 yang berhasil Anda jumlahkan?
qwr
@ qwr, itu akan menjadi 0. Jika Anda ingin angka berurutan, Anda harus menentukannya di pertanyaan Anda =)
Ry-
Aku melakukannya. Saya sudah mengeditnya, saya akan mengeditnya lagi.
qwr
2

Matlab: 1464 = 26355867/18000

Saya tidak dapat menguji kode Anda, jadi saya membagi 18.000 karena mewakili komputer tercepat dari mereka yang diuji. Saya sampai pada skor menggunakan properti ini:

  • jika p prima, phi (p) = p - 1 (untuk p <10 ^ 20)

Saya sebagian besar suka itu adalah satu liner:

sum(primes(500000000)-1)
Dennis Jaheruddin
sumber
1
Bagaimana dengan phi(p)semua yang bukan perdana p?
Geobits
2
@ Geobits saya melewatkan itu karena pertanyaannya tidak menyebutkan angka yang harus Anda gunakan, selama mereka benar-benar dihitung.
Dennis Jaheruddin
Ah, tidak memperhatikan hal itu dalam kata-kata. Bagus.
Geobits
Anda bahkan tidak memposting skor ...
qwr
1
... Bagaimana mungkin untuk tidak memiliki Matlab & C ++ di komputer yang sama?
Kyle Kanos
1

Python 2.7: 10.999 (165975/15090)

Pypy 2.3.1: 28.496 (430000/15090)

Beberapa metode menarik yang saya gunakan:

Rabin-Miller Strong Pseudoprime Test - Tes primality yang menyediakan algoritma probabilistik yang efisien untuk menentukan apakah angka yang diberikan adalah prima

Formula produk Euler - Produk melebihi bilangan prima yang berbeda yang membagi n

Formula produk Euler

Kode:

import math
import random

#perform a Modular exponentiation
def modular_pow(base, exponent, modulus):
    result=1
    while exponent>0:
        if exponent%2==1:
           result=(result * base)%modulus
        exponent=exponent>>1
        base=(base * base)%modulus
    return result

#Miller-Rabin primality test
def checkMillerRabin(n,k):
    if n==2: return True
    if n==1 or n%2==0: return False

    #find s and d, with d odd
    s=0
    d=n-1
    while(d%2==0):
        d/=2
        s+=1
    assert (2**s*d==n-1)

    #witness loop
    composite=1
    for i in xrange(k):
        a=random.randint(2,n-1)
        x=modular_pow(a,d,n)
        if x==1 or x==n-1: continue
        for j in xrange(s-1):
            composite=1
            x=modular_pow(x,2,n)
            if x==1: return False #is composite
            if x==n-1: 
                composite=0
                break
        if composite==1:
            return False        #is composite
    return True                 #is probably prime

def findPrimes(n):              #generate a list of primes, using the sieve of eratosthenes

    primes=(n+2)*[True]

    for i in range(2,int(math.sqrt(n))+1):
        if primes[i]==True:
            for j in range(i**2,n+1,i):
                primes[j]=False

    primes=[i for i in range(2,len(primes)-1) if primes[i]==True]
    return primes

def primeFactorization(n,primes):   #find the factors of a number

    factors=[]

    i=0
    while(n!=1):
        if(n%primes[i]==0):
            factors.append(primes[i])
            n/=primes[i]
        else:
            i+=1

    return factors

def phi(n,primes):
    #some useful properties
    if (checkMillerRabin(n,10)==True):      #fast prime check
        return n-1

    factors=primeFactorization(n,primes)    #prime factors
    distinctive_prime_factors=set(factors)  

    totient=n
    for f in distinctive_prime_factors:     #phi = n * sum (1 - 1/p), p is a distinctive prime factor
        totient*=(1-1.0/f);

    return totient

if __name__ == '__main__':


    s=0
    N=165975
    # N=430000
    primes=findPrimes(N)    #upper bound for the number of primes
    for i in xrange(1,N):
        s+=phi(i,primes)

    print "Sum =",s 
AlexPnt
sumber
Terima kasih untuk algoritme! Itu adalah satu-satunya yang bisa saya pahami dengan mudah dan bukan pengecekan paksa menghitung co-primes.
pengguna