How to add 2 arbitrarily sized integers in C++?

前端 未结 3 606
离开以前
离开以前 2020-11-27 07:38

I would like to add 2 arbitrarily sized integers in C++. How can I go about doing this?

相关标签:
3条回答
  • 2020-11-27 07:54

    Here's an example showing how to use the OpenSSL bignum implementation for arbitrary-precision arithmetic. My example does 264 + 265. I'm using 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;
    }
    

    It produces this output:

    18446744073709551616 + 36893488147419103232 = 55340232221128654848
    

    You need to have OpenSSL installed with the development libraries. If you have Linux, install the development library from your package manager and link with libcrypto.so.

    g++ bignum.cpp -o bignum -lcrypto
    

    Or download the OpenSSL source and build the static library libcrypto.a and link with it statically.

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

    On Windows, you'll need to install from the Windows port of OpenSSL.

    0 讨论(0)
  • 2020-11-27 07:58

    I would like to add 2 arbitrarily sized integers in C++. How can I go about doing this?

    If you want to perform the multi-precision math yourself, then I suggest you take a look at Donald Knuth's Art of Computer Programming. I believe Volume II, Seminumerical Algorithms, Chapter 4, Multiple Precision Arithmetic, is what you are interested in. Knuth gives you all the gory details.

    Handling large numbers in C++? also provides a reference to an interesting paper. You should probably read it if you are rolling your own implementation. (Other similar questions lack the reference. Thanks to @herohuyongtao for providing it).

    In addition to @indiv answer of using OpenSSL in C, you can use Botan or Crypto++. Both are C++ libraries, and both are about as old as OpenSSL. I'm surprised answers were not provided for them considering your question is tagged C++.

    If you have C++11 or unique_ptr, then you can use them for the OpenSSL C code. unique_ptr really tidies things up. An example is given below.


    Botan

    Here is the program:

    $ 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;
    }
    

    And building from the library's directory (expediency):

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

    Crypto++

    Here is the program:

    $ 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;
    }
    

    And building from the library's directory (expediency):

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

    OpenSSL

    Here is the program for C++ and OpenSSL. The BN_obj "has a" BIGNUM, and it uses unique_ptr to manage the resources.

    $ 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;
    }
    

    And building from the library's directory (expediency):

    $  g++ -I ./include test.cxx ./libcrypto.a -o test.exe -ldl -pthread
    $ ./test.exe
    55340232221128654848
    0x30000000000000000
    
    0 讨论(0)
  • 2020-11-27 08:03

    Using the + operator?

    0 讨论(0)
提交回复
热议问题