How do we add two 64 bit numbers using 32 bit arithmetic??
相关问题
- readdir() 32/64 compatibility issues
- Difference in casting float to int, 32-bit C
- x86 and x64 share instruction set?
- Ubuntu : dpkg --add-architecture i386 throwing err
- Issue running 32-bit executable on 64-bit Windows
相关文章
- Using a 64 bit driver in a 32 bit program. Windows
- How are numbers greater than 2^32 handled by a 32
- Why is abs(0x80000000) == 0x80000000?
- How can I choose between 32-bit or 64-bit build in
- How come a 32 bit kernel can run a 64 bit binary?
- What is this error- “IOError: [Errno 2] No such fi
- Where can I find a JDK for 32 bit Windows? [closed
- Stack overflow despite tail call position but only
Consider how you add two 2-digit numbers using 1-digit arithmetic.
First you add the right column. (The "ones" or "units"). 2+9 is 11. 11 "overflowed" your 1 digit arithmetic, so you have to "carry" the 10.
Now you add up the left "tens" column, including the carry. 1+4+3=8.
8 is less than 10, so no carry. You're done.
What just happened? When you say that a number is "42" (in base 10) you really mean
Or, equivalently,
(when I say "a^b", like "10^1", I mean "a raised to the b'th power": a multiplied by itself b times. 10^0 is 1. 10^1 is 10. 10^2 is 10*10=100...)
When you add "42" and "39" you are saying
Which equals
Now since "11" isn't a valid one digit number, you need to carry 10 from the ones, turning it into a 1 in the tens place.
which is 81.
So, why have I been talking about this rather than your question about 64 bit numbers and 32 bit arithmetic? Because they are actually exactly the same!
A digit ranges from 0 to 9. A "32 bit number" ranges from 0 to 2^32-1. (Assuming it is unsigned.)
So, rather than working in base 10, let's work in base 2^32. In base 2^32, we write 2^32 as 10. If you write a 64 bit number in base 2^32, it would be
where x and y are symbols for numbers between 0 and 2^32-1. Those symbols are bitstrings.
If you want to add two 64 bit numbers, break them down in base 2^32 as:
Now you add them in base 2^32 the exact same way you add them in base 10 -- just, rather than adding using digit arithmetic you add using 32 bit arithmetic!
How do you split a 64 bit number a into two 32 bit numbers a_1 and a_0? Divide a by 2^32. Not in floating point, but integerwise -- where you get a dividend and a remainder. The dividend is a_1, the remainder is a_0.
Unfortunately that requires 64 bit arithmetic. However, typically a_1 is the "most significant half" of a, so, in C style syntax:
where >> is a right bitshift and & is bitwise and.
Typically if you can't do 64 bit addition, a "64 bit number" will actually be the two 32 bit numbers a_1 and a_0. You won't have a uint64_t if you can't do uint64_t arithmetic!
All this assumes that you're doing unsigned arithmetic, but dealing with signs is easy from here.
The C code previously posted is unnecessarily verbose:
The 'a1' in the 'if' can be replaced with 'b1' as well. On overflow, c1 will be less than both a1 and b1.
Pretty much every processor has the carry bit and add-with-carry operation, which you only care about if you're programming in assembly. If you're using a higher language, the compiler dumps out the exact same add-with-carry operations. My AVR-GCC gave me this when adding two 16-bit numbers--the AVR is 8-bit--but the same concepts would apply for higher processors.
Given the numbers are in registers R1:R2 and R3:R4:
The result is stored into R1:R2.
If the 64-bit numbers are (a2,a1) and (b2,b1), where x2 is the high 32 bits taken as unsigned, and x1 is the low 32 bits taken as unsigned, then the sum of the two numbers is given below.
it looks something like this
Actual hardware doesn't use 32 bits to add 16 bits at a time, only one extra bit of carry is ever needed for addition, and almost all CPU's have a carry status flag for when an addition operation overflowed, so if you are using a 32 bit cpu, you can add 64 bit operands in two, 32 bit operations.
Add the least significant bytes first, keep the carry. Add the most significant bytes considering the carry from LSBs: