Articulo de referencia

Raíz cuadrada entera

En teoría de números , la raíz cuadrada entera (isqrt) de un entero no negativo n es el entero no negativo m que es el mayor entero menor o igual que la raíz cuadrada de n , esq...

En teoría de números , la raíz cuadrada entera (isqrt) de un entero no negativo n es el entero no negativo m que es el mayor entero menor o igual que la raíz cuadrada de n , esqrt(norte)=norte.{\displaystyle \operatorname {isqrt} (n)=\lfloor {\sqrt {n}}\rfloor .}

Por ejemplo,esqrt(27)=27=5.19615242270663...=5.{\displaystyle \operatorname {isqrt} (27)=\lfloor {\sqrt {27}}\rfloor =\lfloor 5.19615242270663...\rfloor =5.}

Observación introductoria

Dejary{\displaystyle y}yk{\displaystyle k}sean números enteros no negativos.

Algoritmos que calculan (la representación decimal de)y{\displaystyle {\sqrt {y}}}ejecutarse indefinidamente en cada entraday{\displaystyle y}que no es un cuadrado perfecto . [ nota 1 ]

Algoritmos que calculany{\displaystyle \lfloor {\sqrt {y}}\rfloor }no funcionan para siempre . Sin embargo, son capaces de calcular.y{\displaystyle {\sqrt {y}}}hasta cualquier precisión deseadak{\displaystyle k}.

Elige cualquierak{\displaystyle k}y calculary×100k{\textstyle \lfloor {\sqrt {y\times 100^{k}}}\rfloor }.

Por ejemplo (configuracióny=2{\displaystyle y=2}): k=0:2×1000=2=1k=1:2×1001=200=14k=2:2×1002=20000=141k=3:2×1003=2.000.000=1414k=8:2×1008=20000000000000000=141421356{\displaystyle {\begin{aligned}&k=0:\lfloor {\sqrt {2\times 100^{0}}}\rfloor =\lfloor {\sqrt {2}}\rfloor =1\\&k=1:\lfloor {\sqrt {2\times 100^{1}}}\rfloor =\lfloor {\sqrt {200}}\rfloor =14\\&k=2:\lfloor {\sqrt {2\times 100^{2}}}\rfloor =\lfloor {\sqrt {20000}}\rfloor =141\\&k=3:\lfloor {\sqrt {2\times 100^{3}}}\rfloor =\lfloor {\sqrt {2000000}}\rfloor =1414\\&\vdots \\&k=8:\lfloor {\sqrt {2\times 100^{8}}}\rfloor =\lfloor {\sqrt {20000000000000000}}\rfloor =141421356\\&\vdots \\\end{aligned}}}

Compare los resultados con2=1.41421356237309504880168872420969807856967187537694...{\displaystyle {\sqrt {2}}=1.41421356237309504880168872420969807856967187537694...}

Parece que la multiplicación de la entrada por100k{\displaystyle 100^{k}}proporciona una precisión de k dígitos decimales. [ nota 2 ]

Para calcular la representación decimal (completa) dey{\displaystyle {\sqrt {y}}}, uno puede ejecutaresqrt(y){\displaystyle \operatorname {isqrt} (y)}un número infinito de veces, aumentandoy{\displaystyle y}por un factor100{\displaystyle 100}en cada pasada.

Supongamos que en el siguiente programa (raíz cuadrada para siempre{\displaystyle \operatorname {sqrtForever} }) el procedimientoesqrt(y){\displaystyle \operatorname {isqrt} (y)}ya está definido y —para efectos de la argumentación— que todas las variables pueden contener números enteros de magnitud ilimitada.

Entoncesraíz cuadrada para siempre(y){\displaystyle \operatorname {sqrtForever} (y)}imprimirá la representación decimal completa dey{\displaystyle {\sqrt {y}}}. [ nota 3 ]

import math # se asume el cálculo de isqrt como se indica aquídef sqrtForever ( y : int ): """ Imprime sqrt(y), sin detenerse """ result = math.isqrt ( y ) print ( str ( result ) + "." , end = " " ) # Imprime el resultado, seguido de un punto decimalwhile True : # repetir indefinidamente ... y *= 100 # ejemplo teórico: el desbordamiento se ignora result = math . isqrt ( y ) print ( str ( result % 10 ), end = "" ) # imprimir el último dígito de result

La conclusión es que los algoritmos que calculan isqrt()son computacionalmente equivalentes a los algoritmos que calculansqrt() .

