__int64 on a 32-Bit machine?

21,021

Solution 1

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.

Solution 2

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.

Solution 3

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.

Solution 4

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;.

Share:
21,021
Admin
Author by

Admin

Updated on August 03, 2022

Comments

  • Admin
    Admin almost 2 years

    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?