Python Generator връща итерация за спиране?

Не мога да разбера защо резултатът от това излиза като:

>  File "<pyshell#177>", line 6, in func
>     list.append(next(PrimeGen)) 
>  StopIteration

когато има толкова много смисъл в главата ми!! Както и да е, основно се опитвам да направя генератор на прости числа, използвайки функция ifprime и генератор за събиране на простите числа в списък.

Това определя дали е просто и връща стойността, ако е, в противен случай нищо.

def prime(x):
    if (2**(x-1))%x ==1:
        return x

Това прави генератора, който трябва да върне списък, пълен с прости числа до x, но вместо това дава грешката по-горе. Започнах списък с 2 вътре в него, защото горната функция prime(x) не счита 2 за просто число (така че диапазонът ще започне от 3)

def func(x):
  count=0
  list=[2]
  PrimeGen = (prime(X) for X in range(3,x+1))
  while count<99:
      list.append(next(PrimeGen))
      count+=1
  print list

Може ли някой да обясни защо не работи? Благодаря ви предварително! V.


person Valentine Bondar    schedule 01.08.2012    source източник


Отговори (3)


Имайте предвид, че вашият основен тест

def prime(x):
    if (2**(x-1))%x ==1:
        return x

е грешно, че декларира напр. 341 = 11*31 и 2047 = 23*89 първични.

Също така, за по-големи x, които генерират много големи междинни стойности, е много по-ефективно

pow(2,x-1,x)

което намалява междинните стойности.

Умерено ефективно внедряване на по-силна проверка на първичността:

# The primes below 200 used as bases for the strong Fermat test,
# prime bases have more discriminatory power than composite bases,
# therefore we use prime bases first
bases = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199]

# The strong Fermat test for base b, where n is odd and large,
# n - 1 = m * 2^s with odd m
# the strong test checks whether b**m % n == 1 or
# b**(2**j) % n == n-1 for a 0 <= j < s
# If the test returns False, n is definitely composite, otherwise probably prime
def strongFermat(b,n,m,s):
    a = pow(b,m,n)
    if a == 1:
        return True
    n1 = n-1
    for i in xrange(s):
        if a == n1:
            return True
        a = (a*a) % n
    return False

# Multiple strong Fermat tests, by default use 10 bases
# The probability that a composite passes is less than 0.25**iters
def sppTest(n, iters = 10):
    # Assumes n > 1 and with no prime divisors < 200
    m = n-1
    s = 0
    while (m & 1) == 0:
        m >>= 1
        s += 1
    pbases = iters if iters < 47 else 46
    for i in xrange(pbases):
        if not strongFermat(bases[i],n,m,s):
            return False
    if pbases < iters:
        for i in xrange(iters-pbases):
            if not strongFermat(211 + 2*i,n,m,s):
                return False
    return True

# Trial division to weed out most composites fast
def trialDivisionPrime(n):
    if n < 2:
        return 0        # Not a prime
    if n < 4:
        return 2        # definitely prime
    if n % 2 == 0 or n % 3 == 0:
        return 0        # definitely composite
    for d in xrange(5, 200, 6):
        if d*d > n:
            return 2    # definitely prime
        if n % d == 0 or n % (d+2) == 0:
            return 0    # composite
    return 1            # not yet decided

# The prime test, first do trial division by numbers < 200,
# if that doesn't decide the matter, use some strong Fermat tests
# using 20 tests is the paranoid setting for largish numbers,
# for numbers in 64-bit range, ten or fewer suffice
def prime(n):
    td = trialDivisionPrime(n)
    return td > 1 or (td == 1 and sppTest(n,20))

# just check a couple of larger numbers
for c in xrange(100000):
    if prime(c + 10**25):
        print c
person Daniel Fischer    schedule 01.08.2012
comment
О, това е странно, използвах малката теорема на Ферма, просто предположих, че е бронирана... или я преведох погрешно на Python? Благодаря все пак за по-ефективния - person Valentine Bondar; 01.08.2012
comment
Преводът е правилен, но теоремата посочва само необходимо условие, за да бъде просто. Съставните цели числа, притежаващи тестваното свойство, са известни като псевдопрости числа на Ферма. Има много повече бързи вероятностни основни тестове, но известните окончателни първични тестове все още са значително по-бавни. Можете да получите по-висок процент на коректност, като използвате повече бази и бих препоръчал да преминете към силния тест на Ферма, който е по-мощен и едва ли е по-сложен. - person Daniel Fischer; 01.08.2012

Генерирани са по-малко от 99 стойности. Използвайте itertools.islice() вместо цикъл.

person Ignacio Vazquez-Abrams    schedule 01.08.2012

Това е малко по-хубаво (изглежда някак глупаво вашата функция "prime" да връща или числото, ако е просто, или None в противен случай, въпреки че всъщност би работило добре на мястото на леко модифицираната версия по-долу поради начина, по който bool(None) == False) и не води до получаване на StopIteration:

def isprime(x):
    return (2**(x-1))%x==1

def func(x):
    list=[2]
    list.extend(X for X in range(3,x+1) if isprime(X))
    print list

Но според казаното от Даниел Фишер, основната ви функция така или иначе е неправилна.

person JAB    schedule 01.08.2012