Otra derivación dey{\displaystyle {\sqrt {y}}}dey{\displaystyle \lfloor {\sqrt {y}}\rfloor }se da en la sección Fracción continua de √c basada en isqrt a continuación.

Algoritmos básicos

La raíz cuadrada entera de un número entero no negativoy{\displaystyle y}puede definirse como y=máximo{incógnita:incógnita2y<(incógnita+1)2,incógnitanorte}{\displaystyle \lfloor {\sqrt {y}}\rfloor =\max\{x:x^{2}\leq y<(x+1)^{2},x\in \mathbb {N} \}}

Por ejemplo,esqrt(27)=27=5{\displaystyle \operatorname {isqrt} (27)=\lfloor {\sqrt {27}}\rfloor =5}porque62>27 y 5227{\displaystyle 6^{2}>27{\text{ y }}5^{2}\ngtr 27}.

Los siguientes programas en Python son implementaciones sencillas.

def isqrt ( y : int ) -> int : """  Raíz cuadrada entera  (búsqueda lineal, ascendente)  """ # subestimación inicial, L <= isqrt(y) L = 0 while ( L + 1 ) * ( L + 1 ) <= y : L += 1regresar L
def isqrt ( y : int ) -> int : """  Raíz cuadrada entera  (búsqueda lineal, descendente)  """ # sobreestimación inicial, isqrt(y) <= R R = y while ( R * R > y ): R -= 1devolver R

Búsqueda lineal mediante suma

En el programa anterior (búsqueda lineal, ascendente) se puede reemplazar la multiplicación por la suma, utilizando la equivalencia (L+1)2=L2+2L+1=L2+1+i=1L2.{\displaystyle (L+1)^{2}=L^{2}+2L+1=L^{2}+1+\sum _ {i=1}^{L}2.}

def isqrt ( y : int ) -> int : """  Raíz cuadrada entera  (búsqueda lineal, ascendente) usando suma  """ L = 0 a = 1 d = 3mientras a <= y : a = a + d d = d + 2 L = L + 1regresar L

La búsqueda lineal comprueba secuencialmente cada valor hasta que encuentra el más pequeño.incógnita{\displaystyle x}dóndeincógnita2>y{\displaystyle x^{2}>y}.

Se consigue una mayor velocidad utilizando la búsqueda binaria .

def isqrt ( y : int ) -> int : """ Raíz cuadrada entera (búsqueda binaria) """ L = 0 # límite inferior de la raíz cuadrada R = y + 1 # límite superior de la raíz cuadradamientras ( L != R - 1 ): M = ( L + R ) // 2 # punto medio para probar si ( M * M <= y ): L = M sino : R = Mregresar L

Ejemplos numéricos

  • esqrt(0)=0{\displaystyle \operatorname {isqrt} (0)=0},esqrt(1)=1{\displaystyle \operatorname {isqrt} (1)=1}.
  • Utilizando la búsqueda binaria, el cálculo deesqrt(131072){\displaystyle \operatorname {isqrt} (131072)}converge a362{\displaystyle 362}en17{\displaystyle 17}pasos de iteración a través del[L,R]{\displaystyle [L,R]}secuencia
[0,131073][0,65536][0,32768][0,16384][0,8192][0,4096][0,2048][0,1024][0,512][256,512][256,384][320,384][352,384][352,368][360,368][360,364][362,364][362,363]{\displaystyle {\begin{aligned}&[0,131073]\to [0,65536]\to [0,32768]\to [0,16384]\to [0,8192]\to [0,4096]\rightarrow [0,2048]\to [0,1024]\to [0,512]\\&\to [256,512]\to [256,384]\to [320,384]\to [352,384]\to [352,368]\to [360,368]\to [360,364]\to [362,364]\to [362,363]\end{aligned}}}
  • El cálculo deesqrt(2.000.000){\displaystyle \operatorname {isqrt} (2000000)}converge a1414{\displaystyle 1414}en21{\displaystyle 21}pasos a través del[L,R]{\displaystyle [L,R]}secuencia
[0,2000001][0,1.000.000][0,500000][0,250000][0,125000][0,62500][0,31250][0,15625][0,7812][0,3906][0,1953][976,1953][976,1464][1220,1464][1342,1464][1403,1464][1403,1433][1403,1418][1410,1418][1414,1418][1414,1416][1414,1415]{\displaystyle {\begin{aligned}&[0,2000001]\to [0,1000000]\to [0,500000]\to [0,250000]\to [0,125000]\to [0,62500]\to [0,31250]\to [0,15625]\\&\to [0,7812]\to [0,3906]\to [0,1953]\to [976,1953]\to [976,1464]\to [1220,1464]\to [1342,1464]\to [1403,1464]\\&\to [1403,1433]\to [1403,1418]\to [1410,1418]\to [1414,1418]\to [1414,1416]\to [1414,1415]\end{aligned}}}
Búsqueda lineal (ascendente, comenzando desde0{\displaystyle 0}) necesidades1414 escalones.

