web-dev-qa-db-ja.com

範囲が大きすぎますPython

数値xの最大の素数を見つけようとしています、Pythonは、範囲が大きすぎるというエラーを表示します。x範囲を使用しようとしましたが、OverflowErrorが発生します:= Python intが大きすぎてClongに変換できません

x = 600851475143
maxPrime = 0


for i in range(x):
    isItPrime = True
    if (x%i == 0):
        for prime in range(2,i-1):
            if (i%prime == 0):
                isItPrime = False
        if (isItPrime == True):

            if (i > maxPrime):
                maxPrime = i;

print maxPrime
17
Alberto Does

古い(2.x)バージョンのPythonでは、xrangeはネイティブによってバインドされているPython 2.x intsのみを処理できますlong integerプラットフォームのサイズ。さらに、rangeは事前にPython 2.xにすべての数値を含むリストを割り当てるため、大きな引数には適していません。

3.x(推奨)、またはlong int(C)が64ビット長のプラットフォームに切り替えるか、次のドロップインを使用できます。

import itertools
range = lambda stop: iter(itertools.count().next, stop)

同様に、プレーンな形式で:

def range(stop):
   i = 0
   while i < stop:
       yield i
       i += 1
28
phihag

これは私がすることです:

def prime_factors(x):
    factors = []
    while x % 2 == 0:
        factors.append(2)
        x /= 2
    i = 3
    while i * i <= x:
        while x % i == 0:
            x /= i
            factors.append(i)
        i += 2
    if x > 1:
        factors.append(x)
    return factors

>>> prime_factors(600851475143)
[71, 839, 1471, 6857]

それはかなり速いです、そして私はそれが正しいと思います。見つかった要素を最大限に活用するのは非常に簡単です。


2017-11-08

5年後にこれに戻ると、私はyieldyield fromに加えて、プライム範囲でのより高速なカウントを使用します。

def prime_factors(x):
    def diver(x, i):
        j = 0
        while x % i == 0:
            x //= i
            j += 1
        return x, [i] * j
    for i in [2, 3]:
        x, vals = diver(x, i)
        yield from vals
    i = 5
    d = {5: 2, 1: 4}
    while i * i <= x:
        x, vals = diver(x, i)
        yield from vals
        i += d[i % 6]
    if x > 1:
        yield x

list(prime_factors(600851475143))

Dict {5: 2, 1: 4}は、すべての奇数を調べる必要がないという事実を使用しています。 3を超えると、すべての数値x % 6 == 3は3の倍数になるため、x % 6 == 1x % 6 == 5のみを確認する必要があり、5から始めて2と4を交互に加算することで、これらの間を移動できます。 。

6
hughdbrown

受け入れられた回答は、xrangeのドロップイン置換を示唆していますが、カバーするのは1つのケースのみです。これは、より一般的なドロップインの代替品です。

def custom_range(start=0,stop=None,step=1):
    '''xrange in python 2.7 fails on numbers larger than C longs.
    we write a custom version'''
    if stop is None:
        #handle single argument case. ugly...
        stop = start
        start = 0
    i = start
    while i < stop:
        yield i
        i += step

xrange=custom_range
4
bgschiller

0から無限大に匹敵する数のように見えるリストを作成すると、メモリに負担がかかるため、私は間違いなくxrangeに固執します。 xrangeは、要求されたときに数値のみを生成します。数が大きすぎる問題の場合は、「長い」を試してみてください。これは、番号の末尾にLを書き込むことで実現できます。私はそれをテストするために自分のバージョンを作りました。コンピューターを事実上while(1)ループに破壊しないように、私は少し眠りました。プログラムが完全に終了するのを待ちきれなかったので、印刷物のステートメントを入れました

from time import sleep

x = 600851475143L
maxPrime = 0

for i in xrange(1,x):
    isItPrime = True
    if (x%i) == 0:
        for prime in xrange(2,i-1):
            if (i%prime) == 0:
                isItPrime = False
                break
        if isItPrime:
            maxPrime = i
            print "Found a prime: "+str(i)
    sleep(0.0000001)


print maxPrime

お役に立てれば!

編集:このバージョンを作成するために、さらにいくつかの編集を行いました。それはかなり効率的で、私はこのプログラムが提供するかなりの数をチェックしました(これまでにチェックアウトしているようです):

from time import sleep

x = 600851475143L

primes = []

for i in xrange(2,x):
    isItPrime = True
    for prime in primes:
        if (i%prime) == 0:
            isItPrime = False
            break
    if isItPrime:
        primes.append(i)
        print "Found a prime: "+str(i)
    sleep(0.0000001)


print primes[-1]
1
jakebird451

非常に非効率的なコード。これは分周器を取得するための最良の方法ではありません。forrangeを使用して実行しましたが、変数が長いため実行できないため、決定しました。しばらく使用するためにそれを実装し、自分でカウンターをインクリメントします。

13195のような32ビットintの場合:

# The prime factors of 13195 are 5, 7, 13 and 29.
# What is the largest prime factor of the number 600851475143 ?

i = 13195
for j in xrange(2, i, 1):
    if i%j == 0:
        i = i/j
        print j

長い数字の良い方法:

# The prime factors of 13195 are 5, 7, 13 and 29.
# What is the largest prime factor of the number 600851475143 ?

i = 600851475143
j = 2

while i >= j:
    if i%j == 0:
        i = i/j
        print j
    j = j+1

最後の素数は、最後に出力された値です。

0
Joselu90

python 2 range()の別の実装:

import itertools
import operator

def range(*args):
    """Replace range() builtin with an iterator version."""
    if len(args) == 0:
        raise TypeError('range() expected 1 arguments, got 0')
    start, stop, step = 0, args[0], 1
    if len(args) == 2: start, stop = args
    if len(args) == 3: start, stop, step = args
    if step == 0:
        raise ValueError('range() arg 3 must not be zero')
    iters = itertools.count(start, step)
    pred = operator.__ge__ if step > 0 else operator.__le__
    for n in iters:
        if pred(n, stop): break
        yield n
0
mja