¿Cómo podemos procesar números incluso más grandes que largos?

Permítanme aclarar esto … no se le permite usar algo que ya se ha hecho, probado y optimizado para que funcione de la manera más rápida y correcta posible.

También está restringido de usar la estructura de datos (matriz) más eficiente para este propósito, que es lo que se usa dentro de las implementaciones de BigInt.

SÓLO se permiten cadenas y métodos en cadenas. ¿Al menos se le permiten cosas como operadores + y * en valores enteros que lee de una cadena? ¿O debe simular manualmente a un humano haciendo división / multiplicación / suma / resta larga?

Supongo que este es un ejercicio para enseñarle a resolver problemas, en lugar de enseñarle a calcular con números mayores que largos. De lo contrario, las restricciones anteriores no tienen sentido. Y si ese es el caso, entonces en realidad te estás disparando en el pie pidiéndole a otros que te muestren cómo. El punto es enseñarle cómo convertir la forma en que lo haría usted mismo en las instrucciones para decirle a la computadora que haga las mismas acciones que usted había hecho.

Por lo tanto, mire MUY cuidadosamente exactamente lo que haría al multiplicar dos números juntos usando la multiplicación larga. Divídalo en pasos. Vea qué líneas de texto ha escrito (se convertirán en sus cadenas). Vea cómo atraviesa cada una, cómo combina una línea con otra para obtener una tercera y / o cuarta. Cómo continúa haciendo lo mismo y cuándo sabe que ha terminado. De eso se trata la pregunta, no de la longitud de un número entero o de cómo calcular valores mayores que largos. Pero más los medios para convertir un “problema” o un conjunto de tareas en las instrucciones para que una computadora los complete.

¿Cómo podemos procesar números incluso más grandes que largos?

El valor máximo de tipo largo tiene 18 dígitos. Por ejemplo, queremos multiplicar o dos números de 20 dígitos. ¿Cómo podemos hacerlo? Está prohibido el uso de BigInteger, etc.

Muy fácilmente, en realidad. Simplemente use boost :: multiprecision :: cpp_int. Oh, no tienes permitido usar BigInteger …

Ahora, supongo que esta es una especie de asignación de casa. En realidad, como TA, una vez les había dado esa tarea a mis alumnos. Es bastante fácil en realidad, si lo piensas. Regrese al segundo grado, conceptualmente, y piense cómo hacer una larga suma de números.

Simplemente tome una hoja de papel y recuérdese cómo hacerlo con dos números, como 555555 + 182766. Piense cuidadosamente lo que está haciendo, para que pueda hacer exactamente lo mismo en su código. Implementé la adición en 15 líneas de C ++, 10 líneas de Python, pero fue flojo hacerlo en C ya que debería ser idéntico, pero más largo.

La multiplicación es un poco más complicada, como recuerdas del tercer grado, pero puedes usar la suma como un bloque de construcción.

Todo esto supone que implementa todo en la base 10, es decir, decimal. Pero si convierte todos los números a binario, le resultará mucho más fácil de implementar. Además de eso, en una computadora, las operaciones con números binarios son mucho más rápidas que las decimales. No estoy seguro si sus requisitos de ejercicio permiten tal conversión a binario.

Puede hacerlo como en tercer grado, como si todos aprendieran a sumar y restar si está trabajando con cadenas basadas en ASCII, lo cual es fácil. ¿O puede hacerlo como aprendí a calcular en mi segundo, o fue el primer grado ?: mediante cálculo binario.

Sí, así aprendí los números. Lo primero fue la teoría de conjuntos, luego aprendimos a contar y agregar binario, terciario y subimos los sistemas de números a 16, luego 60 y luego volvimos a la base diez y trabajamos con eso desde ese momento en adelante.

Mi maestra era muy inteligente, era pelirroja y muy muy grande. Y ella me enseñó los conceptos básicos de las cosas a la edad de seis o siete años que otros no suelen aprender antes de ingresar a la universidad. Eran los años 70 y todo fue revolución. Entonces nací en esto. Y cuento diferente de otras personas, los números tienen un significado diferente para mí.

Pero comencemos con “tercer grado” (¡¿tan tarde ?! wtf). Teníamos un conocimiento completo sobre la sexualidad a esa edad, porque eso era algo que aprendimos también en segundo grado, bueno, una segunda vez en cuarto, quinto, séptimo y genética en décimo más o menos.

Pero volvamos a los números. Sumas dos números sumando los últimos cifrados y sigues con el carry. 8 + 9 = 17, entonces es 7 y se pasa a la siguiente columna. Si solo vuelvo a la primera lección en números que tuve, es binario 1 + 1 = 10 significa 0 y carry. Agrega el carry a la siguiente columna. Nunca puede haber más de un transporte independiente del sistema de números que está utilizando.

Entonces hexadecimal E + F es 1D significa D y carry. No puede estar más allá de F + F = 1E. En decimal no puede ser más de 9 + 9 = 18 en binario no más de 1 + 1 = 10. Siempre obtienes una carga.

Entonces, si está utilizando para agregar sus números en columnas decimales, solo procesa un poco menos de 4 bits a la vez. “Un poco menos” significa definitivamente más de 3 bits, lo que representa 0–7 en el sistema octal y cuatro bits 0-F en hexadecimal. Es exactamente [matemática] 1 / log (2) = 3.32… [/ matemática] dígitos binarios para ser precisos.

Pero nuestros procesadores modernos tienen 64 bits. Entonces eso sería altamente ineficiente.

; dos números para agregar en RDI, RSI
; resultar en RAX (bajo) RDX (alto)
globl add_longc

