Как добавить 2 целых числа произвольного размера в C ++? - PullRequest
8 голосов
/ 28 мая 2010

Я хотел бы добавить 2 целых числа произвольного размера в C ++. Как я могу сделать это?

Ответы [ 3 ]

15 голосов
/ 28 мая 2010

Вот пример, показывающий, как использовать реализацию OpenSSL bignum для арифметики произвольной точности. Мой пример: 2 64 + 2 65 . Я использую Linux.

#include <cstdio>
#include <openssl/crypto.h>
#include <openssl/bn.h>

int main(int argc, char *argv[])
{
        static const char num1[] = "18446744073709551616";
        static const char num2[] = "36893488147419103232";

        BIGNUM *bn1 = NULL;
        BIGNUM *bn2 = NULL;

        BN_CTX *ctx = BN_CTX_new();

        BN_dec2bn(&bn1, num1); // convert the string to BIGNUM
        BN_dec2bn(&bn2, num2);

        BN_add(bn1, bn1, bn2); // bn1 = bn1 + bn2

        char *result_str = BN_bn2dec(bn1);  // convert the BIGNUM back to string
        printf("%s + %s = %s\n", num1, num2, result_str);
        OPENSSL_free(result_str);

        BN_free(bn1);
        BN_free(bn2);
        BN_CTX_free(ctx);

        return 0;
}

Он производит такой вывод:

18446744073709551616 + 36893488147419103232 = 55340232221128654848

Вам необходимо установить OpenSSL с библиотеками разработки. Если у вас Linux, установите библиотеку разработки из вашего менеджера пакетов и свяжитесь с libcrypto.so.

g++ bignum.cpp -o bignum -lcrypto

Или загрузите исходный код OpenSSL и создайте статическую библиотеку libcrypto.a и статически связывайте ее с ней.

g++ bignum.cpp -o bignum -I./openssl-1.0.0/include ./openssl-1.0.0/libcrypto.a

В Windows вам потребуется установить с порта Windows OpenSSL.

4 голосов
/ 29 августа 2017

Я хотел бы добавить 2 целых числа произвольного размера в C ++. Как я могу сделать это?

Если вы хотите выполнить математику с высокой точностью самостоятельно, то я предлагаю вам взглянуть на Искусство компьютерного программирования Дональда Кнута . Я полагаю, что вас интересует том II, Получисловые алгоритмы, Глава 4, Арифметика с множественной точностью. Кнут дает вам все кровавые подробности.

Обработка больших чисел в C ++? также дает ссылку на интересную статью. Возможно, вам следует прочитать его, если вы используете собственную реализацию. (Другие подобные вопросы не имеют ссылки. Спасибо @herohuyongtao за предоставленную информацию).

В дополнение к @indiv ответу об использовании OpenSSL в C вы можете использовать Botan или Crypto ++ . Оба являются библиотеками C ++, и оба примерно так же стары, как OpenSSL. Я удивлен, что ответы на них не предоставлены, учитывая, что ваш вопрос помечен C ++.

Если у вас есть C ++ 11 или unique_ptr, вы можете использовать их для кода OpenSSL C. unique_ptr действительно приводит в порядок вещи. Пример приведен ниже.


Ботан

Вот программа:

$ cat test.cxx
#include "botan/bigint.h"

#include <iostream>

int main()
{
    using Botan::BigInt;

    BigInt num1("18446744073709551616");
    BigInt num2("36893488147419103232");

    std::cout << num1 + num2 << std::endl;
    std::cout << std::hex << "0x" << num1 + num2 << std::endl;

    return 0;
}

И сборка из справочника библиотеки (целесообразность):

$ g++ -I ./build/include test.cxx ./libbotan-2.a -o test.exe
$ ./test.exe
55340232221128654848
0x30000000000000000

Crypto ++

Вот программа:

$ cat test.cxx
#include "cryptlib.h"
#include "integer.h"

#include <iostream>

int main()
{
    using CryptoPP::Integer;

    Integer num1("18446744073709551616");
    Integer num2("36893488147419103232");

    std::cout << num1 + num2 << std::endl;
    std::cout << std::hex << "0x" << num1 + num2 << std::endl;

    return 0;
}

И сборка из справочника библиотеки (целесообразность):

$ g++ -I . test.cxx ./libcryptopp.a -o test.exe
$ ./test.exe
55340232221128654848.
0x30000000000000000h

OpenSSL

Вот программа для C ++ и OpenSSL. BN_obj "имеет" BIGNUM и использует unique_ptr для управления ресурсами.

$ cat test.cxx
#include "openssl/bn.h"
#include "openssl/err.h"

#include <iostream>
#include <stdexcept>
#include <sstream>
#include <memory>
#include <new>

class BN_obj
{
using BN_ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
using BN_CTX_ptr = std::unique_ptr<BN_CTX, decltype(&::BN_CTX_free)>;

public:
    BN_obj() : m_bn(BN_Zero_Helper(), ::BN_free) {}
    BN_obj(const char* str) : m_bn(BN_Asciiz_Helper(str), ::BN_free) {}
    BN_obj(const BN_obj& obj) : m_bn(BN_Copy_Helper(obj.m_bn), ::BN_free) {}

    BN_obj& operator=(const BN_obj& obj) 
    {
        if(this != &obj)
            m_bn.reset(BN_dup(obj.m_bn.get()));

        return *this;
    }

    BN_obj Plus(const BN_obj& obj) const
    {
        BN_obj result;
        if (BN_add(result.m_bn.get(), m_bn.get(), obj.m_bn.get()) != 1)
        {
            std::ostringstream msg;
            unsigned long err = ERR_get_error();            
            msg << "BN_add failed, error 0x" << std::hex << err;
            throw std::runtime_error(msg.str());        
        }
        return result;
    }

    BN_obj Minus(const BN_obj& obj) const
    {
        BN_obj result;
        if (BN_sub(result.m_bn.get(), m_bn.get(), obj.m_bn.get()) != 1)
        {
            std::ostringstream msg;
            unsigned long err = ERR_get_error();            
            msg << "BN_sub failed, error 0x" << std::hex << err;
            throw std::runtime_error(msg.str());        
        }
        return result;
    }

    BN_obj Times(const BN_obj& obj) const
    {
        BN_obj result;
        BN_CTX_ptr ctx(BN_CTX_new(), ::BN_CTX_free);
        if (BN_mul(result.m_bn.get(), m_bn.get(), obj.m_bn.get(), ctx.get()) != 1)
        {
            std::ostringstream msg;
            unsigned long err = ERR_get_error();            
            msg << "BN_sub failed, error 0x" << std::hex << err;
            throw std::runtime_error(msg.str());        
        }
        return result;
    }

    friend std::ostream& operator<<(std::ostream& out, const BN_obj& obj);

protected:
    static BIGNUM* BN_Zero_Helper()
    {
        BIGNUM* z = BN_new();
        BN_zero(z);
        return z;
    }

    static BIGNUM* BN_Asciiz_Helper(const char* str)
    {
        BIGNUM* t = BN_new();
        if(!t)
            throw std::bad_alloc();
        if(BN_dec2bn(&t, str) == 0) {
            std::ostringstream msg;
            unsigned long err = ERR_get_error();            
            msg << "BN_dec2bn failed, error 0x" << std::hex << err;
            throw std::runtime_error(msg.str());
        }
        return t;
    }

    static BIGNUM* BN_Copy_Helper(const BN_ptr& obj)
    {
        return BN_dup(obj.get());
    }

private:
    BN_ptr m_bn;
};

BN_obj operator+(const BN_obj& a, const BN_obj& b) {
    return a.Plus(b);
}

BN_obj operator-(const BN_obj& a, const BN_obj& b) {
    return a.Minus(b);
}

BN_obj operator*(const BN_obj& a, const BN_obj& b) {
    return a.Times(b);
}

std::ostream& operator<<(std::ostream& out, const BN_obj& obj)
{
    const long f = out.flags() & std::ios::basefield;
    char* ptr = nullptr;

    if(f == std::ios::hex)
    {
        ptr = BN_bn2hex(obj.m_bn.get());
        out << ptr;
    }
    else if(f == std::ios::dec)
    {
        ptr = BN_bn2dec(obj.m_bn.get());
        out << ptr;
    }
    else
        throw std::runtime_error("Not implemented");

    if(ptr)
        OPENSSL_free(ptr);

    return out;
}

int main()
{
    const char z1[] = "18446744073709551616";
    const char z2[] = "36893488147419103232";

    BN_obj num1(z1);
    BN_obj num2(z2);

    std::cout << num1 + num2 << std::endl;
    std::cout << std::hex << "0x" << num1 + num2 << std::endl;

    return 0;
}

И сборка из справочника библиотеки (целесообразность):

$  g++ -I ./include test.cxx ./libcrypto.a -o test.exe -ldl -pthread
$ ./test.exe
55340232221128654848
0x30000000000000000
4 голосов
/ 28 мая 2010

Использование оператора +?

...