Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

For example in Java programming language we can use int (32 bit) or long (64 bit) values. As I understood 32 bit cpu can operate with 32 bit numbers in one cycle. There is 32-bit and 64-bit cpu's. So the question is how 32 bit cpu will work with long values (64 bit). Some literature will be appreciated.

And one more question, why 32 bit processor can work only with 4 gb and lower RAM?

share|improve this question
This question has been asked so many times, and answered even more. Memory limit for 32bit cpus is 2^32 (about 4 GB), which means that all memory in the computer must fall into that limit. Some cpus support Physical Address Extension (PAE), which allows them to circumvent this limit. You should really google this up, resources are plenty. – Damir Kasipovic Feb 25 '14 at 13:48
Who told you that 32-bit processors can only work with 4GB of memory? CPUs use memory registers. In a 32-bit environment these registers hold 32-bit in a 64-bit environment these hold 64-bits. A 32-bit processor would use 2 memory registers to hold 64-bits of information. – Ramhound Feb 25 '14 at 13:50
The Wiki article on PAE would be relevant also. – Jonathan Garber Feb 25 '14 at 16:32
up vote 1 down vote accepted

Doubled integer precision is just a special case of arbitrary precision. At the level of assembly language, how this is implemented is dependent on the ISA. (Even though you asked specifically about x86, I will provide some additional information.)

For addition and subtraction, many ISAs (e.g., ARM, Power, x86) provide a carry (borrow for subtraction) bit and special add with carry and subtract with borrow instructions.

ADD r1, r2, r3; // r1 = r2 + r3, set or clear carry bit
ADDC r4, r5, r6; // r4 = r5 + r6 + carry bit (also sets/clears carry)

Some ISAs (e.g., Alpha [which was always 64-bit], MIPS) do not provide a carry bit and special add/subtract instructions. These may use a set-on-less-than instruction (setting a register to zero if not less than and to one if less than) to test whether the result is less than one of the operands (which determines whether the result generated a carry).

ADD r1, r2, r3; // r1 = r2 + r3
ADD r4, r5, r6; // r4 = r5 + r6
SLT r7, r1, r2; // r7 = (r1 < r2)? 1 : 0 (determining carry)
ADD r4, r4, r7; // r4 = r4 + r7 (adding in carry)

(The ISA designers who chose not to provide a carry bit did so because multiple precision operation is not common, a single carry bit introduces a data dependency that hinders superscalar operation, and special bits make register renaming for out-of-order execution more complex.)

For multiplication, doubled precision might not be enough to make sophisticated algorithms more efficient, so the straightforward method of generating partial products and summing the results might be preferred. This uses the formula (where a and c are the upper half of the doubled precision value):

(a + b) * (c + d) = a*c + a*d + b*c + b*d.

(For simplicity, the following assumes a doubled precision result with any excess being ignored. This means that the product term a*c is ignored completely.)

For an ISA (e.g., MIPS, x86) that provides both a high and a low result from a single multiply, the operation is reasonably straightforward. The following is a rough approximation for x86 (I am not familiar with the details):

 MUL r2:r0, r3, r7; // multiply a*d
 MOV r1, r0;  // preserve low result of a*d
 MUL r2:r0, r5, r6; // multiply b*c
 MOV [temp], R0; // preserve low result on stack at temp
 MUL r2:r0, r5, r7; // multiply b*d
 ADD r2, r1; // add high b*d and low b*c for part of 
                  // higher result
 ADD r2, [temp]; // add partial higher result and low a*d
 // doubled precision product is now in r2:r0

For an ISA (e.g., Alpha) that provides separate multiply for high result and multiple for low result instructions (multiplication naturally produces a doubled precision value), this operation is somewhat similar:

// a*c result is beyond doubled precision range
MULL r16, r1, r4; // low multiply result (a*d)
// high a*d result is beyond doubled precision range
MULL r17, r2, r3; // low multiply result (b*c)
// high b*c result is beyond doubled precision range
MULL r18, r2, r4; // low multiply result (b*d)
MULH r19, r2, r4; // high multiply result (b*d)
ADD  r20, r19, r17; // sum high (b*d) and low (b*c)
                    // for part of higher result
ADD  r20, r20, r16; // sum partial result and low (a*d)
// double precision result is in r20:r16

(Some ISAs do not provide a means of getting the higher result of a multiply. For such ISAs, the operands could be split into half-sized units and a quadruple precision multiplication performed, though there is probably a more sophisticated algorithm. ISAs with multiply add instructions can obviously merge the additions and two of the multiplies into multiply-adds.)

The above pseudo-assembly code assumes that overflow is not a concern (and is not optimized for performance). An actual implementation would handle such properly.

The GNU Multiple Precision Arithmetic Library, an open-source library for arbitrary precision arithmetic, would provide details of a real-world implementation.

Address Space Limitations

The reason that a 32-bit processor can (in a simple sense) only use 4 GiB of memory is that it uses 32-bit pointers/addresses and use byte addressing (so 232 addresses are available). Traditionally, even with virtual memory systems, supporting a physical address space (which includes memory-mapped I/O addresses, by the way) larger than 4 GiB was considered unnecessary. (A 4 GiB physical address space is also convenient for 32-bit page table entries, allowing the use of 10 bits to define validity, permissions, and other metadata when using 4 KiB pages. Using 64-bit page table entries would tend to use excess memory for small systems, and initial 32-bit systems were small.)

To extend the life of 32-bit ISAs, some ISAs (e.g., ARM, x86) added Physical Address Extensions which use a 64-bit page table entry to allow a larger physical address. This workaround is awkward, especially for the OS (which must manage all of the physical memory).

Some ISAs (like HP PA-RISC) provided a segmentation system which allowed user-level programs to address a larger address space by appending special purpose segment registers to the top of the address. (Power[PC] also uses segments, but the values cannot be modified by unprivileged [i.e., application] software.)

(In theory, an ISA could used a register pair to expand memory addressing capabilities, like some 8-bit processors. However, by that point moving to a 64-bit ISA generally makes more sense.)

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.