Algoritmo que utiliza el método de Newton

Una forma de calcularnorte{\displaystyle {\sqrt {n}}}yesqrt(norte){\displaystyle \operatorname {isqrt} (n)}es utilizar el método de Herón , que es un caso especial del método de Newton , para encontrar una solución para la ecuaciónincógnita2norte=0{\displaystyle x^{2}-n=0}, dando como resultado la fórmula iterativa incógnitak+1=12(incógnitak+norteincógnitak),k0,incógnita0>0.{\displaystyle x_{k+1}={\frac {1}{2}}\!\left(x_{k}+{\frac {n}{x_{k}}}\right),\quad k\geq 0,\quad x_{0}>0.}

La secuencia{incógnitak}{\displaystyle \{x_{k}\}}converge cuadráticamente anorte{\displaystyle {\sqrt {n}}}comok{\displaystyle k\to \infty }. [ 1 ] [ nota 4 ]

Utilizando únicamente la división entera

Para computaciónnorte{\displaystyle \lfloor {\sqrt {n}}\rfloor }Se puede utilizar el cociente de la división euclidiana para ambas operaciones de división. Esto tiene la ventaja de usar solo números enteros para cada valor intermedio, lo que hace innecesario el uso de representaciones de punto flotante .

Dejarnorte>0{\displaystyle n>0}y suposición inicialincógnita0>0{\displaystyle x_{0}>0}. Defina la secuencia de enteros:

incógnitak+1=incógnitak+norte/incógnitak2,k=0,1,2,{\displaystyle x_{k+1}=\left\lfloor {\frac {x_{k}+\left\lfloor n/x_{k}\right\rfloor }{2}}\right\rfloor ,\quad k=0,1,2,\dots }

Prueba de convergencia

1. Positividad: Todos los términos son números enteros positivos:incógnitak>0{\displaystyle x_{k}>0}a pesar dek{\displaystyle k}.

2. Monotonía:

  • Siincógnitak>norte{\displaystyle x_{k}>{\sqrt {n}}}, entoncesnorte/incógnitaknorte/incógnitak{\displaystyle \lfloor n/x_{k}\rfloor \leq n/x_{k}};
entoncesincógnitak+1=incógnitak+norte/incógnitak2<incógnitak+norte/incógnitak2<incógnitak{\displaystyle x_{k+1}=\left\lfloor {\frac {x_{k}+\lfloor n/x_{k}\rfloor }{2}}\right\rfloor <{\frac {x_{k}+n/x_{k}}{2}}<x_{k}}.
Por lo tanto, la secuencia disminuye.
  • Siincógnitak<norte{\displaystyle x_{k}<{\sqrt {n}}}, entoncesnorte/incógnitaknorte/incógnitak1{\displaystyle \lfloor n/x_{k}\rfloor \geq n/x_{k}-1};
entoncesincógnitak+1incógnitak+norte/incógnitak12>incógnitak1{\displaystyle x_{k+1}\geq {\frac {x_{k}+n/x_{k}-1}{2}}>x_{k}-1}.
Por lo tanto, la secuencia aumenta o permanece igual.

3. Acotación: La sucesión está acotada inferiormente por 1 y superiormente porincógnita0{\displaystyle x_{0}}, por lo tanto, está delimitado.

4. Estabilización / Oscilación: Una secuencia de enteros monótona y acotada se estabiliza u oscila entre dos enteros consecutivos:

incógnitak+1=incógnitak{\displaystyle x_{k+1}=x_{k}}oincógnitak+1=incógnitak±1{\displaystyle x_{k+1}=x_{k}\pm 1}.

5. Condición de "punto fijo" entero: En la estabilización o la oscilación:

incógnitak+1=(incógnitak+norte/incógnitak)/2{\displaystyle x_{k+1}=\lfloor (x_{k}+\lfloor n/x_{k}\rfloor )/2\rfloor }.
Esto garantiza que la secuencia esté ennorte{\displaystyle \lfloor {\sqrt {n}}\rfloor }o oscilando entre los dos enteros más cercanos alrededornorte{\displaystyle {\sqrt {n}}}.

