【问题标题】:How to add 2 arbitrarily sized integers in C++?如何在 C++ 中添加 2 个任意大小的整数?
【发布时间】:2023-03-28 20:34:01
【问题描述】:

我想在 C++ 中添加 2 个任意大小的整数。我该怎么做?

【问题讨论】:

  • 请说明更多信息.. 可以进行演员表吗?
  • 您可以查看GMP,这是一个用于 C 和 C++ 的任意精度算术库。
  • libgmp 这样的东西会做任意精度的算术。
  • 对于大多数任意大小整数的实现来说,添加它们通常很容易。您只需从低位端开始逐条添加它们,添加上一步中的任何进位并计算进位。就像你在小学学到的一样。
  • 默认情况下,c++ 没有任意大小的整数,但存在大量第三方库。如果您仍在购买图书馆,也可以考虑使用 Boost。

标签: c++ bignum arbitrary-precision


【解决方案1】:

这是一个示例,展示了如何使用OpenSSL bignum 实现进行任意精度的算术运算。我的例子是 264 + 265。我正在使用 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 上,您需要从 OpenSSL 的 Windows port 安装。

【讨论】:

  • 您的示例中变量 ctx 的用途是什么。好像没用过?
  • @MadOgre:很好的观察。事实证明,您不需要 BN_add 的上下文,因此在此示例中它仍然未使用。其他数学运算确实需要它,例如BN_mulBN_divBN_mod 等等。 OpenSSL 使用上下文进行内部记账。
  • 由于您使用 gnu 编译器,我不会对此类数字使用那种东西,因为在您的情况下有一个 128 位整数的内置类型。
  • 感谢这个例子。通过一些小的更改,我也能够在 ANSI C 中将这段代码编译为gcc test.c -o test -Wall -lcrypto -ansi -Wpedantic -Wextra
【解决方案2】:

使用+ 运算符?

【讨论】:

    【解决方案3】:

    我想在 C++ 中添加 2 个任意大小的整数。我该怎么做?

    如果你想自己执行多精度数学,那么我建议你看看 Donald Knuth 的 Art of Computer Programming。我相信第 II 卷,半数值算法,第 4 章,多精度算术,是您感兴趣的内容。Knuth 为您提供了所有血淋淋的细节。

    Handling large numbers in C++? 还提供了一篇有趣论文的参考。如果您正在滚动自己的实现,您可能应该阅读它。 (其他类似问题缺乏参考。感谢@herohuyongtao提供)。

    除了@indiv 回答在 C 中使用 OpenSSL 之外,您还可以使用 BotanCrypto++。两者都是 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
    

    加密++

    这是程序:

    $ 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
    

    【讨论】:

      猜你喜欢
      • 2015-04-25
      • 1970-01-01
      • 2017-04-06
      • 1970-01-01
      • 2010-12-07
      • 1970-01-01
      • 2015-11-20
      • 1970-01-01
      • 2013-02-24
      相关资源
      最近更新 更多