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

社会主义新天地 提交于 2019-12-06 03:05:19

Right. So the basic problem is how to do unsigned + unsigned + carry to give unsigned and carry. If we consider 16-bit integers (it works the same in 32-bits, but is more typing), on the first digit, 0xFFFF + 0xFFFF == 0xFFFE + a carry of 1. On subsequent digits 0xFFFF + 0xFFFF + carry == 0xFFFF + carry. Hence carry can only be one. The algorithm is:

    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;

Basically, the idea is to do the addition in unsigned, and then detect wrapping (and hence carry). What is very annoying, is that this is masses of conditional logic and multiple instructions to implement "add with carry", which is an instruction in every instruction set I have ever used. (Note: it may be worth making the final calculation of carry_out use | rather than || - it saves branching, which is bad for performance. As always, profile to see if it helps.)

If you are going to eventually support multiplication, you need a type which is twice as wide as your "digit" - in which case, you might as well use it for addition too. Using the variables from above, and assuming "unsigned long long" is your "wide" type:

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

Choosing your "wide" type can be tricky. As a first pass, it's probably best to use uint32_t for your digits and uint64_t for your wide type.

For more details on implementing multi-precision arithmetic, Chapter 14 from Handbook of Applied Cryptography looks useful.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!