6. Conclusión: La secuencia finalmente se estabiliza ennorte{\displaystyle \lfloor {\sqrt {n}}\rfloor }o oscila entrenorte{\displaystyle \lfloor {\sqrt {n}}\rfloor }ynorte{\displaystyle \lceil {\sqrt {n}}\rceil }.

Observación:

  • norte{\displaystyle \lfloor {\sqrt {n}}\rfloor }es un punto fijo estricto a menos quenorte+1{\displaystyle n+1}es un cuadrado perfecto.
  • Sinorte+1{\displaystyle n+1}es un cuadrado perfecto, la secuencia oscila entrenorte{\displaystyle \lfloor {\sqrt {n}}\rfloor }ynorte{\displaystyle \lceil {\sqrt {n}}\rceil }.

Ejemplo de implementación

def isqrt ( n : int , x0 : int = 1 ) -> int : """  isqrt mediante iteración de Newton-Heron con estimación inicial especificada.  Utiliza detección de oscilación de 2 ciclos. Precondiciones:  n >= 0 # isqrt(0) = 0  x0 > 0, por defecto es 1 # estimación inicial Salida:  isqrt(n)  """ assert n >= 0 and x0 > 0 , "Entrada no válida"# isqrt(0) = 0; isqrt(1) = 1 si n < 2 : devuelve nprev2 = - 1 # x_{i-2} prev1 = x0 # x_{i-1}mientras sea verdadero : x1 = ( prev1 + n // prev1 ) // 2# Caso 1: convergencia (valor estable) si x1 == prev1 : devolver x1# Caso 2: oscilación (ciclo 2) si x1 == prev2 y x1 != prev1 : # Estamos alternando entre prev1 y prev2 # Elegimos el menor (la raíz cuadrada del entero verdadero) devolver min ( prev1 , x1 )# Avanzar prev2 , prev1 = prev1 , x1

Ejemplos numéricos

La llamada isqrt(2000000)converge a1414{\displaystyle 1414}en 14 pasos a través de while:

1.000.0005000012500021250046250931270156667896407422821579142214141414{\displaystyle {\begin{aligned}&1000000\to 500001\to 250002\to 125004\to 62509\to 31270\to 15666\to 7896\to 4074\to 2282\\&\to 1579\to 1422\to 1414\rightarrow 1414\end{aligned}}}.

Se obtiene una iteración al establecer x0ennorte/2{\displaystyle \lfloor n/2\rfloor }con la llamada isqrt(2000000, 1000000). Aunque el método de Heron converge cuadráticamente cerca de la solución, se gana menos de un bit de precisión por iteración al principio. Esto significa que la elección de la estimación inicial es crítica para el rendimiento del algoritmo. [ nota 5 ] Cuando se dispone de un cálculo rápido para la parte entera del logaritmo binario o para la longitud en bitsn.bit_length() (como por ejemplo en Python ), es mejor comenzar enincógnita0=2(registro2norte)/2+1,{\displaystyle x_{0}=2^{\lfloor (\log _{2}n)/2\rfloor +1},}que es la menor potencia de dos mayor quenorte{\displaystyle {\sqrt {n}}}. En el ejemplo de la raíz cuadrada entera de 2000000 ,registro2norte=20{\displaystyle \lfloor \log _{2}n\rfloor =20},incógnita0=211=2048{\displaystyle x_{0}=2^{11}=2048}y la secuencia resultante es 20481512141714141414.{\displaystyle 2048\rightarrow 1512\rightarrow 1417\rightarrow 1414\rightarrow 1414.}En este caso solo se necesitan cuatro pasos de iteración. Esto corresponde a la llamada isqrt(2000000, 2048).

Algoritmo dígito por dígito

El algoritmo tradicional de lápiz y papel para calcular la raíz cuadradanorte{\displaystyle {\sqrt {n}}}Se basa en trabajar desde las posiciones de dígitos más altas hacia las más bajas, y a medida que cada nuevo dígito elige el más grande que aún produzca un cuadrado.norte{\displaystyle \leq n}. Si se detiene después de la posición de las unidades, el resultado calculado será la raíz cuadrada entera.

Utilizando operaciones bit a bit

Si se trabaja en base 2 , la elección del dígito se simplifica a uno entre 0 (el "candidato pequeño") y 1 (el "candidato grande"), y las manipulaciones de dígitos se pueden expresar en términos de operaciones de desplazamiento binario. Siendo *la multiplicación, el desplazamiento a la izquierda y el desplazamiento lógico a la derecha, un algoritmo recursivo para hallar la raíz cuadrada entera de cualquier número natural es:<<>>

