n
비트 정수의 제곱근의 바닥을 계산하기위한 알려진 이차 알고리즘이 있습니까?
순진한 알고리즘은
def sqrt(x):
r = 0
i = x.bit_length() // 2
while i >= 0:
inc = (r << (i+1)) + (1 << (i*2))
if inc <= x:
x -= inc
r += 1 << i
i -= 1
return r
이 작업에는 O(n)
반복 작업 이 필요합니다 . 각 작업에는 O(n)
시간 이 더해진 작업이 포함 되므로 O(n^2)
전체 시간입니다. 더 빠른 것이 있습니까? 곱셈의 경우 2 차 시간보다 나은 특수 알고리즘이 있지만 제곱근에 대해서는 아무것도 찾을 수 없다는 것을 알고 있습니다.
답변
다항식의 근에 근사값을 구하기 위해 Newton의 방법 또는 다른 여러 방법을 사용할 수 있습니다
p(x)=x2−c.
Newton의 방법에 대한 수렴 속도는 2 차적입니다. 즉, 올바른 반복 횟수는 각 반복에서 두 배가됩니다. 이것은 의미
O(lgn)뉴턴의 방법으로 충분하다.
뉴턴 방법의 각 반복 계산
곱셈의 비트 복잡성은
O (blgb)두 곱하기
b비트 정수 (무시)
lglgb요인). 나누기의 비트 복잡도
b정밀도의 비트)는 동일합니다. 따라서 각 반복은
O (nlgn)작업. 에 의해 곱하기
O(lgn)반복, 우리는 제곱근을 계산하는 전체 실행 시간을
n정밀한 비트는
O (n(lgn)2). 이것은 이차 이하입니다.
더 신중한 분석에 따르면 이것이 향상 될 수 있다고 생각합니다.
영형 (엔lg엔)러닝 타임 (각각 알아야 할 것을 고려하여
xj~ 안에
j정밀도가 아닌 비트
n정밀한 비트). 그러나 더 기본적인 분석조차도 이미 이차적 인 실행 시간을 보여줍니다.
답변
Newton의 방법의 문제점 중 하나는 각 반복마다 나누기 연산이 필요하다는 것입니다. 이는 가장 느린 기본 정수 연산입니다.
그러나 역 제곱근에 대한 뉴턴의 방법은 그렇지 않습니다. 만약
엑스찾고자하는 번호입니다
1엑스반복 :
이것은 종종 다음과 같이 표현됩니다 :
세 번의 곱셈 연산입니다. 2 개로 나누는 것은 오른쪽 이동으로 구현할 수 있습니다.
이제 문제는
r정수가 아닙니다. 그러나 부동 소수점을 수동으로 구현하고 적절한 경우 보상하기 위해 많은 시프트 연산을 수행하여이를 조작 할 수 있습니다.
먼저 크기를 조정하겠습니다
x:
우리가 원하는 곳
x′보다 크지 만 가까이 있어야합니다
1. 위의 알고리즘을 실행하면
x′대신에
x, 우리는 찾는다
r=1x′. 그때,
x=2erx′.
이제 나누자
r가수와 지수로 :
어디
ri′정수입니다. 직관적으로
ei답의 정확성을 나타냅니다.
우리는 뉴턴의 방법이 정확한 유효 자릿수의 두 배를 가짐을 알고 있습니다. 그래서 우리는 선택할 수 있습니다 :
약간의 조작만으로 우리는 다음을 발견합니다.
반복 할 때마다 :
예를 들어, 제곱근을 계산해 봅시다
x=263. 우리는 그 답이
2312. 상호 제곱근은
122−31그래서 우리는 설정합니다
e=31(이것은 문제의 규모입니다) 첫 번째 추측을 위해 우리는 선택할 것입니다
r0′=3과
e0=2. (즉, 우리는
34초기 추정치
12.)
그때:
우리는 반복을 멈추는 시점을 비교하여 해결할 수 있습니다.
ei에
e; 내가 정확하게 계산했다면
ei>2e충분해야합니다. 우리는 여기서 멈추고 다음을 찾습니다.
올바른 정수 제곱근은
3037000499우리는 아주 가깝습니다. 또 다른 반복을 수행하거나 최적화되지 않은 최종 반복을 수행 할 수 있습니다.
ei. 세부 사항은 연습으로 남습니다.
To analyse the complexity of this method, note that multiplying two
b-bit integers takes
O(blogb)operations. However, we have arranged things so that
ri′<2ei. So the multiplication to calculate
wimultiplies two
ei-bit numbers to produce a
ei+1-bit number, and the other two multiplications multiply two
ei+1-bit numbers to produce a
2ei+1-bit number.
In each case, the number of operations per iteration is
O(eilogei), and there are
O(loge)iterations required. The final multiplication is on the order of
O(2elog2e)operations. So the overall complexity is
O(elog2e)operations, which is sub-quadratic in the number of bits in
x. That ticks all the boxes.
However, this analysis hides an important principle which everyone working with large integers should keep in mind: because multiplication is superlinear in the number of bits, any multiplication operations should only be performed on integers which have the roughly the magnitude of the current precision (and, I might add, you should try to multiply numbers together which have a similar order of magnitude). Using integers larger than that is a waste of effort. Constant factors matter, and for large integers, they matter a lot.
As a final observation, two of the multiplications are of the form
ab2c. Clearly it's wasteful to compute the all the bits of
abonly to throw
cof them away with a right-shift. Implementing a smart multiplication method which takes this into account is also left as an exercise.