(первое 10-значное простое число в e).com python google challenge 2004

Я только что подошел к одной из задач, которые якобы использовались Google 2004.

(the first 10-digit prime in e).com 

Независимо от этого, я хотел принять вызов и решить его с помощью Python.

>>> '%0.52f' % math.exp(1)
'2.71828182845904509079**5598298427**6488423347473144531250'
>>> '%0.52f' % numpy.exp(1)
'2.71828182845904509079**5598298427**6488423347473144531250'

моя программа вернула 5598298427, что является простым числом

посмотрев в интернете правильный ответ был7427466391

но число exp в python не включает эти цифры, как вы можете видеть выше

import numpy
import math

def prime(a):
    if a == 2: return True
    if a % 2 == 0: return False
    if a < 2: return False
    i = 2
    n = math.sqrt(a) + 1
    while(i < n):
        if a % i == 0:
            return False
        i += 1
    return True

def prime_e():
    e = '%0.51f' % math.exp(1)
    e = e.replace("2.","")
    for i in range(len(e)):
        x = int(e[i:10+i])
        if prime(x):
            return [i, x]

print prime_e()

так я что-то не так делаю?


EDIT: использование gmpy2

def exp():
    with gmpy2.local_context(gmpy2.context(), precision=100) as ctx:
        ctx.precision += 1000
        return gmpy2.exp(1)

возвращает 7427466391 после 99 итераций


person Elteroooo    schedule 02.09.2015    source источник
comment
Вы также можете использовать стандартный библиотечный модуль decimal: например, decimal.getcontext().prec = 1000; e = decimal.Decimal(1).exp().   -  person Mark Dickinson    schedule 02.09.2015
comment
Большое спасибо, при поиске в интернете о точности я наткнулся только на bigfloat и gmpy2. Я столкнулся с проблемами при компиляции обоих в Windows, но у gmpy2 уже была скомпилированная версия для Windows.   -  person Elteroooo    schedule 03.09.2015
comment
Да, моя беда: у меня никогда не было ни времени, ни ресурсов для правильной упаковки bigfloat для Windows. Из этих двух gmpy2 определенно правильный выбор.   -  person Mark Dickinson    schedule 03.09.2015


Ответы (3)


Фактическое значение e (константа Эйлера) составляет

http://www.gutenberg.org/files/127/127.txt

2,71828182845904523536028747135266249775724709369995957496696762772407663035354759457138217852516642 <сильный> 7427466391 932003059921817413596629043572900334295260595630 ...

и поэтому правильный ответ на вызов 7427466391. Вы не можете вычислить e с требуемой точностью с помощью math.exp(1)

person Dmitry Bychenko    schedule 02.09.2015
comment
Чтобы расширить это, двойной IEEE точен только до 53 двоичных цифр, что составляет 15 или 16 десятичных цифр. Результатом math.exp(1) является 53-значное двоичное число, которое находится в пределах 1 цифры от e в 53-й двоичной цифре. За пределами этой позиции он не имеет никакого отношения к e, хотя Python по-прежнему даст вам точное десятичное представление до 53 знаков после запятой. - person Steve Jessop; 02.09.2015
comment
@ElTero: Что касается основного тестирования для этой точной проблемы, то да. Однако один (1) не является простым числом, как бы ни говорила ваша подпрограмма; еще сомнительно i += 1: можно проверить не каждый потенциальный делитель (2, 3, 4, 5...), а odd (3, 5, 7..) - person Dmitry Bychenko; 02.09.2015
comment
@DmitryBychenko вы правы, но для 1 я просто скопировал строку выше: if a < 2 == 0: return False -> if a < 2: return False забыл удалить == 0. - person Elteroooo; 02.09.2015

Вот как это сделать:

Сгенерируйте 1-ю 1000 цифр числа e, используя метод непрерывных дробей с ответом @quantum в Код для генерации одной цифры за раз, который взят из ответа @wnoise в Генерация цифр квадратного корня из 2, что "адаптация кода Haskell... которая циркулирует вокруг":

def z(contfrac, a=1, b=0, c=0, d=1):
    for x in contfrac:
        while a > 0 and b > 0 and c > 0 and d > 0:
            t = a // c
            t2 = b // d
            if not t == t2:
                break
            yield t
            a = (10 * (a - c*t))
            b = (10 * (b - d*t))
            # continue with same fraction, don't pull new x
        a, b = x*a+b, a
        c, d = x*c+d, c
    for digit in rdigits(a, c):
        yield digit

def rdigits(p, q):
    while p > 0:
        if p > q:
           d = p // q
           p = p - q * d
        else:
           d = (10 * p) // q
           p = 10 * p - q * d
        yield d    

def e_cf_expansion():
    yield 1
    k = 0
    while True:
        yield k
        k += 2
        yield 1
        yield 1

def e_dec():
    return z(e_cf_expansion())

gen = e_dec()
e = [str(gen.next()) for i in xrange(1000)]
e.insert(1, '.')

Функция для проверки простоты целого числа, выбранного для эффективности из Rosetta Code Primality_by_trial_division#Python:

def isprime(a):
    if a < 2: return False
    if a == 2 or a == 3: return True # manually test 2 and 3   
    if a % 2 == 0 or a % 3 == 0: return False # exclude multiples of 2 and 3
    maxDivisor = a**0.5
    d, i = 5, 2
    while d <= maxDivisor:
        if a % d == 0: return False
        d += i 
        i = 6 - i # this modifies 2 into 4 and viceversa
    return True

Найдите первое 10-значное простое число в e (мой вклад):

for i in range(len(e[2:])-10):
  x = int(reduce(operator.add,e[2:][i:i+10]))
  if isprime(x):
      print x
      print i
      break

Это печатает:

7427466391
98

Это означает, что первое 10-значное простое число в e находится на 98-м месте после запятой в соответствии с http://explorepdx.com/firsten.html в разделе "Местоположение ответа".

Более простой способ сгенерировать цифры e – использовать расширение ряда Эйлера, которое можно делается следующим образом с кодом, адаптированным из Число Эйлера со 100-значной точностью (Python), использующее класс Python Decimal для обеспечения достаточной точности:

import operator
import decimal as dc

def edigits(p):
    dc.getcontext().prec = p
    factorial = 1
    euler = 2
    for x in range(2, 150):
        factorial *= x
        euler += dc.Decimal(str(1.0))/dc.Decimal(str(factorial))
    return euler

estring = edigits(150).to_eng_string()[2:]

for i in range(len(estring)-10):
    x = int(reduce(operator.add,estring[i:i+10]))
    if isprime(x):
        print x
        print i
        break

Это печатает:

7427466391
98   

Как указал @MarkDickinson, еще более простым методом является использование десятичного модуля напрямую для генерации e с необходимой точностью. Например:

import operator
import decimal

decimal.getcontext().prec = 150
e_from_decimal = decimal.Decimal(1).exp().to_eng_string()[2:]
for i in range(len(e_from_decimal)-10):
    x = int(reduce(operator.add,e_from_decimal[i:i+10]))
    if isprime(x):
        print x
        print i
        break  

Это печатает:

7427466391
98
person Community    schedule 02.09.2015
comment
Если вы собираетесь импортировать десятичный модуль, вы можете просто сделать decimal.Decimal(1).exp() с подходящей точностью. - person Mark Dickinson; 02.09.2015
comment
@MarkDickinson: спасибо. Я проголосовал за ваш комментарий и добавил прямое использование десятичного модуля для генерации e с достаточной точностью к моему ответу, в котором вы зачислены. - person ; 02.09.2015
comment
Спасибо! Признаюсь, что был предвзятым: я отвечал за реализацию метода Decimal.exp (по крайней мере, в Python 2, до преобразования десятичного модуля в C), так что приятно видеть, что он иногда используется. (Даже если это очень изредка :-) - person Mark Dickinson; 02.09.2015
comment
Я не понимаю, что это делает reduce(operator.add. Я проверил ваш код без него и все еще работает int(euler_number[i:i+10]) - person Claudiu Creanga; 30.12.2015

Проблема в том, что ваше «e» неверно после 15-го десятичного знака (09079 и далее) по причинам, которые здесь объяснили другие. Тем не менее, сам python имеет все встроенные инструменты для обеспечения «е» практически неограниченной точностью. Я еще не сталкивался с этим решением, поэтому решил опубликовать его здесь. Магия заключается в «длинном» int, который может быть настолько длинным, насколько позволяет память вашей машины. Поскольку число с плавающей запятой — это не что иное, как целое число, деленное на некоторую степень 10, мы можем легко вычислить (и сохранить) e_as_int=e*10**d, где d — количество требуемых десятичных знаков. Простой код ниже генерирует e из ряда натуральных логарифмов:

import itertools
count = itertools.count

def ape(digits):
    # e = sum(1/k! for k in count())
    # calculate some extra digits to compensate for loss of precision:
    r = 3    
    m = 10**(digits+r)
    e = 2*m
    f = 1   #initial value for k!
    for k in count(2):
        f *= k
        if f>m: break
        # remember, we're doing int division, so m/f = 0 for f>m
        e += (m/f)

    return e/10**r #truncate to required precision

«обезьяна» означает «приближение е» и довольно хорошо отражает его простоту :-) Этот алгоритм находит 10000 цифр е примерно за секунду на моей машине.

person Hermen    schedule 23.11.2015