def isqrt_recursive ( n : int ) -> int : assert n >= 0 , "n debe ser un entero no negativo" if n < 2 : return n# Llamada recursiva: small_cand = isqrt_recursive ( n >> 2 ) << 1 # equivalente a 2 * isqrt(n // 4) large_cand = small_cand + 1 if large_cand * large_cand > n : return small_cand else : return large_cand

Programa equivalente no recursivo: [ 2 ] [ nota 6 ]

def isqrt_iterative ( x : int ) -> int : """ Guy, Martin (1985). "Raíz cuadrada de enteros rápida mediante el algoritmo del ábaco del Sr. Woo" """ assert x >= 0 , "x debe ser un entero no negativo"op = x ; res = 0# nota: i << 1 es 2 * i, i << 2 es 4 * i, # i >> 1 es i // 2, e i >> 2 es i // 4...# "uno" comienza en la potencia más alta de cuatro <= x uno = 1 mientras uno <= op : uno <<= 2 uno >>= 2mientras uno != 0 : dltasqr = res + uno si op >= dltasqr : op -= dltasqr res += uno << 1 res >>= 1 uno >>= 2retorno res

Véase Métodos para calcular raíces cuadradas §  Sistema de numeración binario (base 2) para un ejemplo. [ 2 ]

Algoritmo de raíz cuadrada de Karatsuba

El algoritmo de raíz cuadrada de Karatsuba aplica el mismo principio de divide y vencerás que el algoritmo de multiplicación de Karatsuba para calcular raíces cuadradas de números enteros. El método fue analizado formalmente por Paul Zimmermann (1999). [ 3 ] Divide recursivamente el número de entrada en dos mitades, calcula la raíz cuadrada de la mitad superior y luego determina la mitad inferior algebraicamente.

Algoritmo

Paul Zimmermann (1999) proporciona el siguiente algoritmo. [ 3 ]

