Page 1 of 1

Fast integer Square Root, Cubic Root, Exponentiation

Posted: Fri Dec 30, 2016 5:14 pm
by Keya
just a few fast integer routines for when the slower accuracy of floats isn't required :) (wasn't sure if i should post this in Feature Requests or Tips n Tricks!)
from the fascinating bithacks book Hackers Delight i've no doubt several ppl here also already have :)

Code: Select all

EnableExplicit

Procedure ISqr(x) ;Square Root
  Protected m,b,y,t
  m = $40000000
  While m
    b = y | m
    y >> 1
    t = (x | ~(x - b)) >> 31
    x = x - (b & t)
    y = y | (m & t)
    m = m >> 2
  Wend
  ProcedureReturn y
EndProcedure

Procedure IExp(x,n) ;Exponentiation
  Protected p=x,y=1
  Repeat
    If (n & 1): y = p * y: EndIf
    n>>1
    If Not n: ProcedureReturn y: EndIf
    p*p
  ForEver   
EndProcedure

Procedure ICbRt(x) ;Cubic Root
  Protected s,y,b
  For s = 30 To 0 Step -3
    y*2
    b = (3*y*(y+1)+1) << s
    If x => b
      x-b
      y+1
    EndIf
  Next s
  ProcedureReturn y
EndProcedure

Re: Fast integer Square Root, Cubic Root, Exponentiation

Posted: Fri Dec 30, 2016 6:47 pm
by wilbert
Nice routines :)
When I timed the ISqr however, it was much slower compared to the PB Sqr procedure. :?

Re: Fast integer Square Root, Cubic Root, Exponentiation

Posted: Fri Dec 30, 2016 7:14 pm
by Keya
haaah, here's why - PB floating-point Sqr is only three beautiful little lines :)

Code: Select all

fld dword [in]
fsqrt
fistp dword [out]
but there is no fcbrt so the post remains valid, lol

Re: Fast integer Square Root, Cubic Root, Exponentiation

Posted: Fri Dec 30, 2016 9:03 pm
by wilbert
Keya wrote:but there is no fcbrt so the post remains valid, lol
That's true :D
It's a nice routine with little variables.
Perfect candidate to convert to asm :wink:

Re: Fast integer Square Root, Cubic Root, Exponentiation

Posted: Fri Dec 30, 2016 10:28 pm
by davido
@Keya,

Is the Cube Root routine correct?
I carried out the simple test using the code below:

Code: Select all

EnableExplicit

Global M.i, C.i

Procedure ISqr(x) ;Square Root
  Protected m,b,y,t
  m = $40000000
  While m
    b = y | m
    y >> 1
    t = (x | ~(x - b)) >> 31
    x = x - (b & t)
    y = y | (m & t)
    m = m >> 2
  Wend
  ProcedureReturn y
EndProcedure

Procedure IExp(x,n) ;Exponentiation
  Protected p=x,y=1
  Repeat
    If (n & 1): y = p * y: EndIf
    n>>1
    If Not n: ProcedureReturn y: EndIf
    p*p
  ForEver   
EndProcedure

Procedure ICbRt(x) ;Cubic Root
  Protected s,y,b
  For s = 30 To 0 Step -3
    y*2
    b = (2*y*(y+1)+1) << s
    If x => b
      x-b
      y+1
    EndIf
  Next s
  ProcedureReturn y
EndProcedure


For M = 3 To 100 Step 7
  C = M * M * M
  Debug Str(M) + " --> " + Str(ICbRt(C))
Next M

Re: Fast integer Square Root, Cubic Root, Exponentiation

Posted: Fri Dec 30, 2016 10:47 pm
by Keya
davido good catch :) a *2 had to be a *3 (fixed), the *2 immediately above it threw me off :P
here's the original from the book: http://www.hackersdelight.org/hdcodetxt/icbrt.c.txt

Code: Select all

int icbrt1(unsigned x) {
   int s;
   unsigned y, b;
   y = 0;
   for (s = 30; s >= 0; s = s - 3) {
      y = 2*y;
      b = (3*y*(y + 1) + 1) << s;
      if (x >= b) {
         x = x - b;
         y = y + 1;
      }
   }
   return y;
}

Re: Fast integer Square Root, Cubic Root, Exponentiation

Posted: Sat Dec 31, 2016 7:34 am
by wilbert
Just for fun the ICbRt converted to asm.
It really isn't required since the PB code itself already is very fast but is shows how convenient the LEA instruction can be. :wink:

Code: Select all

Procedure ICbRt(x.l)
  !mov edx, [p.v_x]     ; edx = x
  !xor eax, eax         ; eax = y
  !mov ecx, 30          ; ecx = s
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    !push ebx
  CompilerElse
    !push rbx
  CompilerEndIf  
  !.loop:
  !shl eax, 1           ; y = 2*y
  !lea ebx, [eax + 1]   ; b = y + 1
  !imul ebx, eax        ; b = y*b
  !lea ebx, [3*ebx + 1] ; b = 3*b + 1
  !shl ebx, cl          ; b = b << s
  !cmp edx, ebx         
  !jb .cont
  !sub edx, ebx         ; x = x - b
  !add eax, 1           ; y = y + 1
  !.cont:
  !sub ecx, 3
  !jnc .loop
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    !pop ebx
  CompilerElse
    !pop rbx
  CompilerEndIf    
  ProcedureReturn
EndProcedure

Re: Fast integer Square Root, Cubic Root, Exponentiation

Posted: Sat Dec 31, 2016 11:13 am
by Keya
sweet!
wilbert wrote:

Code: Select all

  !lea ebx, [3*ebx + 1]    ; b = 3*b + 1
It's these 3-for-the-price-of-1 meal deals i really want to add as a regular part to my game next, but it's still not coming to mind as naturally as i'd hope :) getting there though, especially thanks to examples like these! anyway brb, still using imul lol
Have yourself a great NYE wilbert! :)