Предел Python Sqrt?

Я работаю с очень большими числами (1 000 000 цифр), и мне нужно вычислить их квадратный корень. Кажется, я достиг предела в своем коде.

y = 10**309
x = y**0.5
print(x)

И я получаю эту ошибку:

x = y**0.5
OverflowError: int too large to convert to float

Код работает до 10**308. Но помимо этого он кажется сломанным. Я также проверил это в командной строке. Та же ошибка. Кто-нибудь может мне помочь?

Если это предел Python, есть ли альтернативный метод, который я мог бы использовать?

РЕДАКТИРОВАТЬ: Внесены исправления в код.


person S Anwar    schedule 30.01.2015    source источник
comment
Интересно, что math.sqrt возвращает inf для всего, что больше 10^308.   -  person Holloway    schedule 30.01.2015
comment
1 миллион цифр .... Вы понимаете, что арифметика произвольной точности - это серьезная математическая задача .... верно?   -  person sarveshseri    schedule 30.01.2015
comment
Я думаю, что это должно быть выполнимо без нынешнего уровня математики... но у меня мало надежд... и еще меньше надежд на то, что уже существует что-то (даже на уровне математики... не программирование), чтобы помочь вам в этом.   -  person sarveshseri    schedule 30.01.2015
comment
sqrt и различные функции в math основаны на математической библиотеке C. Эта библиотека обычно обрабатывает только до предела двойного числа C, обычно 64-битного числа с плавающей запятой. 10^308 — это (абсолютный) максимум 64-битного числа с плавающей запятой (в соответствии со стандартом IEEE 754).   -  person    schedule 30.01.2015
comment
Обратите внимание, что цифры и размер числа не всегда совпадают: 10^309 имеет только 1 значащую цифру. Поэтому очень большие числа (1 миллион цифр) здесь не применимы.   -  person    schedule 30.01.2015
comment
Попробуйте переместить этот вопрос на mathoverflow.net, может быть, какой-нибудь математик подскажет вам...   -  person sarveshseri    schedule 30.01.2015
comment
Однако вы можете упростить задачу: разделите свои числа, например, на 10^100. Квадратный корень из 10^100 = 10^50. Затем вы можете использовать sqrt(a*b) = sqrt(a) * sqrt(b).   -  person    schedule 30.01.2015
comment
;-) Если вы пытаетесь ограничить свой алгоритм простого сита, вы также можете использовать округленное стоимость.   -  person Wolf    schedule 30.01.2015
comment
Я полагаю, что gmpy2 — это современное состояние для работы с действительно огромными числами в Python (я предвзят, потому что я создал его предшественник gmpy, но долгое время не проявлял активности ни в том, ни в другом — нынешние сопровождающие сделали классная работа). Попробуйте!   -  person Alex Martelli    schedule 30.01.2015
comment
Стандартные двойники IEEE-754 могут представлять только до 10 ** 308, независимо от значащих цифр, как обнаружил OP. Вам придется использовать стороннюю библиотеку для обработки больших чисел.   -  person Lee Daniel Crocker    schedule 30.01.2015
comment
@LeeDanielCrocker, правильно, а gmpy2 использует Python как оболочку для таких библиотек (GMP/MPIR, MPFR и т. д. -- см. gmpy2.readthedocs.org/en/latest/intro.html ).   -  person Alex Martelli    schedule 30.01.2015
comment
@AlexMartelli, быстрый тест в моей системе показывает, что gmpy2.isqrt может вычислить целочисленный квадратный корень из 1 000 0000-значного числа менее чем за 25 мс.   -  person casevh    schedule 30.01.2015
comment
@casevh спасибо, попробую gmpy2 и сообщу здесь, как дела. Хотя у меня есть еще один вопрос. Являются ли результаты точными?   -  person S Anwar    schedule 31.01.2015
comment
Результаты точны. Вам нужно использовать правильную функцию. isqrt вычисляет целочисленный квадратный корень. sqrt возвращает значение с плавающей запятой с множественной точностью, но вы можете увеличить точность до любого количества бит.   -  person casevh    schedule 31.01.2015
comment
@casevh, спасибо -- кстати, Кейс является текущим сопровождающим, которого я похвалил выше, и фактически инициатором gmpy2!-)   -  person Alex Martelli    schedule 31.01.2015


Ответы (3)


Упростите свою задачу, используя немного математики.

Обратите внимание, что sqrt(a*b) = sqrt(a) * sqrt(b) (по крайней мере, для реальных положительных чисел).

Итак, любое число больше, чем, скажем, 10^100, разделите на 10^100. Это a, а результат деления равен b, так что исходное число = a * b. Затем используйте квадратный корень из 10 ^ 100 (= 10 ^ 50), умножьте его на квадратный корень из b, и вы получите ответ.

На вашем примере:

import math
x = 10**309
a = 1e100
b = 1e209   # Note: you can't calculate this within Python; just use plain math here
y = 1e50 * math.sqrt(1e209)

Пример не очень круглого числа:

x = 3.1415 * 1e309
a = 1e100
b = 3.1415e209   # Again, just subtract the exponent: 309 - 100
y = 1e50 * math.sqrt(3.1415e209)

Или для целого числа, которое не является степенью 10, полностью записано:

x = 707070
x = 70.707 * 1e4  # note: even number in exponent
x = 70.707e4
a = 1e2  # sqrt(1e2) = 1e1 = 10
b = 70.707e2
y = 10 * sqrt(70.707e2)