Algoritmo Raíz cuadrada(norte=a3b3+a2b2+a1b+a0){\displaystyle {\text{Algorithm }}{\text{SqrtRem}}(n=a_{3}b^{3}+a_{2}b^{2}+a_{1}b+a_{0})}
Aporte: 0ai<b, con a3b/4{\displaystyle {\text{Input: }}0\leq a_{i}<b,{\text{ with }}a_{3}\geq b/4}
Producción: (s,r) de tal manera que s2norte=s2+r<(s+1)2{\displaystyle {\text{Output: }}(s,r){\text{ such that }}s^{2}\leq n=s^{2}+r<(s+1)^{2}}
(s,r)Raíz cuadrada(a3b+a2){\displaystyle \qquad (s',r')\gets {\text{SqrtRem}}(a_{3}b+a_{2})}
(q,)DivRem(rb+a1,2s){\displaystyle \qquad (q,u)\gets {\text{DivRem}}(r'b+a_{1},2s')}
ssb+q{\displaystyle \qquad s\gets s'b+q}
rb+a0q2{\displaystyle \qquad r\gets ub+a_{0}-q^{2}}
si r<0 entonces {\displaystyle \qquad {\text{if }}r<0{\text{ then }}}
rr+2s1{\displaystyle \qquad \qquad r\gets r+2s-1}
ss1{\displaystyle \qquad \qquad s\gets s-1}
devolver (s,r){\displaystyle \qquad {\text{return }}(s,r)}

Debido a que solo se realiza una llamada recursiva por nivel, la complejidad total permaneceO(norte){\displaystyle O(n)}en número de bits. Cada nivel realiza únicamente aritmética de tiempo lineal sobre números de tamaño reducido.

Comparación con la multiplicación de Karatsuba

Uso e historia

La raíz cuadrada al estilo Karatsuba se utiliza principalmente para aritmética de precisión arbitraria en enteros muy grandes, donde se combina eficientemente con la división de Burnikel-Ziegler y la multiplicación de Karatsuba . Fue analizada formalmente por primera vez por Paul Zimmermann (1999). [ 3 ] Trabajos prácticos anteriores incluyen a Martin Guy (1985), [ 2 ] y versiones recursivas aparecen en Donald Knuth (1998). [ 4 ] Las bibliotecas modernas GMP y MPIR implementan técnicas recursivas similares.

Implementación en Python

El siguiente programa en Python implementa el algoritmo de Zimmermann. Dado un número enteronorte0{\displaystyle n\geq 0}, SqrtRemcalcula simultáneamente su raíz cuadrada enteras=norte{\displaystyle s=\lfloor {\sqrt {n}}\rfloor }y el resto correspondienter=nortes2{\displaystyle r=n-s^{2}}La elección isqrt()es a voluntad . [ nota 5 ]

def SqrtRem ( n : int , word_bits : int = 32 ) -> tuple [ int , int ]: """  Implementación basada en el algoritmo de raíz cuadrada entera estilo Karatsuba de Zimmermann  [Zimmermann, 1999]. Divide recursivamente la entrada n en "ramas"  de tamaño `word_bits` y combina resultados parciales para calcular la raíz cuadrada entera. Argumentos:  n (int): Entero no negativo del que calcular la raíz cuadrada.  word_bits (int, opcional): Número de bits por "rama" o fragmento  utilizado al dividir recursivamente n. El valor predeterminado es 32. Cada  rama representa una parte de tamaño fijo de n para el algoritmo. Devuelve:  tupla[int, int]: s = raíz cuadrada entera de n, r = resto (n - s*s). Notas:  El tamaño de la rama controla la granularidad de la recursión. Un valor mayor de word_bits  reduce la profundidad de la recursión, pero aumenta el tamaño de los subproblemas;  un valor menor de word_bits aumenta la profundidad de la recursión, pero trabaja con fragmentos más pequeños. Referencia:  Zimmermann, P. (1999). "Karatsuba Square Root", Informe de investigación n.° 3805, Inria.  Archivado en: https://inria.hal.science/inria-00072854v1/file/RR-3805.pdf  """ if n < 0 : raise ValueError ( "n debe ser no negativo" ) if n == 0 : return 0 , 0 # caso trivial# Determinar el número de ramas del tamaño de una palabra (imita la división de "ramas" en Zimmermann) limblen = ( n . bit_length () + word_bits - 1 ) // word_bits# Caso base: extremidad única — calcular directamente si limblen <= 1 : s = isqrt ( n ) # cualquier isqrt, por ejemplo, math.isqrt o personalizado r = n - s * s return s , r# --- Paso 1: Dividir n en partes alta y baja --- half_limbs = limblen // 2 shift = half_limbs * word_bits hi = n >> shift # mitad alta, corresponde a a3*b + a2 lo = n & (( 1 << shift ) - 1 ) # mitad baja, corresponde a a1*b + a0# --- Paso 2: Llamada recursiva en la parte superior --- s_high , r_high = SqrtRem ( hi , word_bits ) # raíz cuadrada aproximada de la mitad superior# --- Paso 3: Recombinar para aproximar la raíz cuadrada completa --- cuarto = desplazamiento // 2 numerador = ( r_alto << cuarto ) | ( lo >> cuarto ) # simular el paso DivRem de Zimmermann denominador = s_alto << 1 # término de 2*sq = numerador // denominador si denominador sino 0 # división entera s_candidato = ( s_alto << cuarto ) + q # recombinar alto y bajo# --- Paso 4: Verificación y corrección --- # Asegúrese de que el resto sea no negativo y s*s <= n < (s+1)*(s+1) s = s_candidate r = n - s * smientras r < 0 : # corrección de sobreestimación s -= 1 r = n - s * s mientras ( s + 1 ) * ( s + 1 ) <= n : # corrección de subestimación s += 1 r = n - s * sdevolver s , r

Ejemplo de uso

para n en [( 2 ** 32 ) + 5 , 12345678901234567890 , ( 1 << 1512 ) - 1 ]: s , r = SqrtRem ( n ) print ( f "SqrtRem( { n } ) = { s } , resto = { r } " )

En lenguajes de programación

Algunos lenguajes de programación dedican una operación explícita al cálculo de la raíz cuadrada de números enteros, además del caso general, o pueden ampliarse mediante bibliotecas para este fin.

Fracción continua de √c basada en isqrt

El cálculo de la fracción continua simple dedo{\displaystyle {\sqrt {c}}}se puede realizar utilizando únicamente operaciones con enteros, conesqrt(do){\displaystyle \operatorname {isqrt} (c)}sirviendo como término inicial. El algoritmo [ 23 ] genera una expansión de fracción continua en forma canónica .

Dejara0=do{\displaystyle a_{0}=\lfloor {\sqrt {c}}\rfloor } sea ​​la raíz cuadrada entera dedo{\displaystyle c}.

Sido{\displaystyle c}Si es un cuadrado perfecto, la fracción continua termina inmediatamente:

do=[a0].{\displaystyle {\sqrt {c}}=[a_{0}].}

De lo contrario, la fracción continua es periódica:

do=[a0;a1,a2,,ametro¯]{\displaystyle {\sqrt {c}}=[a_{0};{\overline {a_{1},a_{2},\dots ,a_{m}}}]},

donde la línea superior indica la parte que se repite.

La fracción continua se puede obtener mediante la siguiente recurrencia, que utiliza únicamente aritmética de enteros:

metro0=0,d0=1,a0=do.{\displaystyle m_{0}=0,\quad d_{0}=1,\quad a_{0}=\lfloor {\sqrt {c}}\rfloor .}
Parak0{\displaystyle k\geq 0},
metrok+1=dkakmetrok,dk+1=dometrok+12dk,ak+1=a0+metrok+1dk+1.{\displaystyle m_{k+1}=d_{k}a_{k}-m_{k},\quad d_{k+1}={\frac {c-m_{k+1}^{2}}{d_{k}}},\quad a_{k+1}=\left\lfloor {\frac {a_{0}+m_{k+1}}{d_{k+1}}}\right\rfloor .}

Dado que solo hay un número finito de triples posibles(metrok,dk,ak){\displaystyle (m_{k},d_{k},a_{k})}, finalmente se repite, y a partir de ese momento la fracción continua se vuelve periódica.

Implementación en Python

En la entradado{\displaystyle c}, un entero no negativo, el siguiente programa calcula la fracción continua simple dedo{\displaystyle {\sqrt {c}}}La raíz cuadrada enterado{\displaystyle \lfloor {\sqrt {c}}\rfloor }se calcula una vez. [ nota 5 ] Solo se utiliza aritmética de enteros. El programa muestra[a0,(a1,a2,...,ametro)]{\displaystyle [a0,(a1,a2,...,am)]}, donde el segundo elemento es la parte periódica.

def continue_fraction_sqrt ( c : int ) -> tuple [ int , tuple [ int , ... ]]: """  Calcula la fracción continua de sqrt(c) usando aritmética de enteros.  Devuelve [a0, (a1, a2, ..., am)] donde el segundo elemento es la parte periódica.  Para cuadrados perfectos, el período está vacío.  """ a0 = isqrt ( c ) # Cuadrado perfecto: devuelve el período vacío if a0 * a0 == c : return ( a0 , ())m , d , a = 0 , 1 , a0 periodo = [] visto = conjunto ()Mientras sea verdadero : m_next = d * a - m d_next = ( c - m_next * m_next ) // d a_next = ( a0 + m_next ) // d_nextSi ( m_next , d_next , a_next ) está en seen : breakvisto . agregar (( m_next , d_next , a_next )) período . agregar ( a_next ) m , d , a = m_next , d_next , a_nextdevolver ( a0 , tupla ( período ))

Ejemplo de uso

para c en lista ( rango ( 0 , 18 )) + [ 114 ] + [ 4097280036 ]: cf = continue_fraction_sqrt ( c ) print ( f "sqrt( { c } ): { cf } " )

Producción

Véase también

Notas

  1. Las raíces cuadradas de los cuadrados perfectos (por ejemplo, 0, 1, 4, 9, 16) son números enteros. En todos los demás casos, las raíces cuadradas de los enteros positivos son números irracionales.
  2. No sorprende que la multiplicación repetida por 100 sea una característica en Jarvis (2006).
  3. La parte fraccionaria de las raíces cuadradas de cuadrados perfectos se representa como 000... .
  4. Véase el método de Herón .
  5. 1 2 3 El método de Newton se puede expresar de la siguiente manera(con la estimación inicial establecida ens{\displaystyle s}):
    def isqrt ( s : int ) -> int : """isqrt mediante iteración de Newton/Heron.""" L , R = 1 , s while L < R : R = L + (( R - L ) // 2 ) L = s // R return R
    Cálculos
    • esqrt(0)=0{\displaystyle \operatorname {isqrt} (0)=0},esqrt(1)=1{\displaystyle \operatorname {isqrt} (1)=1}.
    • El cálculo deesqrt(2.000.000){\displaystyle \operatorname {isqrt} (2000000)}consiste en13[L,R]{\displaystyle 13\;[L,R]}pasos:
    [1,2.000.000][2,1.000.000][3,500001][7,250002][15,125004][31,62509][63,31270][127,15666][253,7896][490,4074][876,2282][1266,1579][1406,1422][1414,1414]{\displaystyle {\begin{aligned}&[1,2000000]\to [2,1000000]\to [3,500001]\\&\to [7,250002]\to [15,125004]\to [31,62509]\\&\to [63,31270]\to [127,15666]\to [253,7896]\\&\to [490,4074]\to [876,2282]\to [1266,1579]\\&\to [1406,1422]\to [1414,1414]\end{aligned}}}
    Se observa que la mejora en el rendimiento del método de Newton sobre la búsqueda binaria se debe al hecho de ques{\displaystyle \lfloor {\sqrt {s}}\rfloor }se aborda simultáneamente desde la izquierda y la derecha, mientras que la búsqueda binaria ajusta solo un lado en cada iteración.
  6. El algoritmo se explica en Algoritmos de raíz cuadrada#Sistema numérico binario (base 2)
  7. Véase el ejemplo en el artículo Fracción periódica continua .
  8. La expansión fraccionaria continua de4097280036{\displaystyle {\sqrt {4097280036}}}Tiene un período de 13.032 términos. Si bien Python no puede mostrar la secuencia completa en pantalla debido a su longitud, la escritura del resultado en un archivo se completa correctamente.

Referencias

  1. Johnson, SG (4 de febrero de 2015). "Raíces cuadradas mediante el método de Newton" (PDF) . Curso 18.335 del MIT: Introducción a los métodos numéricos . Consultado el 12 de octubre de 2025 .
  2. 1 2 3 Guy, Martin (1985). "Raíz cuadrada de enteros rápidos mediante el algoritmo del ábaco del Sr. Woo" . Universidad de Kent en Canterbury (UKC). Archivado del original el 6 de marzo de 2012. Recuperado el 5 de octubre de 2025 .
  3. 1 2 3 Zimmermann, Paul (1999). "Karatsuba Square Root" (PDF) . Informe de investigación n.° 3805. Inria (publicado el 24 de mayo de 2006). Archivado (PDF) del original el 11 de mayo de 2023.
  4. Knuth, Donald E. (1998). El arte de la programación informática, volumen 2: algoritmos seminuméricos (3.ª ed.). Addison–Wesley. ISBN  9780201896848.
  5. "BigInteger - Documentación de Chapel 2.1" . Documentación de Chapel - Documentación de Chapel 2.1 .
  6. "CLHS: Función SQRT, ISQRT" . Common Lisp HyperSpec (TM) .
  7. "Matemáticas - Crystal 1.13.2" . Documentación de la API del lenguaje de programación Crystal .
  8. "BigInteger (Java SE 21 y JDK 21)" . Documentación de JDK 21 .
  9. "Matemáticas - El lenguaje Julia" . Documentación de Julia - El lenguaje Julia .
  10. "iroot- Ayuda de Maple" . Ayuda - Maplesoft .
  11. "Catálogo de funciones GP/PARI: funciones aritméticas" . Sede de desarrollo de PARI/GP .
  12. "Índice de /archive/science/math/multiplePrecision/pari/" . Recursos digitales de PSG . Archivado del original el 6 de noviembre de 2024.
  13. "Funciones matemáticas" . Documentación de PHP .
  14. "Funciones matemáticas" . Documentación de la biblioteca estándar de Python .
  15. "4.3.2 Numéricos genéricos" . Documentación de Racket .
  16. "clase Entero - Documentación de RDoc" . Documentación de RDoc .
  17. "i32 - Rust" . std - Rust .
  18. "i32 - Rust" . std - Rust .
  19. "Elementos del anillo ℤ de enteros - Anillos conmutativos estándar" . Documentación de SageMath .
  20. ↑ " Informe revisado 7 sobre el esquema del lenguaje algorítmico" . Estándares de Scheme .
  21. "Página del manual de mathfunc - Funciones matemáticas de Tcl" . Manual de Tcl/Tk 8.6 .
  22. "std.math.sqrt.sqrt - Documentación de Zig" . Inicio Lenguaje de programación Zig .
  23. Beceanu, Marius (5 de febrero de 2003). "Periodo de la fracción continua de sqrt(n)" (PDF) . Teorema 2.3. Archivado (PDF) del original el 21 de diciembre de 2015. Recuperado el 5 de octubre de 2025 .
  • Jarvis, Ashley Frazer (2006). "Raíces cuadradas por sustracción" (PDF) . Mathematical Spectrum . 37 : 119–122 .
  • Minsky, Marvin (1967). «9. Los números reales computables». Computación: máquinas finitas e infinitas . Prentice-Hall. ISBN 0-13-165563-9OCLC 0131655639 
  • "Una visión geométrica del algoritmo de la raíz cuadrada" .
Obtenido de " https://en.wikipedia.org/w/index.php?title=Integer_square_root&oldid=1333190360 "