flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > Reciprocals macro

Author
Thread Post new topic Reply to topic
idle



Joined: 06 Jan 2011
Posts: 359
Location: Ukraine
idle
Razz
Code:
; the macro generates constants to replace div by mul
; having questions, mail me to edemko@rambler.ru, or find me at www.board.flatassembler.net
; examples: rcp32 0
;           rcp32 1
;           rcp32 2
;           rcp32 10
;           rcp32 60
;           rcp32 100
;           rcp32 60*60
;           ...
macro rcp32 divisor*{
  virtual at 0
    local dvs
    dvs = divisor

    if dvs = 0 | dvs = 1
      display 13, 10, 'division by ', dvs + '0', ' is easy'
      err
    end if

    if dvs shr 32 <> 0
      display 13, 10, 'divisor must be a 32bit value'
      err
    end if

    repeat 31
      if dvs = 1 shl %
        display 13, 10, 'division by this power of 2 = dividend shr ', % / 10 + '0', % mod 10 + '0'
        err
      end if
    end repeat

    local dvd, quo, counter, stop_counter?
    dvd = 1
    quo = 0
    counter = 0
    stop_counter? = 0

    repeat 32 + 31
      dvd = dvd shl 1
      quo = quo shl 1
      if dvd >= dvs
        dvd = dvd - dvs
        quo = quo + 1
        stop_counter? = 1
      else
        if stop_counter? = 0
          counter = counter + 1
        end if
      end if
    end repeat

    display 13, 10, 'mov     eax,dividend',\
            13, 10, 'mov     edx,$'
    dq quo shr 31
    quo = quo shl counter shr 31 or 1
    repeat 32 / 4
      quo = quo shl 4
      if quo and $f'0000'0000 > $9'0000'0000
        quo = quo + $7'0000'0000
      end if
      display quo shr 32 + '0'
      quo = quo and $ffff'ffff
      if % = 4
        display ''''
      end if
    end repeat
    display ' ;normalized reciprocal(0.'
    load quo qword from 0
    repeat 18
      quo = quo * 10
      display quo shr 32 + '0'
      quo = quo and $ffff'ffff
    end repeat
    display ' * 2^', counter / 10 + '0', counter mod 10 + '0', ')',\
            13, 10, 'mul     edx            ;multiply id est divide Smile',\
            13, 10, 'shr     edx,', counter / 10 + '0', counter mod 10 + '0', '         ;compensate quotient'
  end virtual
}




rcp32 10
    

I wish you code to be fast.
Post 22 Jan 2011, 21:19
View user's profile Send private message Reply with quote
idle



Joined: 06 Jan 2011
Posts: 359
Location: Ukraine
idle
hi
this is a small revision
Tomasz, i think break if condition, and break stopping macro execution, would make a big deal Razz

this...
Code:


                       ;divisor = 0'000'000'010
mov     eax,dividend
mov     edx,$CCCC'CCCD ;normalized reciprocal(0.099999999860301613 * 2^03)
mul     edx            ;multiply id est divide Smile
shr     edx,03         ;compensate quotient

                       ;divisor = 0'000'000'009
mov     eax,dividend
mov     edx,$E38E'38E3 ;normalized reciprocal(0.111111111007630825 * 2^03)
mul     edx            ;multiply id est divide Smile
shr     edx,03         ;compensate quotient

                       ;divisor = 0'000'000'008
mov     eax,dividend
shr     eax,03         ;divisor is power of 2 Smile

                       ;divisor = 0'000'000'007
mov     eax,dividend
mov     edx,$9249'2493 ;normalized reciprocal(0.142857142724096775 * 2^02)
mul     edx            ;multiply id est divide Smile
shr     edx,02         ;compensate quotient

                       ;divisor = 0'000'000'006
mov     eax,dividend
mov     edx,$AAAA'AAAB ;normalized reciprocal(0.166666666511446237 * 2^02)
mul     edx            ;multiply id est divide Smile
shr     edx,02         ;compensate quotient

                       ;divisor = 0'000'000'005
mov     eax,dividend
mov     edx,$CCCC'CCCD ;normalized reciprocal(0.199999999953433871 * 2^02)
mul     edx            ;multiply id est divide Smile
shr     edx,02         ;compensate quotient

                       ;divisor = 0'000'000'004
mov     eax,dividend
shr     eax,02         ;divisor is power of 2 Smile

                       ;divisor = 0'000'000'003
mov     eax,dividend
mov     edx,$AAAA'AAAB ;normalized reciprocal(0.333333333255723118 * 2^01)
mul     edx            ;multiply id est divide Smile
shr     edx,01         ;compensate quotient

                       ;divisor = 0'000'000'002
mov     eax,dividend
shr     eax,01         ;divisor is power of 2 Smile

division by 1 is easy
    

...is generated by this
Code:
; the macro generates constants to replace div by mul
; having questions, mail me to edemko@rambler.ru, or find me at www.board.flatassembler.net
; examples: rcp32 0
;           rcp32 1
;           rcp32 2
;           rcp32 10
;           rcp32 60
;           rcp32 100
;           rcp32 60*60
;           ...
macro rcp32 divisor*{
  virtual at 0
    local dvs
    dvs = divisor

    if dvs shr 32 <> 0
      display 13, 10, 'divisor must be a 32bit value'
      err
    end if

    if dvs < 2
      display 13, 10, 'division by ', dvs + '0', ' is easy'
      err
    end if

    display 13, 10, '                       ;divisor = ',\
                     dvs / 1'000'000'000         + '0',\
                    '''',\
                    (dvs / 0'100'000'000) mod 10 + '0',\
                    (dvs / 0'010'000'000) mod 10 + '0',\
                    (dvs / 0'001'000'000) mod 10 + '0',\
                    '''',\
                    (dvs / 0'000'100'000) mod 10 + '0',\
                    (dvs / 0'000'010'000) mod 10 + '0',\
                    (dvs / 0'000'001'000) mod 10 + '0',\
                    '''',\
                    (dvs / 0'000'000'100) mod 10 + '0',\
                    (dvs / 0'000'000'010) mod 10 + '0',\
                     dvs                  mod 10 + '0'

    repeat 31
      if dvs = 1 shl %
        display 13, 10, 'mov     eax,dividend',\
                13, 10, 'shr     eax,', % / 10 + '0', % mod 10 + '0', '         ;divisor is power of 2 Smile'
        dvs = 0
        break
      end if
    end repeat

    if dvs <> 0
      local dvd, quo, counter, stop_counter?
      dvd = 1
      quo = 0
      counter = 0
      stop_counter? = 0

      repeat 32 + 31
        dvd = dvd shl 1
        quo = quo shl 1
        if dvd >= dvs
          dvd = dvd - dvs
          quo = quo + 1
          stop_counter? = 1
        else
          if stop_counter? = 0
            counter = counter + 1
          end if
        end if
      end repeat

      display 13, 10, 'mov     eax,dividend',\
              13, 10, 'mov     edx,$'
      dq quo shr 31
      quo = quo shl counter shr 31 or 1
      repeat 32 / 4
        quo = quo shl 4
        if quo and $f'0000'0000 > $9'0000'0000
          quo = quo + $7'0000'0000
        end if
        display quo shr 32 + '0'
        quo = quo and $ffff'ffff
        if % = 4
          display ''''
        end if
      end repeat
      display ' ;normalized reciprocal(0.'
      load quo qword from 0
      repeat 18
        quo = quo * 10
        display quo shr 32 + '0'
        quo = quo and $ffff'ffff
      end repeat
      display ' * 2^', counter / 10 + '0', counter mod 10 + '0', ')',\
              13, 10, 'mul     edx            ;multiply id est divide Smile',\
              13, 10, 'shr     edx,', counter / 10 + '0', counter mod 10 + '0', '         ;compensate quotient'
    end if
  end virtual
}




count equ 10
rept count var1:0{
  display 13,10
  rcp32 count-var1
}
    
Post 23 Jan 2011, 06:55
View user's profile Send private message Reply with quote
idle



Joined: 06 Jan 2011
Posts: 359
Location: Ukraine
idle
this is v3:
- new hex macro
- fraction macro supports 64 bit fractions
- rounding corrected
- set LANG equ ENU to switch from RUS, that's the reason i did not put code directly


Description:
Download
Filename: rcp.asm
Filesize: 4.15 KB
Downloaded: 107 Time(s)

Post 31 Jan 2011, 06:30
View user's profile Send private message Reply with quote
idle



Joined: 06 Jan 2011
Posts: 359
Location: Ukraine
idle
this is v4:
- new hex macro
- rounding corrected, staying experimental
- english language only, i'm sorry, let me know and i'll write russian one
- macro supports check-code creation

main file:
Code:
;show_hex <13,10,'$'>, 00, 00, ';',\
;         <13,10,'$'>, 01, 01, ';',\
;         <13,10,'$'>, 02, 02, ';',\
;         <13,10,'$'>, 03, 03, ';',\
;         <13,10,'$'>, 04, 04, ';',\
;         <13,10,'$'>, 05, 05, ';',\
;         <13,10,'$'>, 06, 06, ';',\
;         <13,10,'$'>, 07, 07, ';',\
;         <13,10,'$'>, 08, 08, ';',\
;         <13,10,'$'>, 09, 09, ';',\
;         <13,10,'$'>, 10, 10, ';',\
;         <13,10,'$'>, 11, 11, ';',\
;         <13,10,'$'>, 12, 12, ';',\
;         <13,10,'$'>, 13, 13, ';',\
;         <13,10,'$'>, 14, 14, ';',\
;         <13,10,'$'>, 15, 15, ';',\
;         <13,10,'$'>, 16, 16, ';',\
;         <13,10,'$'>, 17, 17, ';'
;
;repeat 18
;  show_hex <13,10,'$'>, %-1, ';'
;end repeat
macro show_hex [intro, val, count, outro]{
  common
    local c, v, d
  forward
    display intro
    c = count
    if c > 0 & c < 17
      v = val
      while c > 0
        c = c - 1
        d = v shr (c * 4) and 1111b
        display d + '0' + d/10*7
        if c <> 0 & c mod 4 = 0
          display ''''
        end if
      end while
    end if
    display outro
}




;show_frac <13,10,'2^-1       : '>, $8000'0000'0000'0000, ';',\
;          <13,10,'2^-2       : '>, $4000'0000'0000'0000, ';',\
;          <13,10,'2^-1 + 2^-2: '>, $c000'0000'0000'0000, ';'
;
;repeat 64
;  show_frac <13,10>, 1 shl (%-1), ''
;end repeat
macro show_frac [intro, val, outro]{
  common
    local a, b
  forward
    display intro, '0.'
    a = (val) and $ffff'ffff
    b = (val) shr 32
    repeat 18
      a = a * 10
      b = b * 10 + a shr 32
      display b shr 32 + '0'
      a = a and $ffff'ffff
      b = b and $ffff'ffff
      if % = 18
        display outro
      else if % mod 3 = 0
        display ''''
      end if
    end repeat
}




;repeat 17
;  display 13,10
;  rcp32 %-1
;end repeat
;
;repeat 17
;  display 13,10
;  rcp32 %-1, :)
;end repeat
macro rcp32 val, check{
  local dvs
  dvs = (val) and $ffff'ffff
repeat 1
  if dvs < 2
    display 13, 10, ':) can you not divide by ', dvs + '0'
    break
  end if

  local dvd, quo, cnt, cnt?
  dvd  = 1
  quo  = 0
  cnt  = 0
  cnt? = 1
  repeat 64
    dvd = dvd shl 1
    quo = quo shl 1
    if dvd < dvs
      if cnt? = 1
        cnt = cnt + 1
      end if
    else
      cnt? = 0
      dvd = dvd - dvs
      quo = quo + 1
    end if
  end repeat

  show_hex <13, 10, ';   divisor[$1f..$00] = $'>  , dvs,  8, '',\
           <13, 10, '; 1/divisor[$1f..$00] = $0.'>, quo, 16, ''
  show_frac '(', quo, ')'

  repeat 31
    if dvs = 1 shl %
      show_hex <13, 10, 'code:   shr     eax,$'>, %, 2, '           ; divisor is this power of two'
      dvs = 0
      break
    end if
  end repeat
  if dvs = 0
    break
  end if

  quo = quo shr (32-cnt-1)
  if quo and 1 = 1
    quo = quo + 10b
  else
    quo = quo or 10b
  end if
  quo = quo shr 1

  show_hex <13, 10, 'code:   mov     edx,$'>, quo, 8, '    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$', '', cnt, 2, '), and rounded',\
           <13, 10, '        mul     edx               ; id est div :)'>, , 0, '',\
           <13, 10, '        shr     edx,$'>, cnt, 2, '           ; compensate quotient'

  if ~ check eq
    show_hex <13,10,'; use this code to check rcp32 over',\
              13,10,'        call    check',\
              13,10,'        jne     mail_edemko@rambler.ru_about_rounding_error',\
              13,10,'        invoke  MessageBoxA,0,''rcp32 returned ok'',0,0',\
              13,10,'        invoke  ExitProcess,0',\
              13,10,'mail_edemko@rambler.ru_about_rounding_error:',\
              13,10,'        hlt',\
              13,10,'check:  mov     esi,$'>,dvs,8,<\
              13,10,'        or      ecx,-1',\
              13,10,'  .loop:xor     edx,edx',\
              13,10,'        mov     eax,ecx',\
              13,10,'        div     esi',\
              13,10,'        mov     ebx,eax',\
              13,10,'        mov     eax,$'>,'',quo,8,<\
              13,10,'        mul     ecx',\
              13,10,'        shr     edx,$'>,'',cnt,2,<\
              13,10,'        cmp     edx,ebx',\
              13,10,'        loope   .loop',\
              13,10,'        ret'>
  end if
end repeat}
    

this...
Code:
repeat 17
  display 13,10
  rcp32 %-1
end repeat
    

...creates this:
Code:


:) can you not divide by 0

:) can you not divide by 1

;   divisor[$1f..$00] = $0000'0002
; 1/divisor[$1f..$00] = $0.8000'0000'0000'0000(0.500'000'000'000'000'000)
code:   shr     eax,$01           ; divisor is this power of two

;   divisor[$1f..$00] = $0000'0003
; 1/divisor[$1f..$00] = $0.5555'5555'5555'5555(0.333'333'333'333'333'333)
code:   mov     edx,$AAAA'AAAB    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$01), and rounded
        mul     edx               ; id est div :)
        shr     edx,$01           ; compensate quotient

;   divisor[$1f..$00] = $0000'0004
; 1/divisor[$1f..$00] = $0.4000'0000'0000'0000(0.250'000'000'000'000'000)
code:   shr     eax,$02           ; divisor is this power of two

;   divisor[$1f..$00] = $0000'0005
; 1/divisor[$1f..$00] = $0.3333'3333'3333'3333(0.199'999'999'999'999'999)
code:   mov     edx,$CCCC'CCCD    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$02), and rounded
        mul     edx               ; id est div :)
        shr     edx,$02           ; compensate quotient

;   divisor[$1f..$00] = $0000'0006
; 1/divisor[$1f..$00] = $0.2AAA'AAAA'AAAA'AAAA(0.166'666'666'666'666'666)
code:   mov     edx,$AAAA'AAAB    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$02), and rounded
        mul     edx               ; id est div :)
        shr     edx,$02           ; compensate quotient

;   divisor[$1f..$00] = $0000'0007
; 1/divisor[$1f..$00] = $0.2492'4924'9249'2492(0.142'857'142'857'142'857)
code:   mov     edx,$9249'2493    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$02), and rounded
        mul     edx               ; id est div :)
        shr     edx,$02           ; compensate quotient

;   divisor[$1f..$00] = $0000'0008
; 1/divisor[$1f..$00] = $0.2000'0000'0000'0000(0.125'000'000'000'000'000)
code:   shr     eax,$03           ; divisor is this power of two

;   divisor[$1f..$00] = $0000'0009
; 1/divisor[$1f..$00] = $0.1C71'C71C'71C7'1C71(0.111'111'111'111'111'111)
code:   mov     edx,$E38E'38E4    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$03), and rounded
        mul     edx               ; id est div :)
        shr     edx,$03           ; compensate quotient

;   divisor[$1f..$00] = $0000'000A
; 1/divisor[$1f..$00] = $0.1999'9999'9999'9999(0.099'999'999'999'999'999)
code:   mov     edx,$CCCC'CCCD    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$03), and rounded
        mul     edx               ; id est div :)
        shr     edx,$03           ; compensate quotient

;   divisor[$1f..$00] = $0000'000B
; 1/divisor[$1f..$00] = $0.1745'D174'5D17'45D1(0.090'909'090'909'090'909)
code:   mov     edx,$BA2E'8BA3    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$03), and rounded
        mul     edx               ; id est div :)
        shr     edx,$03           ; compensate quotient

;   divisor[$1f..$00] = $0000'000C
; 1/divisor[$1f..$00] = $0.1555'5555'5555'5555(0.083'333'333'333'333'333)
code:   mov     edx,$AAAA'AAAB    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$03), and rounded
        mul     edx               ; id est div :)
        shr     edx,$03           ; compensate quotient

;   divisor[$1f..$00] = $0000'000D
; 1/divisor[$1f..$00] = $0.13B1'3B13'B13B'13B1(0.076'923'076'923'076'923)
code:   mov     edx,$9D89'D89E    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$03), and rounded
        mul     edx               ; id est div :)
        shr     edx,$03           ; compensate quotient

;   divisor[$1f..$00] = $0000'000E
; 1/divisor[$1f..$00] = $0.1249'2492'4924'9249(0.071'428'571'428'571'428)
code:   mov     edx,$9249'2493    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$03), and rounded
        mul     edx               ; id est div :)
        shr     edx,$03           ; compensate quotient

;   divisor[$1f..$00] = $0000'000F
; 1/divisor[$1f..$00] = $0.1111'1111'1111'1111(0.066'666'666'666'666'666)
code:   mov     edx,$8888'8889    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$03), and rounded
        mul     edx               ; id est div :)
        shr     edx,$03           ; compensate quotient

;   divisor[$1f..$00] = $0000'0010
; 1/divisor[$1f..$00] = $0.1000'0000'0000'0000(0.062'500'000'000'000'000)
code:   shr     eax,$04           ; divisor is this power of two
    

this...
Code:
repeat 17
  display 13,10
  rcp32 %-1, :)
end repeat
    

...creates this:
Code:


:) can you not divide by 0

:) can you not divide by 1

;   divisor[$1f..$00] = $0000'0002
; 1/divisor[$1f..$00] = $0.8000'0000'0000'0000(0.500'000'000'000'000'000)
code:   shr     eax,$01           ; divisor is this power of two

;   divisor[$1f..$00] = $0000'0003
; 1/divisor[$1f..$00] = $0.5555'5555'5555'5555(0.333'333'333'333'333'333)
code:   mov     edx,$AAAA'AAAB    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$01), and rounded
        mul     edx               ; id est div :)
        shr     edx,$01           ; compensate quotient
; use this code to check rcp32 over
        call    check
        jne     mail_edemko@rambler.ru_about_rounding_error
        invoke  MessageBoxA,0,'rcp32 returned ok',0,0
        invoke  ExitProcess,0
mail_edemko@rambler.ru_about_rounding_error:
        hlt
check:  mov     esi,$0000'0003
        or      ecx,-1
  .loop:xor     edx,edx
        mov     eax,ecx
        div     esi
        mov     ebx,eax
        mov     eax,$AAAA'AAAB
        mul     ecx
        shr     edx,$01
        cmp     edx,ebx
        loope   .loop
        ret

;   divisor[$1f..$00] = $0000'0004
; 1/divisor[$1f..$00] = $0.4000'0000'0000'0000(0.250'000'000'000'000'000)
code:   shr     eax,$02           ; divisor is this power of two

;   divisor[$1f..$00] = $0000'0005
; 1/divisor[$1f..$00] = $0.3333'3333'3333'3333(0.199'999'999'999'999'999)
code:   mov     edx,$CCCC'CCCD    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$02), and rounded
        mul     edx               ; id est div :)
        shr     edx,$02           ; compensate quotient
; use this code to check rcp32 over
        call    check
        jne     mail_edemko@rambler.ru_about_rounding_error
        invoke  MessageBoxA,0,'rcp32 returned ok',0,0
        invoke  ExitProcess,0
mail_edemko@rambler.ru_about_rounding_error:
        hlt
check:  mov     esi,$0000'0005
        or      ecx,-1
  .loop:xor     edx,edx
        mov     eax,ecx
        div     esi
        mov     ebx,eax
        mov     eax,$CCCC'CCCD
        mul     ecx
        shr     edx,$02
        cmp     edx,ebx
        loope   .loop
        ret

;   divisor[$1f..$00] = $0000'0006
; 1/divisor[$1f..$00] = $0.2AAA'AAAA'AAAA'AAAA(0.166'666'666'666'666'666)
code:   mov     edx,$AAAA'AAAB    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$02), and rounded
        mul     edx               ; id est div :)
        shr     edx,$02           ; compensate quotient
; use this code to check rcp32 over
        call    check
        jne     mail_edemko@rambler.ru_about_rounding_error
        invoke  MessageBoxA,0,'rcp32 returned ok',0,0
        invoke  ExitProcess,0
mail_edemko@rambler.ru_about_rounding_error:
        hlt
check:  mov     esi,$0000'0006
        or      ecx,-1
  .loop:xor     edx,edx
        mov     eax,ecx
        div     esi
        mov     ebx,eax
        mov     eax,$AAAA'AAAB
        mul     ecx
        shr     edx,$02
        cmp     edx,ebx
        loope   .loop
        ret

;   divisor[$1f..$00] = $0000'0007
; 1/divisor[$1f..$00] = $0.2492'4924'9249'2492(0.142'857'142'857'142'857)
code:   mov     edx,$9249'2493    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$02), and rounded
        mul     edx               ; id est div :)
        shr     edx,$02           ; compensate quotient
; use this code to check rcp32 over
        call    check
        jne     mail_edemko@rambler.ru_about_rounding_error
        invoke  MessageBoxA,0,'rcp32 returned ok',0,0
        invoke  ExitProcess,0
mail_edemko@rambler.ru_about_rounding_error:
        hlt
check:  mov     esi,$0000'0007
        or      ecx,-1
  .loop:xor     edx,edx
        mov     eax,ecx
        div     esi
        mov     ebx,eax
        mov     eax,$9249'2493
        mul     ecx
        shr     edx,$02
        cmp     edx,ebx
        loope   .loop
        ret

;   divisor[$1f..$00] = $0000'0008
; 1/divisor[$1f..$00] = $0.2000'0000'0000'0000(0.125'000'000'000'000'000)
code:   shr     eax,$03           ; divisor is this power of two

;   divisor[$1f..$00] = $0000'0009
; 1/divisor[$1f..$00] = $0.1C71'C71C'71C7'1C71(0.111'111'111'111'111'111)
code:   mov     edx,$E38E'38E4    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$03), and rounded
        mul     edx               ; id est div :)
        shr     edx,$03           ; compensate quotient
; use this code to check rcp32 over
        call    check
        jne     mail_edemko@rambler.ru_about_rounding_error
        invoke  MessageBoxA,0,'rcp32 returned ok',0,0
        invoke  ExitProcess,0
mail_edemko@rambler.ru_about_rounding_error:
        hlt
check:  mov     esi,$0000'0009
        or      ecx,-1
  .loop:xor     edx,edx
        mov     eax,ecx
        div     esi
        mov     ebx,eax
        mov     eax,$E38E'38E4
        mul     ecx
        shr     edx,$03
        cmp     edx,ebx
        loope   .loop
        ret

;   divisor[$1f..$00] = $0000'000A
; 1/divisor[$1f..$00] = $0.1999'9999'9999'9999(0.099'999'999'999'999'999)
code:   mov     edx,$CCCC'CCCD    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$03), and rounded
        mul     edx               ; id est div :)
        shr     edx,$03           ; compensate quotient
; use this code to check rcp32 over
        call    check
        jne     mail_edemko@rambler.ru_about_rounding_error
        invoke  MessageBoxA,0,'rcp32 returned ok',0,0
        invoke  ExitProcess,0
mail_edemko@rambler.ru_about_rounding_error:
        hlt
check:  mov     esi,$0000'000A
        or      ecx,-1
  .loop:xor     edx,edx
        mov     eax,ecx
        div     esi
        mov     ebx,eax
        mov     eax,$CCCC'CCCD
        mul     ecx
        shr     edx,$03
        cmp     edx,ebx
        loope   .loop
        ret

;   divisor[$1f..$00] = $0000'000B
; 1/divisor[$1f..$00] = $0.1745'D174'5D17'45D1(0.090'909'090'909'090'909)
code:   mov     edx,$BA2E'8BA3    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$03), and rounded
        mul     edx               ; id est div :)
        shr     edx,$03           ; compensate quotient
; use this code to check rcp32 over
        call    check
        jne     mail_edemko@rambler.ru_about_rounding_error
        invoke  MessageBoxA,0,'rcp32 returned ok',0,0
        invoke  ExitProcess,0
mail_edemko@rambler.ru_about_rounding_error:
        hlt
check:  mov     esi,$0000'000B
        or      ecx,-1
  .loop:xor     edx,edx
        mov     eax,ecx
        div     esi
        mov     ebx,eax
        mov     eax,$BA2E'8BA3
        mul     ecx
        shr     edx,$03
        cmp     edx,ebx
        loope   .loop
        ret

;   divisor[$1f..$00] = $0000'000C
; 1/divisor[$1f..$00] = $0.1555'5555'5555'5555(0.083'333'333'333'333'333)
code:   mov     edx,$AAAA'AAAB    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$03), and rounded
        mul     edx               ; id est div :)
        shr     edx,$03           ; compensate quotient
; use this code to check rcp32 over
        call    check
        jne     mail_edemko@rambler.ru_about_rounding_error
        invoke  MessageBoxA,0,'rcp32 returned ok',0,0
        invoke  ExitProcess,0
mail_edemko@rambler.ru_about_rounding_error:
        hlt
check:  mov     esi,$0000'000C
        or      ecx,-1
  .loop:xor     edx,edx
        mov     eax,ecx
        div     esi
        mov     ebx,eax
        mov     eax,$AAAA'AAAB
        mul     ecx
        shr     edx,$03
        cmp     edx,ebx
        loope   .loop
        ret

;   divisor[$1f..$00] = $0000'000D
; 1/divisor[$1f..$00] = $0.13B1'3B13'B13B'13B1(0.076'923'076'923'076'923)
code:   mov     edx,$9D89'D89E    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$03), and rounded
        mul     edx               ; id est div :)
        shr     edx,$03           ; compensate quotient
; use this code to check rcp32 over
        call    check
        jne     mail_edemko@rambler.ru_about_rounding_error
        invoke  MessageBoxA,0,'rcp32 returned ok',0,0
        invoke  ExitProcess,0
mail_edemko@rambler.ru_about_rounding_error:
        hlt
check:  mov     esi,$0000'000D
        or      ecx,-1
  .loop:xor     edx,edx
        mov     eax,ecx
        div     esi
        mov     ebx,eax
        mov     eax,$9D89'D89E
        mul     ecx
        shr     edx,$03
        cmp     edx,ebx
        loope   .loop
        ret

;   divisor[$1f..$00] = $0000'000E
; 1/divisor[$1f..$00] = $0.1249'2492'4924'9249(0.071'428'571'428'571'428)
code:   mov     edx,$9249'2493    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$03), and rounded
        mul     edx               ; id est div :)
        shr     edx,$03           ; compensate quotient
; use this code to check rcp32 over
        call    check
        jne     mail_edemko@rambler.ru_about_rounding_error
        invoke  MessageBoxA,0,'rcp32 returned ok',0,0
        invoke  ExitProcess,0
mail_edemko@rambler.ru_about_rounding_error:
        hlt
check:  mov     esi,$0000'000E
        or      ecx,-1
  .loop:xor     edx,edx
        mov     eax,ecx
        div     esi
        mov     ebx,eax
        mov     eax,$9249'2493
        mul     ecx
        shr     edx,$03
        cmp     edx,ebx
        loope   .loop
        ret

;   divisor[$1f..$00] = $0000'000F
; 1/divisor[$1f..$00] = $0.1111'1111'1111'1111(0.066'666'666'666'666'666)
code:   mov     edx,$8888'8889    ; 1/divisor[$1f..$00], converted to 32 bits(shr $20-$03), and rounded
        mul     edx               ; id est div :)
        shr     edx,$03           ; compensate quotient
; use this code to check rcp32 over
        call    check
        jne     mail_edemko@rambler.ru_about_rounding_error
        invoke  MessageBoxA,0,'rcp32 returned ok',0,0
        invoke  ExitProcess,0
mail_edemko@rambler.ru_about_rounding_error:
        hlt
check:  mov     esi,$0000'000F
        or      ecx,-1
  .loop:xor     edx,edx
        mov     eax,ecx
        div     esi
        mov     ebx,eax
        mov     eax,$8888'8889
        mul     ecx
        shr     edx,$03
        cmp     edx,ebx
        loope   .loop
        ret

;   divisor[$1f..$00] = $0000'0010
; 1/divisor[$1f..$00] = $0.1000'0000'0000'0000(0.062'500'000'000'000'000)
code:   shr     eax,$04           ; divisor is this power of two
    
Post 01 Feb 2011, 10:59
View user's profile Send private message Reply with quote
idle



Joined: 06 Jan 2011
Posts: 359
Location: Ukraine
idle
Code:
2011_??_??




english
~~~~~~~
This file tells how to divide 1 by integer.
1/0 & 1/1 are easy.




First we should understand 1/123(e.g.) in decimal to use the principle in binary then.
  Imagine amount of liquid(e.g. juice).
  Imagine a vessel of 123 capacity(e.g. a glass).

  Our task is to fill the vessel with liquid as many times as possible until liquid ends.
  In other words, you drink juice *glass after a glass* until the juice is drunk.
  In other words, *each glass* glass count increases, juice decreases.
  In other words, *each division* quotient increases, dividend decreases.

  1 is a unit, consisting of smaller ones: mili- micro- nano- etc-.
  This is scaling, and we are just storing quotient of mili- micro- nano- etc- size.

  Ok, let us drink that juice Smile
             quotient
  -------------------
  0'001/123  _       <- ones
  0'010/123  0._     <- tenths
  0'100/123  0.0_    <- hundredths
  -------------------
  1'000/123  0.00_   <- see, we are dividing mili-ones
 -0'123      0.001
 =0'877      
 -0'123      0.002
 =0'754
 -0'123      0.003
 =0'631
 -0'123      0.004
 =0'508
 -0'123      0.005
 =0'385
 -0'123      0.006
 =0'262
 -0'123      0.007
 =0'139
 -0'123      0.008
 =0'016
  -------------------
  0'160/123  0.008_  <- hundredths
 -0'123      0.0081
 =0'037
  -------------------
  0'370/123  0.0081_ <- hundredths
 -0'123      0.00811
 =0'247
 -0'123      0.00812
 =0'124
 -0'123      0.00813
 =0'001
  -------------------
  ...               _
  -------------------




Binary 1/123.
  It is obvious to get 0..9 in decimal quotient.
  Hence binary quotient consists of 0..1 only(we either drink the juice or not Smile.

  Binary juice drunk Smile
           quotient
  -----------------
  001/123  _b
  002/123  0._b
  004/123  0.0_b
  008/123  0.00_b
  016/123  0.000_b
  032/123  0.0000_b
  064/123  0.00000_b
  -----------------
  128/123  0.000000_b
 -123      0.0000001b
 =005
  -----------------
  010/123  0.0000001_b
  020/123  0.00000010_b
  040/123  0.000000100_b
  080/123  0.0000001000_b
  -----------------
  160/123  0.00000010000_b
 -123      0.000000100001b
 =037
  -----------------
  074/123  0.000000100001_b
  -----------------
  148/123  0.0000001000010_b
 -123      0.00000010000101b
 =025
  -----------------
  ...                      _b
  -----------------

  0.00000010000101b = 2^-07 + 2^-12 + 2^-14
                    = 1.0000101b * 2^-07
                    = 10000101.b * (2^-07 * 2^-07 = 2^-14)
                    = 133 * 2^-14
                    = 133 shr 14




How many leading zeros may binary quotient contain?
  (BSR dividend)[+1] the answer is.
  Really, to divide by $00ff, 1 grows  8 times into $00100
                       $ffff, 1 grows 16 times into $10000
                       $1234, 1 grows 13 times into $02000
          ...and only then division(subtraction) starts.
  [+1] is not required if initial divisor is the power of two:
          to divide by $0004, 1 grows          into $00004




Procedure which returns 1/integer.
        ...
        mov     eax,10
        call    dword_rcp
        ...
        ;edx   = quotient of a .1...xxx form
        ;ecx   = number of consecutive zeros AFTER 0.
        ;ebx   = ?
        ;eax   = old eax = divisor
        ;flags = ?
dword_rcp:
  divisor  equ eax
  dividend equ ebx
  leading  equ ecx
  quotient equ edx

        mov     dividend,1
        sub     leading,leading
        sub     quotient,quotient
  .drink_juice:
        inc     leading
        shl     dividend,1        ;=dividend+dividend = dividend*2
        jc      .1
        cmp     divisor,dividend
        ja      .0                ;divisor denotes units of division
  .1:   sub     dividend,divisor  ;drink a glass of juice
        stc
  .0:   rcl     quotient,1        ;inserts either 0 or 1
        jno     .drink_juice      ;the most significant bit not 1
        sub     leading,32        ;number of consecutive zeros AFTER 0.
        ret

  restore divisor,dividend,leading,quotient




Usage sample.
        ...
        mov     eax,$CCCC'CCCD   ;rounded 0.1
        mov     edx,65'535       ;arbitrary divisor
        mul     edx              ;0.1 * divisor
        shr     edx,3            ;shr edx:eax,32+3
                                 ;edx = 6'553
        ...
    
Razz
Post 01 Oct 2011, 09:08
View user's profile Send private message Reply with quote
idle



Joined: 06 Jan 2011
Posts: 359
Location: Ukraine
idle
i misused the two terms
i beg your pardon if it happens again
(BSR divisor)[+1] the answer is.
mov edx,65'535 ;arbitrary dividend
mul edx ;0.1 * dividend

english & slavic(ukrainian)
Post 03 Oct 2011, 18:35
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2020, Tomasz Grysztar. Also on YouTube, Twitter.

Website powered by rwasa.