How to properly add/subtract a 128-bit number (as two uint64_t)?

戏子无情 提交于 2019-12-11 07:30:48

问题


I'm working in C and need to add and subtract a 64-bit number and a 128-bit number. The result will be held in the 128-bit number. I am using an integer array to store the upper and lower halves of the 128-bit number (i.e. uint64_t bigNum[2], where bigNum[0] is the least significant).

Can anybody help with an addition and subtraction function that can take in bigNum and add/subtract a uint64_t to it?

I have seen many incorrect examples on the web, so consider this:

bigNum[0] = 0;  
bigNum[1] = 1;  
subtract(&bigNum, 1);

At this point bigNum[0] should have all bits set, while bigNum[1] should have no bits set.


回答1:


In grade 1 or 2, you should have learn't how to break down the addition of 1 and 10 into parts, by splitting it into multiple separate additions of tens and units. When dealing with big numbers, the same principals can be applied to compute arithmetic operations on arbitrarily large numbers, by realizing your units are now units of 2^bits, your "tens" are 2^bits larger and so on.




回答2:


This should work for the subtraction:

typedef u_int64_t bigNum[2];

void subtract(bigNum *a, u_int64_t b)
{
  const u_int64_t borrow = b > a[1];

  a[1] -= b;
  a[0] -= borrow;
}

Addition is very similar. The above could of course be expressed with an explicit test, too, but I find it cleaner to always do the borrowing. Optimization left as an exercise.

For a bigNum equal to { 0, 1 }, subtracting two would make it equal { ~0UL, ~0UL }, which is the proper bit pattern to represent -1. Here, UL is assumed to promote an integer to 64 bits, which is compiler-dependent of course.




回答3:


For the case the value that your are subtracting is less or equal to bignum[0] you don't have to touch bignum[1].

If it isn't, you subtract it from bignum[0], anyhow. This operation will wrap around, but this is the behavior you need here. In addition you'd then have to substact 1 from bignum[1].




回答4:


Most compilers support a __int128 type intrinsically.

Try it and you might be lucky.




回答5:


In many architectures it's very easy to add/subtract any arbitrarily-long integers because there's a carry flag and add/sub with flag instruction. For example on x86 rdx:rax += r8:r9 can be done like this

add rax, r9
adc rdx, r8

In C there's no way to access this carry flag so you must calculate the flag on your own. The easiest way is checking if the unsigned sum is less than either of the operand like this. For example to do a += b we'll do like this

aL += bL;
aH += bH + (aL < bL);

Here's some example assembly output



来源:https://stackoverflow.com/questions/4757338/how-to-properly-add-subtract-a-128-bit-number-as-two-uint64-t

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