1

Following is the code I wrote to find LCM of two numbers in EMU8086. When I ran it, I am getting value 0 in the Ans variable.

.MODEL SMALL 
.DATA 
Num1 DW 250 
Num2 DW 100
Ans DW ? 
.CODE 
MOV AX,@DATA 
MOV DS, AX 
MOV AX, Num1 
MOV BX, Num2 
MOV DX, 0000h 
NEXT: PUSH AX 
PUSH DX 
DIV BX 
CMP DX, 0000h 
JZ LAST 
POP DX 
POP AX 
ADD AX, Num1 
JNC NEXT 
INC DX 
JMP NEXT 
LAST: POP Ans+2 
POP Ans 
MOV AH, 4Ch 
INT 21h 
END
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
havegudday
  • 65
  • 6
  • I wonder if it's related to [this](https://stackoverflow.com/questions/64717694/emu8086-dividing-32-bit-number-by-a-16-bit-number-gives-unexpected-0-remainder)? emu8086 seems to have a bug in its implementation of `DIV`. Have you tested with other emulators? – Nate Eldredge Nov 07 '20 at 15:58
  • 2
    One note, though; I haven't read the code carefully, but you seem to be storing two words of result at `Ans` and `Ans+2`. However, `Ans` only has one word allocated, so `pop Ans+2` is going to overwrite something else. Not sure if this is your bug, but it looks wrong. – Nate Eldredge Nov 07 '20 at 16:25
  • 1
    Also, this is a pretty absurd algorithm for finding the LCM; repeatedly adding `Num1` to itself until it is a multiple of `Num2`. You might look up "Euclid's algorithm" for something more efficient. – Nate Eldredge Nov 07 '20 at 16:27

1 Answers1

0

LCM(a, b) = a * b / GCD(a, b)

Due to this equation, you can find GCD using Euclid's algorithm and then calculate LCM. Assuming numbers a and b are in al and dl, this code calculate LCM.

; Save multiplication value
MOV AL, DL ; This 2 lines is AL * DH
MUL DH
PUSH AX ; Store result in stack

FINDBCD: ; General idea is : LCM(a, b) = a*b/BCD(a,b)
    ; We calculate BCD with euclidean algorithm
    CMP DH, DL
    JNS CALCULATE ; Jump if DL < DH else swap them
    MOV CL, DL ; This 3 line swap DL and DH
    MOV DL, DH
    MOV DH, CL
    CALCULATE:
    MOV AL, DH ; Move greater number in AL
    XOR AH, AH ; Zero AX 8 second bits
    DIV DL ; This is AL/DL
    CMP AH, 0 ; If remainder is zero so we found BCD
    JE AFTERFINDBCD
    SUB DH, DL ; Else substract smaller number from greater number
    JMP FINDBCD ; Do this until find BCD

AFTERFINDBCD:
    CMP DH, DL 
    JNS FINDLCM ; Jump if DL < DH
    MOV CL, DL ; This 3 line swap DL and DH
    MOV DL, DH
    MOV DH, CL

FINDLCM:
    POP AX ; Retreive multiplication result
    DIV DL ; This is AX/DL
    AND AX, 0000000011111111B ; Ignore remainder

parsa2820
  • 570
  • 4
  • 13
  • 1
    This takes two 8-bit inputs. The question has 16-bit inputs, so the LCM is potentially larger than 16-bit. As Brett Hale [pointed out](https://stackoverflow.com/questions/64790116/calculating-lcm-in-assembly-x86#comment114554910_64790854) on a related question, you can do `(a / gcd) * b` so you can end with a widening `mul`, because a is by definition divisible by the GCD. See Brett's answer on that linked question; doing the same thing with 16-bit regs should work for the OP. – Peter Cordes Nov 17 '20 at 18:24
  • 1
    If you really just want to swap DL and DH without leaving a copy anywhere else, `xchg dh,dl` is at least as efficient on almost all CPUs, much more efficient on real 8086. Also, `and ax, 0x00ff` is silly: use `mov ah,0` or `xor ah,ah` like you did earlier. – Peter Cordes Nov 17 '20 at 18:24
  • 1
    `CMP` / `JNS` is *not* how you check which one is larger. You want `ja` for unsigned above. The `ns` condition just checks the MSB of the subtraction result, which only works if the numbers were small or nearby when interpreted as signed integers (and signed overflow didn't happen). You're using unsigned `div`, so you should be using unsigned branch conditions. – Peter Cordes Nov 17 '20 at 18:30
  • 1
    Note that standard GCD only needs 2 `mov` instructions in the loop: [Greatest Common Divisor](https://codegolf.stackexchange.com/a/77334) – Peter Cordes Nov 17 '20 at 18:40
  • Thanks for your comments I didn't use assembly professionally and I actually didn't know most of them myself. – parsa2820 Nov 18 '20 at 13:10
  • You can still [edit] your answer to fix the `jns` bug, and any other improvements you want to make. And to point out that it's only handling 8-bit inputs. – Peter Cordes Nov 18 '20 at 19:21