Page 1 of 1

Optimizing Dividing by 2,4,16 etc ?

Posted: Sat Feb 23, 2008 6:18 pm
by Franky
Hi, I just played a little bit around with PB and found out, that PB optimizes

Code: Select all

  a=a*16
to

Code: Select all

   SAL dword[v_a],4

But it doesn´t do this with division:

Code: Select all

  a=a/16
Is translated to

Code: Select all

  MOV    ebx,dword [v_a]
  MOV    eax,ebx
  MOV    ebx,16
  CDQ
  IDIV   ebx
  MOV    ebx, eax
  MOV    dword [v_a],ebx

So,
1.) why first move the value of a t ebx and then move it from ebx to eax, why not directly to eax?
2.)Why not just use SAR instead of IDIV?

Posted: Sat Feb 23, 2008 6:23 pm
by Trond

Code: Select all

a = (-4) / 2
Debug a
a = (-4) >> 2
Debug a

Posted: Sat Feb 23, 2008 6:26 pm
by Franky

a = (-4) / 2
Debug a
a = (-4) >> 1
Debug a
;)

Posted: Sat Feb 23, 2008 6:26 pm
by Dare
Trond wrote:

Code: Select all

a = (-4) / 2
Debug a
a = (-4) >> 2
Debug a

Code: Select all

a = (-4) / 2
Debug a
a = (-4) >> 1
Debug a
:wink:

Posted: Sat Feb 23, 2008 6:42 pm
by Trond

Code: Select all

Debug -3 / 2 
Debug -3 >> 1
:twisted: :twisted:

Posted: Sat Feb 23, 2008 8:02 pm
by Dare
:D

Posted: Mon Mar 03, 2008 2:19 pm
by Franky
Noone makes me give up 8)

So, this is the new version, rounding the same way, as PureBasic does:


My Test brought an optimization from 25Seconds to 11 Seconds:

Code: Select all

#Compare=0

Global a,b,c.l,*adr1.long,*adr2.long,adr1.l,adr2.l
adr1=AllocateMemory(80000)
adr2=AllocateMemory(80000)

;Rechnung: c=a/8

Zeit=GetTickCount_()
   For b=1 To 99999
    CompilerIf #compare
     *adr1=adr1
    CompilerEndIf
     For a=-9999 To 9999
 !        MOV    eax,dword [v_a]
; !        MOV    ebx,dword [v_a]
 ;!        MOV    eax,ebx
 !        MOV    ebx,8
 !        CDQ
 !        IDIV   ebx
 ;!        MOV    ebx, eax
 ;!        MOV    dword [v_c],ebx
 !        MOV    dword [v_c],eax
     CompilerIf #Compare
       *adr1\l=c
       *adr1+4
     CompilerEndIf
   Next
 Next
zeit2=GetTickCount_()
   For b=1 To 99999
     CompilerIf #compare
      *adr2=adr2
     CompilerEndIf
;    CallDebugger
    For a=-9999 To 9999
!        MOV    ebx,dword [v_a]
!         SAR    ebx,3
!        MOV    dword [v_c],ebx
!         CMP    ebx,0
!         JNL l___div_end
!            SAL ebx,3
!           CMP dword[v_a],ebx
!            JE l___div_end
!               INC dword[v_c]
         __div_end:
     CompilerIf #compare
         *adr2\l=c
         *adr2+4
     CompilerEndIf
  Next
 Next
zeit3=GetTickCount_()
 
CompilerIf #compare
*adr1=adr1
*adr2=adr2
dif=0
For a=0 To 19998
     If *adr1\l<>*adr2\l
            INC dif
           Debug Str(a-9999)+"/8="+Str(*adr1\l)+"   SAR a,3="+Str(*adr2\l)+"  %8="+Str(a%8)
     EndIf 
     *adr1+4
     *adr2+4
Next 
CompilerEndIf 
MessageRequester("Ergebnis:","Freds Method: "+Str(zeit2-zeit)+"ms"+Chr(13)+"My Method: "+Str(zeit3-zeit2)+"ms"+Chr(13)+"Menge der Unterschiede: "+Str(dif))

Posted: Tue Mar 04, 2008 4:59 pm
by va!n
@Franky:
respect! *thumbs up*
i would like to see such speed optimisations directly done by the compiler... your code is surely a nice contribution to the pb team

Posted: Tue Mar 04, 2008 5:37 pm
by Psychophanta
...and what makes you think that SAR or SAL is more optimized instruction than IDIV, or DIV or IMUL or MUL :?:
Don't be so sure that it is faster in modern processors :!:

Posted: Tue Mar 04, 2008 6:07 pm
by hellhound66
Removed.