Несколько заметок:

  • Python без проблем обрабатывает смехотворно большие целые числа. Для чисел с плавающей запятой он использует стандартные (C) соглашения и ограничивается 64-битной точностью. Вы почти всегда получаете числа с плавающей запятой, когда извлекаете квадратный корень из чего-либо.

  • 1e309 означает 10**309, а 3.1415e209 означает 3.1415 * 10**209. Это стандартное соглашение о программировании.

person Community    schedule 30.01.2015
comment
Я рад, что вы переработали свой первый черновик, я не успел попросить об этом вовремя :-) - person Wolf; 30.01.2015
comment
Привет @Evert, спасибо за идею ... но 10 ^ 309 было просто примером с высоким пределом. Я работаю со всеми целыми числами, а не только с 10, 100 или 1000. Так что это решение, хотя и элегантное, мне не подойдет. Однако, спасибо. Я ценю, что вы нашли время, чтобы ответить :) - person S Anwar; 31.01.2015
comment
@SAnwar Если вы не получили второй пример (который представляет собой просто большое целое число, не являющееся степенью числа 10), я добавил еще один пример, который может быть немного более понятным. - person ; 31.01.2015

Вам следует использовать модуль gmpy2 ( https://code.google.com/p/gmpy/ ). Он обеспечивает очень быструю арифметику с множественной точностью.

В моей системе операции с миллионными числами выполняются очень быстро.

In [8]: a=gmpy2.mpz('3'*1000000)
In [9]: %timeit gmpy2.isqrt(a)
10 loops, best of 3: 22.8 ms per loop
In [10]: %timeit (a+1)*(a-1)
10 loops, best of 3: 20.9 ms per loop

Работа с числами из 100 000 000 цифр занимает всего несколько секунд.

In [20]: a.num_digits(10)
Out[20]: 99995229
In [21]: %timeit gmpy2.isqrt(a)
1 loops, best of 3: 5.05 s per loop
In [22]: %timeit (a+1)*(a-1)
1 loops, best of 3: 3.49 s per loop

Отказ от ответственности: я являюсь текущим сопровождающим gmpy2.

person casevh    schedule 30.01.2015

Основываясь на том, что я считаю подобными вопросами, вы можно изучить с помощью класса Decimal.

Вот пример использования того, что у вас есть

    >>> x = 10**309
    >>> y =x**.5
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    OverflowError: long int too large to convert to float
    >>> import decimal
    >>> d = decimal.Decimal(x)
    >>> d.sqrt()
    Decimal('3.162277660168379331998893544E+154')
    >>> float(d.sqrt())
    3.1622776601683792e+154
    >>> 

Может быть полезно, это не дает вам вашей ошибки.

person CSCFCEM    schedule 30.01.2015
comment
Нет... Текущий уровень математики не дает ответа на этот вопрос. - person sarveshseri; 30.01.2015
comment
Имелось в виду скорее его конкретный пример. В целом я не согласен с тем, что есть числа, которые слишком велики для текущих вычислений. Я добавлю правку. - person CSCFCEM; 30.01.2015
comment
@CSCFCEM, есть числа, слишком большие для удобного размещения в памяти (включая пространство, необходимое для их обработки промежуточных результатов), но это, в зависимости от вашего объема оперативной памяти, составляет от многих миллионов до нескольких миллиардов цифр, а не сотни! Текущий уровень математики в порядке - просто установите gmpy2 и купите намного больше оперативной памяти!-) - person Alex Martelli; 30.01.2015
comment
Я согласен @AlexMartelli. Если я сказал что-то, из-за чего может показаться, что я не согласен, я буду рад исправить это. - person CSCFCEM; 30.01.2015
comment
@CSCFCEM, я не согласен с тем, что есть числа, которые слишком велики для текущих вычислений, и это звучит так, как будто вы не согласны, учитывая комментарий Сарвеша о текущем уровне математики (?!). Конечно, многие специфические форматы, используемые для чисел (например, float), имеют определенные ограничения (часто налагаемые аппаратным обеспечением, а не современной математикой или текущими вычислениями!-), но простое решение состоит в том, чтобы просто использовать разные форматы ( идеально поддерживается современной математикой для текущих вычислений - до тех пор, пока вы покупаете достаточно оперативной памяти :-). - person Alex Martelli; 30.01.2015
comment
Ах да, теперь я понимаю. Возможно, мне следовало сказать «эффективные вычисления»? Я просто не был полностью согласен с тем (и похоже, что вы со мной согласны), что на современном уровне математики нет ответа на этот вопрос. и пытался создать некую золотую середину. Я понимаю, что всегда есть больше огневой мощи (большее/лучшее оборудование), но для некоторых пользователей это может оказаться нецелесообразным. Ваше здоровье! - person CSCFCEM; 30.01.2015
comment
Под текущим уровнем математики... Я имею в виду исследования, проведенные для поиска алгоритмов для выполнения этих вычислений... Поскольку такие числа не помещаются в памяти... создаются специальные алгоритмы, чтобы разбить задачу на более мелкие выполнимые фрагменты. ... Если бы это была задача на сложение... вы бы справились с ней очень легко... потому что существуют очень и очень простые математические расчеты для сложения... но для квадратного корня... я не думаю, что такая математика теория существует. - person sarveshseri; 30.01.2015
comment
@CSCFCEM Не говоря уже об эффективности ... Я сомневаюсь в возможности выполнения. - person sarveshseri; 30.01.2015