大整数增加,我知道理论..在实践中仍然生锈

Big Integer addition, I know the theory... still rusty in practice

本文关键字:实践中 理论 整数 增加 我知道      更新时间:2023-10-16

所以,我正在尝试构建一个简单的大整数类,我在互联网上阅读了一些页面,但是我很困惑。我知道这个理论,我知道我需要一个携带,但是我见过的所有例子,它们都集中在炭中,而在基本10中,我使用的是另一种方法来使其更快一些。我将感谢对加分配运营商的一些帮助,其余的我将尝试自己弄清楚。

#include <iostream>
#include <string>
#include <vector>
using std::cout;
using std::endl;
class big_integer {
    using box = std::vector<int unsigned>;
    box data {0};
    box split(std::string const & p_input) const {
        box output;
        for (size_t i {}; i < p_input.size(); i += 8) {
            output.push_back(stoi(p_input.substr(i, 8)));
        }
        return output;
    }
public:
    big_integer(std::string const & p_data)
        : data {split(p_data)}
    {}
    big_integer(int unsigned const p_data)
        : data {p_data}
    {}
    big_integer & operator +=(big_integer const & p_input) {
        int carry {};
        for (size_t i {}; i < data.size(); ++i) {
            //Need help here!
            //All examples I see either use primitive arrays
            //or are too esoteric for me to understand.             
            //data[i] += p_input.data[i] + carry;
        }
        return *this;
    }
    std::string to_string() const {
        std::string output;
        output.reserve(data.size() * 8);
        for (auto const i : data) {
            output.append(std::to_string(i));
        }
        return output;
    }
};
std::ostream & operator <<(std::ostream & p_output, big_integer const & p_input) {
    return p_output << p_input.to_string();
}
int main() {
    big_integer test1 {"126355316523"};
    big_integer test2 {255};
    test1 += test1;
    cout << test1 << endl;
    cout << test2 << endl;
    return 0;
}

正确。因此,基本问题是如何进行unsigned + unsigned + carry以提供unsignedcarry。如果我们考虑16位整数(在32位中使用相同,但更键入),则在第一个数字上,0xffff 0xffff == 0xfffe a随身携带1.0xffff 随身携带。因此,携带只能是一个。该算法是:

    unsigned lhs, rhs, carry_in;  // Input
    unsigned sum, carry_out;      // Output
    sum = lhs + rhs;
    carry_out = sum < lhs ;
    sum += carry_in;
    carry_out = carry_out || sum < lhs;

基本上,这个想法是在unsigned中进行添加,然后检测包装(因此随身携带)。非常烦人的是,这是大量有条件的逻辑和多个指令"随身携带",这是我使用过的每个说明集中的指令。(注意:可能值得进行carry_out的最终计算使用|而不是||-它保存分支,这对性能不利。与往常一样,配置文件查看是否有帮助。)

如果您最终要支持乘法,则需要一种类型,该类型的宽度是您的"数字"的两倍 - 在这种情况下,您也可以使用它来添加。使用上面的变量,假设"无签名的长长"是您的"宽"类型:

    const auto temp = (unsigned long long)lhs + rhs + carry_in;
    sum = temp; // Will truncate.
    carry_out = temp > UINT_MAX;

选择您的"宽"类型可能很棘手。作为第一次通过,最好将uint32_t用于数字,而uint64_t则用于您的宽类型。

有关实施多工算术的更多详细信息,《应用加密手册》第14章看起来很有用。