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 ,
Por ejemplo,
Observación introductoria
Dejarysean números enteros no negativos.
Algoritmos que calculan (la representación decimal de)ejecutarse indefinidamente en cada entradaque no es un cuadrado perfecto . [ nota 1 ]
Algoritmos que calculanno funcionan para siempre . Sin embargo, son capaces de calcular.hasta cualquier precisión deseada.
Elige cualquieray calcular.
Por ejemplo (configuración):
Compare los resultados con
Parece que la multiplicación de la entrada porproporciona una precisión de k dígitos decimales. [ nota 2 ]
Para calcular la representación decimal (completa) de, uno puede ejecutarun número infinito de veces, aumentandopor un factoren cada pasada.
Supongamos que en el siguiente programa () el procedimientoya está definido y —para efectos de la argumentación— que todas las variables pueden contener números enteros de magnitud ilimitada.
Entoncesimprimirá la representación decimal completa de. [ 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 dedese 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 negativopuede definirse como
Por ejemplo,porque.
Algoritmo que utiliza búsqueda lineal
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
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
Algoritmo que utiliza búsqueda binaria
La búsqueda lineal comprueba secuencialmente cada valor hasta que encuentra el más pequeño.dónde.
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
- ,.
- Utilizando la búsqueda binaria, el cálculo deconverge aenpasos de iteración a través delsecuencia
- El cálculo deconverge aenpasos a través delsecuencia
- Búsqueda lineal (ascendente, comenzando desde) necesidades1414 escalones.
Algoritmo que utiliza el método de Newton
Una forma de calcularyes 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ón, dando como resultado la fórmula iterativa
La secuenciaconverge cuadráticamente acomo. [ 1 ] [ nota 4 ]
Utilizando únicamente la división entera
Para computaciónSe 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 .
Dejary suposición inicial. Defina la secuencia de enteros:
Prueba de convergencia
1. Positividad: Todos los términos son números enteros positivos:a pesar de.
2. Monotonía:
- Si, entonces;
- entonces.
- Por lo tanto, la secuencia disminuye.
- Si, entonces;
- entonces.
- Por lo tanto, la secuencia aumenta o permanece igual.
3. Acotación: La sucesión está acotada inferiormente por 1 y superiormente por, 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:
- o.
5. Condición de "punto fijo" entero: En la estabilización o la oscilación:
- .
- Esto garantiza que la secuencia esté eno oscilando entre los dos enteros más cercanos alrededor.
6. Conclusión: La secuencia finalmente se estabiliza eno oscila entrey.
Observación:
- es un punto fijo estricto a menos quees un cuadrado perfecto.
- Sies un cuadrado perfecto, la secuencia oscila entrey.
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 aen 14 pasos a través de while:
- .
Se obtiene una iteración al establecer x0encon 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 enque es la menor potencia de dos mayor que. En el ejemplo de la raíz cuadrada entera de 2000000 ,,y la secuencia resultante es 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 cuadradaSe 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.. 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 ]
Debido a que solo se realiza una llamada recursiva por nivel, la complejidad total permaneceen 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 entero, SqrtRemcalcula simultáneamente su raíz cuadrada enteray el resto correspondienteLa 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 dese puede realizar utilizando únicamente operaciones con enteros, consirviendo como término inicial. El algoritmo [ 23 ] genera una expansión de fracción continua en forma canónica .
Dejar sea la raíz cuadrada entera de.
SiSi es un cuadrado perfecto, la fracción continua termina inmediatamente:
De lo contrario, la fracción continua es periódica:
- ,
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:
- Para,
Dado que solo hay un número finito de triples posibles, finalmente se repite, y a partir de ese momento la fracción continua se vuelve periódica.
Implementación en Python
En la entrada, un entero no negativo, el siguiente programa calcula la fracción continua simple deLa raíz cuadrada enterase calcula una vez. [ nota 5 ] Solo se utiliza aritmética de enteros. El programa muestra, 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
- ↑ 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.
- ↑ No sorprende que la multiplicación repetida por 100 sea una característica en Jarvis (2006).
- ↑ La parte fraccionaria de las raíces cuadradas de cuadrados perfectos se representa como 000... .
- ↑ Véase el método de Herón .
- 1 2 3 El método de Newton se puede expresar de la siguiente manera(con la estimación inicial establecida en): Cálculos
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
- ,.
- El cálculo deconsiste enpasos:
- Se observa que la mejora en el rendimiento del método de Newton sobre la búsqueda binaria se debe al hecho de quese aborda simultáneamente desde la izquierda y la derecha, mientras que la búsqueda binaria ajusta solo un lado en cada iteración.
- ↑ El algoritmo se explica en Algoritmos de raíz cuadrada#Sistema numérico binario (base 2)
- ↑ Véase el ejemplo en el artículo Fracción periódica continua .
- ↑ La expansión fraccionaria continua deTiene 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
- ↑ 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 .
- 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 .
- 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.
- ↑ Knuth, Donald E. (1998). El arte de la programación informática, volumen 2: algoritmos seminuméricos (3.ª ed.). Addison–Wesley. ISBN 9780201896848.
- ↑ "BigInteger - Documentación de Chapel 2.1" . Documentación de Chapel - Documentación de Chapel 2.1 .
- ↑ "CLHS: Función SQRT, ISQRT" . Common Lisp HyperSpec (TM) .
- ↑ "Matemáticas - Crystal 1.13.2" . Documentación de la API del lenguaje de programación Crystal .
- ↑ "BigInteger (Java SE 21 y JDK 21)" . Documentación de JDK 21 .
- ↑ "Matemáticas - El lenguaje Julia" . Documentación de Julia - El lenguaje Julia .
- ↑ "iroot- Ayuda de Maple" . Ayuda - Maplesoft .
- ↑ "Catálogo de funciones GP/PARI: funciones aritméticas" . Sede de desarrollo de PARI/GP .
- ↑ "Índice de /archive/science/math/multiplePrecision/pari/" . Recursos digitales de PSG . Archivado del original el 6 de noviembre de 2024.
- ↑ "Funciones matemáticas" . Documentación de PHP .
- ↑ "Funciones matemáticas" . Documentación de la biblioteca estándar de Python .
- ↑ "4.3.2 Numéricos genéricos" . Documentación de Racket .
- ↑ "clase Entero - Documentación de RDoc" . Documentación de RDoc .
- ↑ "i32 - Rust" . std - Rust .
- ↑ "i32 - Rust" . std - Rust .
- ↑ "Elementos del anillo ℤ de enteros - Anillos conmutativos estándar" . Documentación de SageMath .
- ↑ " Informe revisado 7 sobre el esquema del lenguaje algorítmico" . Estándares de Scheme .
- ↑ "Página del manual de mathfunc - Funciones matemáticas de Tcl" . Manual de Tcl/Tk 8.6 .
- ↑ "std.math.sqrt.sqrt - Documentación de Zig" . Inicio ⚡ Lenguaje de programación Zig .
- ↑ 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 .
Enlaces externos
- 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" .
- Algoritmos de teoría de números
- teoría de números
- Algoritmos para la búsqueda de raíces