texto de la sección
add_longc:
xor rdx, rdx; borrar RDX = 0
mov rax, rdi; establecer RAX = RDI
agregar rax, rsi; RAX + = RSI
adc rdx, # 0; RDX + = TRANSPORTAR
jubilado

Esta es la base de suma 2 ^ 64. Interesante es ADD, además sin carry y ADC, además con carry. La bandera de acarreo se establece mediante la primera adición si la suma es mayor de lo que cabe en 64 bits.

No tienes el carry como una construcción en ningún lenguaje de alto nivel. Lo cual es realmente una pena, porque esto es realmente algo sensato. Si intenta hacer esto en C, por ejemplo, tendrá muchos problemas para verificar si hay un carry o no. En ensamblaje son solo dos comandos.

Y como siempre trato de presentar la solución más simple a un problema, esto es: hacerlo en Asamblea. Por supuesto, puede cambiar esta variante simple dando los punteros de memoria del algoritmo a los dos operandos y uno a una matriz de destino y un contador sobre la longitud de esas matrices.

Entonces tendrás números largos arbitrarios y la implementación es definitivamente más rápida que la de BigInt. ¿Qué se hace en C. WTF? Desperdicio de ciclos. Tenemos una máquina haciendo esto. Es como conducir una motocicleta al tener seis tipos musculosos que lo llevan en su bicicleta.

HLL no están hechos para esto. No deben ser utilizados para esto. Quien hace esto en HLL debería haber estado en un campo diferente de la ciencia o al menos dejar de enseñar a los niños.

Este es un problema claro del lenguaje ensamblador. Por cierto, llamas esto desde C por:

extern unsigned long * add_longc (registrar unsigned long a asm (“rdi”), registrar unsigned long b asm (“rsi”));

Pero debido a que estoy en conformidad con la API de 64 bits aquí, esta parte asm (…) no es realmente necesaria, además del “registro” enérgico. Y, por supuesto, no he devuelto el valor de retorno correctamente, lo que debe hacerse a una matriz o estructura de datos en este contexto, pero quería mantener el ejemplo fácil y no resolver su tarea.

Simplemente: no hagas eso en HLL. Nunca lo hagas en HLL. Y tome un palo y golpee a cualquiera que vea haciendo esto en HLL. Este es un problema de lenguaje ensamblador. Todos los HLL descalifican para tratarlo, incluso acercándose a él.

Un lenguaje que no comprende algo como un carry no debe usarse para un problema como este. Y no hay orgullo en hacer que los seis hombres musculosos lleven su motocicleta y griten “¡más rápido!”.

Exactamente cómo lo harías a mano.

Apuesto a que si te doy dos números de 18 dígitos, en principio podrías calcular su producto usando una multiplicación larga. Aunque probablemente no conozcas la tabla de tiempos después de 12 x 12.

Entonces, simplemente implementa las reglas para la multiplicación larga que aprendió en la escuela primaria como un algoritmo informático. Usar matrices, etc. para contener los dígitos individuales (0 … 9). Tal vez media hora para codificar.

La división es más difícil, probablemente hayas olvidado cómo hacer una división larga a mano, pero el mismo enfoque funcionará. La suma es trivial, de todos modos lo necesitará para una multiplicación larga, así que hágalo primero ya que es lo más fácil. Restar es un poco más difícil, porque tienes que preocuparte por cómo representar números negativos. No es que preguntes por esto.

Esto se puede manejar usando una matriz, pero las implementaciones deben hacerse de manera diferente. Por ejemplo, si desea averiguar el factorial para un número grande, suponga que el número es 100, entonces el resultado será de 158 dígitos, que es demasiado largo para tipos de datos incluso largos. Por lo tanto, el enlace proporcionado sería útil para comprender cómo utilizar las matrices para este propósito.

sunny-shaw / Programación competitiva

Realice su propia implementación de BigInteger. De verdad.

Editar: Bueno, bueno, en realidad he hecho una implementación interesante para mi laboratorio Uni. Está disponible públicamente en mis repositorios en Github (cs_pub_ro / lab05 / bonus.c) pero solo es muy transitorio (una vez que finalice el año, borraré el repositorio, incluido el historial)

More Interesting

¿Cómo puede un ingeniero eléctrico aprender programación práctica? ¿Qué se necesita en el mundo real?

¿Qué patrones de diseño tienen más probabilidades de ser utilizados por los programadores principiantes sin darse cuenta?

¿Qué son las banderas de características y por qué son importantes?

Tecnología: ¿Los valores decrecientes de las acciones tecnológicas, como Linkedin o Tableau, indican que la 'burbuja tecnológica' estalla?

¿Cuál es la mejor manera de evaluar la tecnología informática?

¿Cuáles son las habilidades que debe tener un ingeniero de software de tener 4 años de experiencia, cuáles son las habilidades que se esperan de él? ¿Y cómo debería planear para los próximos 1 o 2 años?

¿Dónde podría conseguir un trabajo con mis habilidades?

¿Cuándo debo usar Awk, Sed o Grep?

¿Cómo se desarrolló el primer software posible?

¿Puedo usar SQLAlchemy con Node.JS?

¿Qué debe saber todo un ingeniero de telecomunicaciones para lanzarse a la industria del software, aparte de la C básica?

¿Cómo se compararían las industrias de semiconductores y de desarrollo de software entre 10 y 15 años después en términos de pago, tamaño de la industria y consolidación (seguridad laboral)?

¿Cuáles son las habilidades necesarias para administrar un equipo de desarrollo de software?

¿Cuáles son las estrategias más efectivas para encontrar desarrolladores de alta calidad en Moscú y Rusia?

¿A qué estudios avanzaría después de B.Sc en ingeniería de software?