2

I have array of word,with 4 cells

RESULT DW 4 DUP(0)

it will contain Binary number,for example

MOV RESULT,   0H
MOV RESULT+2, 0H
MOV RESULT+4, 35A4H
MOV RESULT+6, E900H

now result contain 0000000035A4E900H which means 900000000 in Decimal way. not I wanna print 900000000 on monitor.

what should I do?

Moein Hosseini
  • 4,309
  • 15
  • 68
  • 106
  • 1
    so you want to print a 64 bit long integer on screen in decimal? – Stefan Paul Noack Jan 31 '12 at 14:14
  • The x86-16 is a little-endian architecture. The 4 lines of code that you provide make *result* equal to E90035A40000h. That's way more than the 900,000,000 that you want to print. – Sep Roland Sep 24 '22 at 17:43

2 Answers2

7

No matter what language you use converting to decimal to print in decimal is the same process. Well one of two processes. You can start from either end. Say you had a 16 bit number 12345 (0x3039).

The first way would be

divide by 10000 result is 1 remainder 2345 save or print the 1
divide by 1000 result is 2 remainder 345 save or print the 2
divide by 100 result is 3 remainder 45 save or print the 3
divide by 10 result is 4 remainder 5 save or print the 4 and 5

The second way

divide by 10 result is 1234 remainder 5 save the remainder use the result
divide by 10 result is 123 remainder 4 save the remainder use the result
divide by 10 result is 12 remainder 3 save the remainder use the result
divide by 10 result is 1 remainder 2 save both the remainder and result 
print the results in the right order

Now if your question is how do I divide a 64 bit number by these powers of 10 with the instruction set I have, well sometimes you can, sometimes you cant, sometimes you have to use other math rules. Dividing by 10 is the same as dividing by 2*5 so you could divide by 2 (shift) then divide by 5.

0x3039 (12345) divided by 10000 is the same as shift right 4 then divide by 5 to the power 4 (625). 0x303 = 771, 771/625 = 1. If your divide isnt that big your multiply might not be either so 1 * 625 = 0x271, 0x271 << 4 = 0x2710, 0x3039 - 0x2710 = 0x929 = 2345. Once you get down to a number you can divide with the hardware then use the hardware.

You might need to divide by one of the numbers in the middle, say you had a 32 bit number (max 4,294,967,296) and you have hardware that can divide from a 32 bit number into 16 bit result and 16 bit remainder. You can knock a couple of digits off using the above method say leaving 94,967,295 then divide by 10000 giving 9496 remainder 7295 then work through those four digit numbers independently using the hardware.

If you dont have division hardware but multiply hardware (yes I know you specified 8086) you can do this:

http://www.divms.uiowa.edu/~jones/bcd/divide.html

If you remember from grade school how to do a multiply on pencil and paper:

    1234
   x1010 
   =====
    0000  
   1234   
  0000
+1234 
========
 1246340

Binary makes that quite simple as you might picture from the numbers I chose

  abcd
x efgh
====== 

If you want to multiply the four bits abcd times the four bits efgh then:

result = 0;
if(h) result+=abcd << 0;
if(g) result+=abcd << 1;
if(f) result+=abcd << 2;
if(e) result+=abcd << 3;

With most instruction sets you can cascade this mulitply as wide as you have memory, want to multiply 1 million bits by 1 million bits. no problem, 500,000 bytes plus a little more or a few registers (and a lot of clock cycles).

egrunin
  • 24,650
  • 8
  • 50
  • 93
old_timer
  • 69,149
  • 8
  • 89
  • 168
2

I did pretty much what old_timer said but a bit more optimized. If the input is 65535 this will happen:

divide by 1000 result is 65 remainder 535 split the 65 then print it
divide 535 by 10 result is 53 remainder 5 split the 53 print it, then print the 5

It's more optimized because you need to do 16-bit division only two times and use only 3 16-bit registers a few times

Here's the code:

; ax = Value to print
printInteger:
    splitUpperSection:
        mov dx, 0
        mov bx, 1000
        div bx      ; bx / ax:dx --> ax = 65   dx = 535
        aam         ; ax -->  ah = 6    al = 5

    add  ax, 0x3030 ; Add hex 30 or decimal 48 because that's the value of letter 0 in ASCII
    xchg ah, al     ; Switch values
    mov  cl, ah

    mov  bx, 0x0007 ; DisplayPage=0, GraphicsColor=7
    mov  ah, 0x0E   ; BIOS.Teletype (printing AL)
    int  0x10
    mov  al, cl
    int  0x10

    mov  ax, dx

    splitLowerSection:
        mov dl, 10
        div dl      ; al = 53   ah = 5
        mov dl, ah
        aam         ; ah = 5   al = 3

    xchg ah, al
    add  ax, 0x3030
    mov  cl, ah

    mov  ah, 0x0E   ; BIOS.Teletype (printing AL)
    int  0x10
    mov  al, cl
    int  0x10

    mov  al, dl
    add  al, 0x30
    int  0x10

This video really helped me understand how and why

ZiyadCodes
  • 379
  • 3
  • 10
  • The line "div dl ; ax = 53 dx = 5" is wrong! The quotient of the **byte-sized** division `div dl` is in AL=53 and the remainder in AH=5. – Sep Roland Sep 24 '22 at 16:29
  • Why don't you use `add ax, 0x3030` a second time so the program is shorter by 3 bytes? – Sep Roland Sep 24 '22 at 16:34
  • @SepRoland oh yeah sorry, I fixed that comment now and added `add ax, 0x3030` Thanks for pointing that out – ZiyadCodes Sep 25 '22 at 07:50
  • 2
    The BIOS.Teletype function 0Eh has BX as one of its parameters! Don't use BH (or BL) for temporarily storing the next character. Still +1. – Sep Roland Oct 02 '22 at 11:36