无32位寄存器的32位/16位有符号整数除法问题(286平台)
Fixing 32-bit Signed Division by 16-bit on 286 (IDIV32 Issues)
Let's break down why your current IDIV32 implementation is failing, and walk through a corrected version that leverages your working DIV32 code.
What's Wrong with the Original IDIV32?
Your approach of swapping XOR DX,DX with CWD and DIV with IDIV works only for positive values where the quotient fits in 16 bits, but it breaks for signed cases because:
- Incorrect stepwise division logic: The two-step division that works for unsigned numbers doesn't translate to signed division. Signed division relies on the entire 32-bit dividend's sign, not just the high 16 bits. Splitting it into two 16-bit signed divisions produces invalid intermediate results (like your
-131076/2returning-2instead of-65538). - IDIV range limitations: The 286
IDIVinstruction requires the quotient to fit within a 16-bit signed integer (-32768 to 32767). When dividing by ±1, the high 16 bits of a large 32-bit dividend (e.g.,0x80000000) will produce a quotient that exceeds this range, triggering a division error.
Corrected IDIV32 Implementation
Instead of trying to adapt the stepwise signed division, we'll use a more reliable approach: convert the problem to unsigned division (using your working DIV32), then adjust the signs of the quotient and remainder afterward.
IDIV32 PROC ;DIVIDES A SIGNED 32-BIT VALUE BY A SIGNED 16-BIT VALUE. ;ALTERS AX, BX, DX, SI, DI ;EXPECTS THE SIGNED 32-BIT DIVIDEND IN DX:AX ;EXPECTS THE SIGNED 16-BIT DIVISOR IN BX ;RETURNS THE SIGNED 32-BIT QUOTIENT IN DX:AX ;RETURNS THE SIGNED 16-BIT REMAINDER IN BX push cx push di push si ; Save sign flags: ; SI = quotient sign (0=positive, 1=negative) ; DI = remainder sign (matches original dividend's sign) xor si, si xor di, di ; Check and normalize dividend (convert to unsigned absolute value) test dx, 8000h ; Check if dividend is negative (bit 31 set) jz @f mov di, 1 ; Remainder will be negative or si, 1 ; Quotient sign starts as negative ; Compute absolute value of 32-bit dividend neg dx neg ax sbb dx, 0 ; Handle carry from negating AX @@: ; Check and normalize divisor (convert to unsigned absolute value) test bx, 8000h ; Check if divisor is negative (bit 15 set) jz @f xor si, 1 ; Flip quotient sign (negative ÷ negative = positive) ; Compute absolute value of 16-bit divisor neg bx @@: ; Use working unsigned division to get quotient and remainder call DIV32 ; Adjust quotient sign if needed test si, 1 jz @f ; Negate 32-bit quotient (convert back to signed negative) neg dx neg ax sbb dx, 0 @@: ; Adjust remainder sign to match original dividend test di, 1 jz @f ; Negate 16-bit remainder neg bx @@: pop si pop di pop cx ret IDIV32 ENDP
How This Works
- Sign Tracking: We first record whether the original dividend and divisor are negative. The quotient's sign is the XOR of the two signs, and the remainder's sign always matches the original dividend (per signed division rules).
- Normalization: Convert both the dividend and divisor to their unsigned absolute values. For the 32-bit dividend, we use
neg ax+neg dx+sbb dx,0to correctly handle the edge case of0x80000000(the smallest 32-bit signed integer, which has no positive equivalent). - Unsigned Division: Call your trusted
DIV32to compute the unsigned quotient and remainder. - Sign Adjustment: Convert the unsigned results back to signed values by negating them if their recorded sign requires it.
Testing Your Problem Cases
-131076 / 2: The dividend converts to0x00020004(unsigned), divides by 2 to get quotient0x00010002and remainder0. We negate the quotient to get-65538(correct) and leave the remainder as0.- Divisor ±1: By using unsigned division, we avoid the
IDIVrange limit. For example,0x80000000 / -1converts to0x80000000 / 1(unsigned), quotient0x80000000, then we negate it to get0x80000000(the correct signed result, no division error). -65538 / 2: Converts to0x00010002 / 2, quotient0x00008001, negated to-32769(correct).
内容的提问来源于stack exchange,提问作者bad
相关产品推荐
相关产品推荐

