home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #1 / NN_1993_1.iso / spool / comp / graphics / 13452 < prev    next >
Encoding:
Internet Message Format  |  1993-01-06  |  5.3 KB

  1. Path: sparky!uunet!mcsun!sunic!dkuug!diku!torbenm
  2. From: torbenm@diku.dk (Torben AEgidius Mogensen)
  3. Newsgroups: comp.graphics
  4. Subject: Re: Fixed point sqrt anyone?
  5. Message-ID: <1993Jan6.110342.12779@odin.diku.dk>
  6. Date: 6 Jan 93 11:03:42 GMT
  7. References: <1idsq6INNced@flop.ENGR.ORST.EDU>
  8. Sender: torbenm@thor.diku.dk
  9. Organization: Department of Computer Science, U of Copenhagen
  10. Lines: 161
  11.  
  12. murrayk@prism.CS.ORST.EDU (the Dodger) writes:
  13.  
  14.  
  15. >Well? Does anyone know of a quick and dirty way to get a reasonably accurate
  16. >square root of a fixed point integer number? My numbers are stored in a 16.16
  17. >bit format. I've heard of a few ways, but I'm open for ideas. I just want to
  18. >keep on avoiding floating point for ethical reasons. 8^)
  19.  
  20. If you have room for a table with 2^16 32 bit words, you can get a
  21. good approximation using a table lookup, a division and a few simple
  22. operations.
  23.  
  24. Let your number be a+b, where a is the integer part and b the
  25. fractional part. You then want a square root of the form x+y, where
  26. (x+y)^2 = a+b. Now, (x+y)^2 = x^2+2xy+y^2. If we assume x^2=a, then
  27. 2xy+y^2=b. If we assume y^2 is very small, we can approximate by
  28. saying 2xy=b, so y=b/2/x. We can make a table for the square root of a
  29. (which is a 16 bit integer). Thus we can find x by a single table
  30. lookup. Finding y then requires a right-shift and a division. The
  31. approximate square root is the x+y.
  32.  
  33. Note that the assumption that y^2 is very small is only valid if a is
  34. large. If a is less than 2^8, you can shift the entire number 8 bits
  35. left, do the square root and then shift the result 4 bits right.
  36.  
  37. If you want a more exact solution, the code below should do. If you
  38. have to implement division by a shift-and-compare loop, the final code
  39. takes time comparable to about 2 divisions, depending on your
  40. processor. On the ARM, the time is about 1.7 divisions.
  41.  
  42. The description below is extracted from some earlier postings in
  43. comp.sys.acorn. Though the code is for ARM, it should be easy to
  44. modify to your favourite processor (if it is reasonably
  45. well-designed). The algorithm is for normalized numbers, but it should
  46. be relatively easy to modify to fixed point.
  47.  
  48. If your number is of the form a*2^n, where 0.5 <= a < 1.0 then do the
  49. following:
  50.  
  51.     sqrt(a*2^(2n)) = sqrt(a)*2^n
  52.     sqrt(a*2^(2n+1)) = sqrt(a/2)*2^(n+1)
  53.  
  54. This reduces the problem to finding a square root of a number a,
  55. 0.25 <= a < 1.0. This can be done by this method, which should have
  56. a cost comparable to 2 or 3 divisions.
  57.  
  58.     { 0.25 <= a < 1.0 }
  59.     x := 4*(a-0.25);
  60.     r := 1;
  61.     n := 1;
  62.     while (n<number-of-bits) and (a<>0) do begin
  63.       { invariant: r^2+x = 4^n*a, x<2*r+1 }
  64.       n := n+1;
  65.       t := 4*r+1;
  66.       x := 4*x;
  67.       r := 2*r;
  68.       if x >= t then begin
  69.         x := x-t;
  70.         r := r+1
  71.       end
  72.     end;
  73.     r := r/2^n;
  74.     { sqrt(a)-r < 2^-n }
  75.  
  76. Note that only addition, subtractions and multiplications by 2 or 4
  77. are used in each part of the loop. At the end a single n-bit shift is
  78. done. Note that r and t are integers, while x is a real.
  79.  
  80. The (a<>0) test allows you to exit the loop if an exact root is found,
  81. but it can be omitted without causing error (so the loop can be
  82. unwound).
  83.  
  84. We can reformulate the algorithm to keep x < 1.0 throughout the
  85. algorithm:
  86.  
  87.     { 0.25 <= a < 1.0 }
  88.     x := (a-0.25)/2;
  89.     r := 1;
  90.     for n := 2 to number-of-bits do begin
  91.       { invariant: r^2+2^n*x= 4^n*a, x<(2*r+1)*2^-n }
  92.       t := 4*r+1;
  93.       x := 2*x;
  94.       r := 2*r;
  95.       if x >= t/2^(n+1) then begin
  96.         x := x-t/2^(n+1);
  97.         r := r+1
  98.       end
  99.     end;
  100.     r := r/2^number-of-bits;
  101.     { sqrt(a)-r < 2^-number-of-bits }
  102.  
  103. We can actually get this better by avoiding the doubling of r in
  104. each iteration. This way r and t are no longer integers, but the code
  105. is better anyway: 
  106.  
  107.     { 0.25 <= a < 1.0 }
  108.     x := a-0.25;
  109.     r := 0.5;
  110.     for n := 2 to number-of-bits do begin
  111.       { invariant: r^2+x/2^(n-2) = a, x<r+2^-(n+1) }
  112.       t := r+2^-(n+1);
  113.       x := 2*x
  114.       if x >= t then begin
  115.         x := x-t;
  116.         r := r+2^-n
  117.       end
  118.     end;
  119.     { sqrt(a)-r < 2^-number-of-bits }
  120.  
  121. There are, however, still a small problem: x might be greater than 1
  122. after the doubling. We can solve this by delaying the doubling:
  123.  
  124.     { 0.25 <= a < 1.0 }
  125.     x := a-0.25;
  126.     r := 0.5;
  127.     for n := 2 to number-of-bits do begin
  128.       { invariant: r^2+x/2^(n-2) = a, x<r+2^-(n+1) }
  129.       t := r+2^-(n+1)
  130.       if x >= t/2 then begin
  131.         x := x-t/2;
  132.         r := r+2^-n
  133.       end;
  134.       x := 2*x
  135.     end;
  136.     { sqrt(a)-r < 2^-number-of-bits }
  137.  
  138. This is shown in ARM assembler below. The number of cycles required
  139. for a 32 bit square root are 154. Note the use of conditional moves
  140. and adds, which allows efficient unfolding of the loop. Note also the
  141. one-cycle shift-and-subtract operation.
  142.  
  143.     \ on entry Ra holds a
  144.     \ on exit Rr holds sqrt(a)
  145.     \ uses Rx and Rt (either can be equal to Ra)
  146.     SUB Rx,Ra,#2^30        \ x := a-0.25;
  147.     MOV Rr,#2^31        \ r := 0.5;
  148.  
  149.     ADD Rt,Rr,#2^29        \ t := r+2^-(n+1);
  150.     SUBS Rt,Rx,Rt,LSR #1    \ if x >= t/2 then begin
  151.     MOVHS Rx,Rt        \   x := x-t/2;
  152.     ADDHS Rr,Rr,#2^30    \   r := r+2^-n
  153.     MOV Rx,Rx,ASL #1    \ x := 2*x;
  154.  
  155.     ...
  156.  
  157.     ADD Rt,Rr,#2^0        \ t := r+2^-(n+1);
  158.     SUBS Rt,Rx,Rt,LSR #1    \ if x >= t/2 then begin
  159.     MOVHS Rx,Rt        \   x := x-t/2;
  160.     ADDHS Rr,Rr,#2^1    \   r := r+2^-n
  161.     MOV Rx,Rx,ASL #1    \ x := 2*x;
  162.  
  163.                 \ t := r+2^-(n+1); 
  164.                 \ { 2^-(n+1) is less than precision }
  165.     SUBS Rt,Rx,Rr,LSR #1    \ if x >= t/2 then begin
  166.                 \   x := x-t/2; { x not needed }
  167.     ADDHS Rr,Rr,#2^0    \   r := r+2^-n
  168.                 \ x := 2*x; { x not needed }
  169.     \ at exit: 0.5 <= Rr < 1.0 when considered as a mantissa
  170.  
  171.  
  172. Torben Mogensen (torbenm@diku.dk)
  173.