Operaciones de Alta Precisión en C++

  1. Introducción

En aplicaciones donde se manejan números extremadamente grandes, los tipos nativos como int o long long no son suficientes. Esta guía explica cómo implementar operaciones aritméticas básicas (suma, resta, multiplicación y división por un entero pequeño) sobre números de gran tamaño usando arrays y manipulación manual de dígitos.

  1. Representación de Números Grandes

Los números con más de 20 cifras no pueden almacenarse directamente en tipos estándar. Por ello, se representa cada número como una cadena de caracteres, que luego se convierte a un array de enteros digitales. El orden inverso facilita el cálculo desde el dígito menos significativo hacia el más significativo.

2.1 Suma de Grandes Números

El proceso sigue las reglas tradicionales de suma: alineación de dígitos, suma desde la derecha, y propagación de acarreo cuando el resultado excede 9.

#include <iostream>
#include <algorithm>
#include <string>
using namespace std;

int main() {
    string num1, num2;
    cin >> num1 >> num2;

    // Invertir cadenas para procesar desde el dígito menos significativo
    reverse(num1.begin(), num1.end());
    reverse(num2.begin(), num2.end());

    int len = max(num1.length(), num2.length());
    int a[len] = {}, b[len] = {}, result[len + 1] = {};

    // Convertir caracteres a dígitos
    for (int i = 0; i < num1.length(); ++i)
        a[i] = num1[i] - '0';
    for (int i = 0; i < num2.length(); ++i)
        b[i] = num2[i] - '0';

    // Realizar suma con acarreo
    for (int i = 0; i < len; ++i) {
        result[i] += a[i] + b[i];
        result[i + 1] += result[i] / 10;
        result[i] %= 10;
    }

    // Invertir resultado final y eliminar ceros iniciales
    reverse(result, result + len + 1);
    string output = "";
    bool leading_zero = true;

    for (int i = 0; i <= len; ++i) {
        if (!(result[i] == 0 && leading_zero)) {
            leading_zero = false;
            output += result[i] + '0';
        }
    }

    if (output.empty()) output = "0";
    cout << output;

    return 0;
}

2.2 Resta de Grandes Números

La resta requiere comparar magnitudes antes de proceder. Si el segundo número es mayor, el resultado será negativo. Se invierten los operandos y se añade un signo negativo si corresponde.

#include <iostream>
#include <algorithm>
#include <string>
using namespace std;

int main() {
    string a, b;
    cin >> a >> b;

    string sign = "";
    if (a.length() < b.length() || 
        (a.length() == b.length() && a < b)) {
        sign = "-";
        swap(a, b);
    }

    reverse(a.begin(), a.end());
    reverse(b.begin(), b.end());

    int len = max(a.length(), b.length());
    int x[len] = {}, y[len] = {}, diff[len + 1] = {};

    for (int i = 0; i < a.length(); ++i)
        x[i] = a[i] - '0';
    for (int i = 0; i < b.length(); ++i)
        y[i] = b[i] - '0';

    for (int i = 0; i < len; ++i) {
        diff[i] += x[i] - y[i];
        if (diff[i] < 0) {
            diff[i] += 10;
            diff[i + 1] -= 1;
        }
    }

    reverse(diff, diff + len + 1);
    string result = "";
    bool leading = true;

    for (int i = 0; i <= len; ++i) {
        if (!(diff[i] == 0 && leading)) {
            leading = false;
            result += diff[i] + '0';
        }
    }

    if (result.empty()) result = "0";
    cout << sign << result;

    return 0;
}

2.3 Multiplicación de Grandes Números

Se aplica el algoritmo de multiplicación por columnas. Cada dígito del primer número se multiplica por cada dígito del segundo, y el resultado se acumula en la posición correspondiente (i+j).

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
    string s1, s2;
    cin >> s1 >> s2;

    int len1 = s1.size(), len2 = s2.size();
    int result_len = len1 + len2;
    int a[len1] = {}, b[len2] = {}, res[result_len] = {};

    // Inversión y conversión a dígitos
    for (int i = 0; i < len1; ++i)
        a[len1 - 1 - i] = s1[i] - '0';
    for (int i = 0; i < len2; ++i)
        b[len2 - 1 - i] = s2[i] - '0';

    // Multiplicación por columnas
    for (int i = 0; i < len1; ++i) {
        int carry = 0;
        for (int j = 0; j < len2; ++j) {
            res[i + j] += a[i] * b[j] + carry;
            carry = res[i + j] / 10;
            res[i + j] %= 10;
        }
        res[i + len2] = carry;
    }

    // Eliminar ceros iniciales
    while (result_len > 1 && res[result_len - 1] == 0)
        --result_len;

    // Imprimir resultado en orden correcto
    for (int i = result_len - 1; i >= 0; --i)
        cout << res[i];

    return 0;
}

2.4 División por Entero Pequeño

Este caso permite dividir un número grande entre un entero de bajo rango (por ejemplo, hasta 1000). Se simula el método de división larga: se toma un dígito a la vez, se forma el cociente parcial y se leva el residuo.

#include <iostream>
#include <string>
using namespace std;

int main() {
    string large_num;
    int divisor;
    cin >> large_num >> divisor;

    int len = large_num.size();
    int digits[len + 1] = {}, quotient[len + 1] = {};
    
    // Convertir cadena a dígitos (desde el inicio)
    for (int i = 0; i < len; ++i)
        digits[i + 1] = large_num[i] - '0';

    int remainder = 0;
    for (int i = 1; i <= len; ++i) {
        int current = remainder * 10 + digits[i];
        quotient[i] = current / divisor;
        remainder = current % divisor;
    }

    // Eliminar ceros iniciales
    int q_len = 1;
    while (q_len < len && quotient[q_len] == 0)
        ++q_len;

    for (int i = q_len; i <= len; ++i)
        cout << quotient[i];

    return 0;
}

  1. Conclusión

Las operaciones de alta precisión permiten trabajar con números que superan los límites de los tipos de datos nativos. Aunque el código puede parecer complejo, su lógica se basa en principios matemáticos fundamentales. Este enfoque es esencial en competencias de programación, criptografía y sistemas financieros.

Etiquetas: high precision arithmetic C++ big integer String Manipulation digit-by-digit calculation

Publicado el 9-21 07:15