I just tried something in MSVC 2010 on my 32-bit machine here and found out that I can use __int64
in my programs - which actually work!
How is that possible?
I just tried something in MSVC 2010 on my 32-bit machine here and found out that I can use __int64
in my programs - which actually work!
How is that possible?
Same way 32-bit arithmetic worked on 16-bit systems.
In this case, it uses 2 32-bit memory addresses to form a 64-bit number together. Addition/substraction is easy, you do it by parts, the only gotcha is taking the carry-over from the lower part to the higher part. For multiplication/division, it's harder (ie more instructions).
It's obviously slow, quite a bit slower than 32 bit arithmetic for multiplication, but if you need it, it's there for you. And when you upgrade to a 64-bit processor compiler, it gets automatically optimized to one instruction with the bigger word size.
The Visual Studio 2010 Professional implementation of 64 bit multiplication on a 32-bit processor, compiled in release mode, is:
_allmul PROC NEAR
A EQU [esp + 4] ; stack address of a
B EQU [esp + 12] ; stack address of b
mov eax,HIWORD(A)
mov ecx,HIWORD(B)
or ecx,eax ;test for both hiwords zero.
mov ecx,LOWORD(B)
jnz short hard ;both are zero, just mult ALO and BLO
mov eax,LOWORD(A)
mul ecx
ret 16 ; callee restores the stack
hard:
push ebx
A2 EQU [esp + 8] ; stack address of a
B2 EQU [esp + 16] ; stack address of b
mul ecx ;eax has AHI, ecx has BLO, so AHI * BLO
mov ebx,eax ;save result
mov eax,LOWORD(A2)
mul dword ptr HIWORD(B2) ;ALO * BHI
add ebx,eax ;ebx = ((ALO * BHI) + (AHI * BLO))
mov eax,LOWORD(A2) ;ecx = BLO
mul ecx ;so edx:eax = ALO*BLO
add edx,ebx ;now edx has all the LO*HI stuff
pop ebx
ret 16 ; callee restores the stack
As you can see, it's a LOT slower than normal multiplication.
Why do you find it surprising? There's nothing to prevent the compiler from supporting 64-, 128- or more-bit integer types on a 32-bit machine. The compiler can even support 57- and 91-bit types, if it feels like it. In practice supporting 2N-bit integer arithmetic on an N-bit machine is a relatively easy task, since the instruction set of a typical machine is often designed with this kind of functionality in mind.
32 bits are merely the native size of a machine word, meaning they can be processed in one go, it does not mean that larger items can't be processed at all, they just need to be processed as separate 32-bit units in multiple steps, in the same way they can be smaller than a machine word, in which case merely a portion of the full machine word will be processed.
It works because 64-bit integer data types are part of the language specification.
A compiler for the language MUST let you work with 64-bit integers (and get correct results, of course).
Your program must work (and work exactly the same), whether you target a 64-bit, 32-bit, 16-bit, or 8-bit machine (whatever the compiler allows).
Whoever wrote the compiler was obliged to make it do whatever is needed to make every supported data type work on every targeted processor type.
Supporting potentially "higher" data types has all been taken care of, so that you don't have to do it yourself.
How?
Obviously, accepting code that commands 16-bit arithmetic operations and translating it into machine code that runs on a 16-bit (or higher) processor is "easy" work for a compiler, almost a direct translation. Z = X + Y
might translate to mov a,(X); add a,(Y); mov (Z),a;
.
Conversely, accepting code that commands 64-bit arithmetic operations and translating it into machine code that runs on a 32-bit (or lower) processor is more complex. The compiler has more work to do, operating on 32-bit pieces of each operand at a time. There are more ways to do get it done.
The resulting machine code could use multiple instructions inline (bigger code, faster execution). Z = X + Y
might translate to mov a,(X); adc a,(Y); mov (Z),a; mov a,CARRY; adc a,(X+1); adc a,(Y+1); mov (Z+1),a;
.
The resulting machine code could call extended arithmetic subroutines (smaller code, slower execution). Z = X + Y
might translate to mov a,X; call GET64; mov a,Y; call ADD64; mov a,Z; call STORE64;
.