Как вычислить энный корень очень большого целого числа

28
задан Colonel Panic 1 April 2015 в 15:35
поделиться

9 ответов

Можно заставить его работать немного быстрее путем предотвращения циклов с условием продолжения в пользу установки низко на 10 ** (len (ул. (x)) / n) и высоко к низкому * 10. Вероятно, лучше должен заменить len (ул. (x)) с поразрядной длиной и использующий немного сдвига. На основе моих тестов я оцениваю 5%-е ускорение сначала и 25%-е ускорение от второго. Если ints являются достаточно большими, это могло бы иметь значение (и ускорения могут варьироваться). Не доверяйте моему коду, не тестируя его тщательно. Я сделал некоторое основное тестирование, но, возможно, пропустил пограничный случай. Кроме того, эти ускорения меняются в зависимости от выбранного числа.

, Если фактические данные Вы используете, намного больше, чем, что Вы отправили здесь, это изменение может стоить.

from timeit import Timer

def find_invpow(x,n):
    """Finds the integer component of the n'th root of x,
    an integer such that y ** n <= x < (y + 1) ** n.
    """
    high = 1
    while high ** n < x:
        high *= 2
    low = high/2
    while low < high:
        mid = (low + high) // 2
        if low < mid and mid**n < x:
            low = mid
        elif high > mid and mid**n > x:
            high = mid
        else:
            return mid
    return mid + 1

def find_invpowAlt(x,n):
    """Finds the integer component of the n'th root of x,
    an integer such that y ** n <= x < (y + 1) ** n.
    """
    low = 10 ** (len(str(x)) / n)
    high = low * 10

    while low < high:
        mid = (low + high) // 2
        if low < mid and mid**n < x:
            low = mid
        elif high > mid and mid**n > x:
            high = mid
        else:
            return mid
    return mid + 1

x = 237734537465873465
n = 5
tests = 10000

print "Norm", Timer('find_invpow(x,n)', 'from __main__ import find_invpow, x,n').timeit(number=tests)
print "Alt", Timer('find_invpowAlt(x,n)', 'from __main__ import find_invpowAlt, x,n').timeit(number=tests)

Норма 0.626754999161

Высокий звук 0.566340923309

6
ответ дан Brian 28 November 2019 в 03:00
поделиться

Если это - ДЕЙСТВИТЕЛЬНО большое количество. Вы могли использовать двоичный поиск.

def find_invpow(x,n):
    """Finds the integer component of the n'th root of x,
    an integer such that y ** n <= x < (y + 1) ** n.
    """
    high = 1
    while high ** n <= x:
        high *= 2
    low = high/2
    while low < high:
        mid = (low + high) // 2
        if low < mid and mid**n < x:
            low = mid
        elif high > mid and mid**n > x:
            high = mid
        else:
            return mid
    return mid + 1

, Например:

>>> x = 237734537465873465
>>> n = 5
>>> y = find_invpow(x,n)
>>> y
2986
>>> y**n <= x <= (y+1)**n
True
>>>
>>> x = 119680039660309643568856114803834088331723464504673392511960931441>
>>> n = 45
>>> y = find_invpow(x,n)
>>> y
227661383982863143360L
>>> y**n <= x < (y+1)**n
True
>>> find_invpow(y**n,n) == y
True
>>>
27
ответ дан Markus Jarderot 28 November 2019 в 03:00
поделиться

Gmpy является модулем расширения C-coded Python, который обертывает библиотеку GMP для обеспечения к быстрой арифметике мультиточности кода Python (целое число, рациональное, и плавание), генерация случайных чисел, усовершенствованные теоретические числом функции, и т.д.

Включает root функция:

x.root (n): возвращает кортеж с 2 элементами (y, m), такой, что y (возможно усеченный) энный корень x; m, обычный интервал Python, равняется 1, если корень точен (x == y ** n), еще 0. n должен быть обычным интервалом Python,> =0.

, Например, 20-й корень:

>>> import gmpy
>>> i0=11968003966030964356885611480383408833172346450467339251 
>>> m0=gmpy.mpz(i0)
>>> m0
mpz(11968003966030964356885611480383408833172346450467339251L)
>>> m0.root(20)
(mpz(567), 0)
16
ответ дан gimel 28 November 2019 в 03:00
поделиться

Если Вы ищете что-то стандартное, быстро для записи с высокой точностью. Я использовал бы десятичное число и скорректировал бы точность (getcontext () .prec), по крайней мере, к длине x.

Код (Python 3.0)

from decimal import *

x =   '11968003966030964356885611480383408833172346450467339251\
196093144141045683463085291115677488411620264826942334897996389\
485046262847265769280883237649461122479734279424416861834396522\
819159219215308460065265520143082728303864638821979329804885526\
557893649662037092457130509980883789368448042961108430809620626\
059287437887495827369474189818588006905358793385574832590121472\
680866521970802708379837148646191567765584039175249171110593159\
305029014037881475265618958103073425958633163441030267478942720\
703134493880117805010891574606323700178176718412858948243785754\
898788359757528163558061136758276299059029113119763557411729353\
915848889261125855717014320045292143759177464380434854573300054\
940683350937992500211758727939459249163046465047204851616590276\
724564411037216844005877918224201569391107769029955591465502737\
961776799311859881060956465198859727495735498887960494256488224\
613682478900505821893815926193600121890632'

minprec = 27
if len(x) > minprec: getcontext().prec = len(x)
else:                getcontext().prec = minprec

x = Decimal(x)
power = Decimal(1)/Decimal(3)

answer = x**power
ranswer = answer.quantize(Decimal('1.'), rounding=ROUND_UP)

diff = x - ranswer**Decimal(3)
if diff == Decimal(0):
    print("x is the cubic number of", ranswer)
else:
    print("x has a cubic root of ", answer)

Ответ

, x является кубическим количеством 22873918786185635329056863961725521583023133411 451452349318109627653540670761962215971994403670045614485973722724603798 107719978813658857014190047742680490088532895666963698551709978502745901 704433723567548799463129652706705873694274209728785041817619032774248488 2965377218610139128882473918261696612098418

7
ответ дан Mahmoud Kassem 28 November 2019 в 03:00
поделиться

О, для чисел , что большой, Вы использовали бы десятичный модуль.

нс: Ваше число как строка

ns = "11968003966030964356885611480383408833172346450467339251196093144141045683463085291115677488411620264826942334897996389485046262847265769280883237649461122479734279424416861834396522819159219215308460065265520143082728303864638821979329804885526557893649662037092457130509980883789368448042961108430809620626059287437887495827369474189818588006905358793385574832590121472680866521970802708379837148646191567765584039175249171110593159305029014037881475265618958103073425958633163441030267478942720703134493880117805010891574606323700178176718412858948243785754898788359757528163558061136758276299059029113119763557411729353915848889261125855717014320045292143759177464380434854573300054940683350937992500211758727939459249163046465047204851616590276724564411037216844005877918224201569391107769029955591465502737961776799311859881060956465198859727495735498887960494256488224613682478900505821893815926193600121890632"
from decimal import Decimal
d = Decimal(ns)
one_third = Decimal("0.3333333333333333")
print d ** one_third

и ответ: 2.287391878618402702753613056E+305

TZ указал, что это не точно..., и он прав. Вот мой тест.

from decimal import Decimal

def nth_root(num_decimal, n_integer):
    exponent = Decimal("1.0") / Decimal(n_integer)
    return num_decimal ** exponent

def test():
    ns = "11968003966030964356885611480383408833172346450467339251196093144141045683463085291115677488411620264826942334897996389485046262847265769280883237649461122479734279424416861834396522819159219215308460065265520143082728303864638821979329804885526557893649662037092457130509980883789368448042961108430809620626059287437887495827369474189818588006905358793385574832590121472680866521970802708379837148646191567765584039175249171110593159305029014037881475265618958103073425958633163441030267478942720703134493880117805010891574606323700178176718412858948243785754898788359757528163558061136758276299059029113119763557411729353915848889261125855717014320045292143759177464380434854573300054940683350937992500211758727939459249163046465047204851616590276724564411037216844005877918224201569391107769029955591465502737961776799311859881060956465198859727495735498887960494256488224613682478900505821893815926193600121890632"
    nd = Decimal(ns)
    cube_root = nth_root(nd, 3)
    print (cube_root ** Decimal("3.0")) - nd

if __name__ == "__main__":
    test()

Это выключено приблизительно 10 ** 891

3
ответ дан Jim Carroll 28 November 2019 в 03:00
поделиться

Возможно для Вашего любопытства:

http://en.wikipedia.org/wiki/Hensel_Lifting

Это могло быть техникой, которую Клен будет использовать для фактического нахождения энного корня больших количеств.

Поза то, что x^n - 11968003.... = 0 mod p, и идут оттуда...

2
ответ дан Calyth 28 November 2019 в 03:00
поделиться

В более старых версиях Python, 1/3 равно 0. В Python 3.0, 1/3 равно 0,33333333333 (и 1//3 равно 0).

Так, или измените свой код, чтобы использовать 1/3.0 или переключиться на Python 3.0.

1
ответ дан Brian 28 November 2019 в 03:00
поделиться

Попытайтесь преобразовать экспоненту в плавающее число, поскольку поведение по умолчанию / в Python является целочисленным делением

n ** (1/плавание (3))

-1
ответ дан Manuel Ferreria 28 November 2019 в 03:00
поделиться

Ну, если Вы особенно не волнуетесь по поводу точности, Вы могли бы преобразовать ее в жало, обрубить некоторые цифры, использовать функцию экспоненты, и затем умножить результат полностью того, сколько Вы обрубили.

, Например, 32123 о равном 32 * 1000, кубический корень о равном кубическому корню 32 * кубический корень 1 000. Последний может быть вычислен путем деления количества 0s 3.

Это избегает потребности в использовании дополнительных модулей.

-3
ответ дан Brian 28 November 2019 в 03:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: