Генерация цифр квадратного корня из 2
Я хочу сгенерировать цифры квадратного корня от двух до 3 миллиона цифр.
Я знаю Newton-Raphson, но у меня нет большой информации о том, как реализовать его на C или С++ из-за нехватки biginteger поддержка. Может ли кто-нибудь указать мне в правильном направлении?
Кроме того, если кто-нибудь знает, как это сделать в python (я новичок), я также был бы признателен.
Ответы
Ответ 1
Вы можете попробовать использовать сопоставление:
a/b -> (a+2b)/(a+b)
начиная с a= 1, b= 1
. Это сходится к sqrt (2) (на самом деле дает представление о продолжении дроби).
Теперь ключевой момент: это может быть представлено как матричное умножение (аналогично фибоначчи)
Если a_n и b_n - n-ые числа в шагах, тогда
[1 2] [a_n b_n] T= [a_ (n + 1) b_ (n + 1)] T
[1 1]
который теперь дает нам
[1 2] n [a_1 b_1] T= [a_ (n + 1) b_ (n + 1)] T
[1 1]
Таким образом, если матрица 2x2 равна A, нам нужно вычислить A n что может быть сделано путем повторного квадратирования и использует только целочисленную арифметику (так что вам не нужно беспокоиться о проблемах с точностью).
Также обратите внимание, что полученный вами a/b всегда будет в сокращенной форме (как gcd (a, b) = gcd (a + 2b, a + b)), поэтому, если вы думаете использовать класс фракций для представляют промежуточные результаты, не!
Так как n-ые знаменатели подобны (1 + sqrt (2)) ^ n, чтобы получить 3 миллиона цифр, вам, вероятно, потребуется вычислить до 3671656 th.
Обратите внимание, что даже если вы ищете ~ 3,6 млн. человек, повторное квадратирование позволит вам вычислить n-й член в O (Log n) умножениях и дополнениях.
Кроме того, это можно легко сделать параллельным, в отличие от итеративных, таких как Newton-Raphson и т.д.
Ответ 2
EDIT. Мне нравится эта версия лучше, чем предыдущая. Это общее решение, которое принимает как целые числа, так и десятичные дроби; с n = 2 и точностью = 100000, это занимает около двух минут. Спасибо Paul McGuire за его предложения и другие предложения приветствуются!
def sqrt_list(n, precision):
ndigits = [] # break n into list of digits
n_int = int(n)
n_fraction = n - n_int
while n_int: # generate list of digits of integral part
ndigits.append(n_int % 10)
n_int /= 10
if len(ndigits) % 2: ndigits.append(0) # ndigits will be processed in groups of 2
decimal_point_index = len(ndigits) / 2 # remember decimal point position
while n_fraction: # insert digits from fractional part
n_fraction *= 10
ndigits.insert(0, int(n_fraction))
n_fraction -= int(n_fraction)
if len(ndigits) % 2: ndigits.insert(0, 0) # ndigits will be processed in groups of 2
rootlist = []
root = carry = 0 # the algorithm
while root == 0 or (len(rootlist) < precision and (ndigits or carry != 0)):
carry = carry * 100
if ndigits: carry += ndigits.pop() * 10 + ndigits.pop()
x = 9
while (20 * root + x) * x > carry:
x -= 1
carry -= (20 * root + x) * x
root = root * 10 + x
rootlist.append(x)
return rootlist, decimal_point_index
Ответ 3
Как и для любых больших чисел, вы можете взглянуть на Библиотека многоточечной арифметики GNU (для C/С++).
Ответ 4
За работу? Используйте библиотеку!
Для удовольствия? Хорошо для вас:)
Напишите программу, чтобы подражать тому, что вы сделали бы с карандашом и бумагой. Начните с 1 цифры, затем 2 цифры, затем 3,...,...
Не беспокойся о Ньютоне или о ком-то еще. Просто сделайте это по-своему.
Ответ 5
Самый приятный способ, вероятно, состоит в использовании продолжения фракции [1; 2, 2, ...]
квадратного корня из двух.
def root_two_cf_expansion():
yield 1
while True:
yield 2
def z(a,b,c,d, contfrac):
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 decimal(contfrac):
return z(1,0,0,1,contfrac)
decimal((root_two_cf_expansion())
возвращает итератор всех десятичных цифр. t1
и t2
в алгоритме указаны минимальные и максимальные значения следующей цифры. Когда они равны, мы выводим эту цифру.
Обратите внимание, что это не обрабатывает некоторые исключительные случаи, такие как отрицательные числа в цепной дроби.
(Этот код является адаптацией кода Haskell для обработки продолжающихся дробей, которые плавали вокруг.)
Ответ 6
Вот короткая версия для вычисления квадратного корня из целых чисел a до цифр. Он работает путем нахождения целочисленного квадратного корня из a после умножения на 10 при увеличении до 2 x цифр.
def sqroot(a, digits):
a = a * (10**(2*digits))
x_prev = 0
x_next = 1 * (10**digits)
while x_prev != x_next:
x_prev = x_next
x_next = (x_prev + (a // x_prev)) >> 1
return x_next
Несколько предостережений.
Вам нужно преобразовать результат в строку и добавить десятичную точку в нужное место (если вы хотите напечатать десятичную точку).
Преобразование очень большого целого в строку не очень быстро.
Деление очень больших целых чисел происходит не очень быстро (в Python).
В зависимости от производительности вашей системы может потребоваться час или более, чтобы вычислить квадратный корень от 2 до 3 миллионов знаков после запятой.
Я не доказал, что цикл всегда заканчивается. Он может колебаться между двумя значениями, отличающимися в последней цифре. Или это не так.
Ответ 7
Ну, вот код, который я написал. Он сгенерировал миллион цифр после десятичного знака для квадратного корня из 2 примерно за 60800 секунд для меня, но мой ноутбук спал, когда он запускал программу, это должно быть быстрее. Вы можете попытаться сгенерировать 3 миллиона цифр, но для его получения может потребоваться несколько дней.
def sqrt(number,digits_after_decimal=20):
import time
start=time.time()
original_number=number
number=str(number)
list=[]
for a in range(len(number)):
if number[a]=='.':
decimal_point_locaiton=a
break
if a==len(number)-1:
number+='.'
decimal_point_locaiton=a+1
if decimal_point_locaiton/2!=round(decimal_point_locaiton/2):
number='0'+number
decimal_point_locaiton+=1
if len(number)/2!=round(len(number)/2):
number+='0'
number=number[:decimal_point_locaiton]+number[decimal_point_locaiton+1:]
decimal_point_ans=int((decimal_point_locaiton-2)/2)+1
for a in range(0,len(number),2):
if number[a]!='0':
list.append(eval(number[a:a+2]))
else:
try:
list.append(eval(number[a+1]))
except IndexError:
pass
p=0
c=list[0]
x=0
ans=''
for a in range(len(list)):
while c>=(20*p+x)*(x):
x+=1
y=(20*p+x-1)*(x-1)
p=p*10+x-1
ans+=str(x-1)
c-=y
try:
c=c*100+list[a+1]
except IndexError:
c=c*100
while c!=0:
x=0
while c>=(20*p+x)*(x):
x+=1
y=(20*p+x-1)*(x-1)
p=p*10+x-1
ans+=str(x-1)
c-=y
c=c*100
if len(ans)-decimal_point_ans>=digits_after_decimal:
break
ans=ans[:decimal_point_ans]+'.'+ans[decimal_point_ans:]
total=time.time()-start
return ans,total
Ответ 8
Python уже поддерживает большие целые числа из коробки, и если это единственное, что удерживает вас на C/С++, вы всегда можете написать быстрый контейнерный класс самостоятельно.
Единственная проблема, о которой вы говорили, - отсутствие больших целых чисел. Если вы не хотите использовать библиотеку для этого, то вы ищете помощь для написания такого класса?
Ответ 9
Здесь более эффективная функция с квадратным корнем (в Python 3.x), которая должна прерываться во всех случаях. Он начинается с числа, намного приближенного к квадратному корню, поэтому требуется меньше шагов. Обратите внимание, что для int.bit_length требуется Python 3.1+. Ошибка проверки оставлена для краткости.
def isqrt(n):
x = (n >> n.bit_length() // 2) + 1
result = (x + n // x) // 2
while abs(result - x) > 1:
x = result
result = (x + n // x) // 2
while result * result > n:
result -= 1
return result