wu :: forums
« wu :: forums - Integer Square Root »

Welcome, Guest. Please Login or Register.
Jun 2nd, 2024, 10:59am

RIDDLES SITE WRITE MATH! Home Home Help Help Search Search Members Members Login Login Register Register
   wu :: forums
   riddles
   cs
(Moderators: ThudnBlunder, SMQ, william wu, Grimbal, towr, Eigenray, Icarus)
   Integer Square Root
« Previous topic | Next topic »
Pages: 1  Reply Reply Notify of replies Notify of replies Send Topic Send Topic Print Print
   Author  Topic: Integer Square Root  (Read 1998 times)
John_Gaughan
Uberpuzzler
*****



Behold, the power of cheese!

5187759 5187759   john23874   SnowmanJTG
WWW Email

Gender: male
Posts: 767
Integer Square Root  
« on: Apr 27th, 2004, 7:49pm »
Quote Quote Modify Modify

This is a problem that has a real application for a program I am writing. I have not been able to come up with a good solution yet.
 
Given a C++ class:
 
Code:
struct Point
{
  int x;
  int y;
  ...
 
  // Calculate the distance between *this point
  // and another one, discarding everything after
  // the decimal (i.e. floor)
  unsigned int distance (const Point &p) const
  {
    ...
  }
};

 
Space considerations aside (as long as they are not too bad), what is the fastest algorithm to calculate the distance between two Point objects? Keep in mind that coordinates are signed, distance is unsigned (think about it for a minute), and rounded down.
 
Standard sqrt() functions work on doubles, which is potentially less precise because of significant digits and floating point precision. This function needs to be precisely accurate in all cases.
 
So far I cannot think of anything that does not use log functions, which are probably not much faster than sqrt().
IP Logged

x = (0x2B | ~0x2B)
x == the_question
Barukh
Uberpuzzler
*****






   


Gender: male
Posts: 2276
Re: Integer Square Root  
« Reply #1 on: Apr 28th, 2004, 12:03am »
Quote Quote Modify Modify

John, are you assuming any constraints on the coordinates of the points?
 
If not, please note that the distance() ought to return long long, not unsigned int. This may affect the selection of the best algorithm.
IP Logged
towr
wu::riddles Moderator
Uberpuzzler
*****



Some people are average, some are just mean.

   


Gender: male
Posts: 13730
Re: Integer Square Root  
« Reply #2 on: Apr 28th, 2004, 1:29am »
Quote Quote Modify Modify

I'd say unsigned long long then..
 
You could do a binary search for the right number d
( d^2 = (x1-x2)^2+(y1-y2)^2 )
You should get the number in log2(d) steps
There are probably some ways to optimise it.
IP Logged

Wikipedia, Google, Mathworld, Integer sequence DB
John_Gaughan
Uberpuzzler
*****



Behold, the power of cheese!

5187759 5187759   john23874   SnowmanJTG
WWW Email

Gender: male
Posts: 767
Re: Integer Square Root  
« Reply #3 on: Apr 28th, 2004, 9:56am »
Quote Quote Modify Modify

Yes, you are right, I would need to go up to the next size. The real application uses 16 bit integers so I could go with an unsigned 32 bit integer for the distance. I was thinking of one dimension but in a plane the distance can be greater.
 
The binary search idea sounds good. This problem essentially is "how do I approximate an integral square root quickly." There are potentially hundreds of points that will need these calculations, and coupled with calculations for other data structures, I want to find a solution that may not be ideal but is good. I have not profiled the standard C sqrt() function yet, but just looking at the code, I can probably come up with something slightly faster given the constraints of the problem domain.
 
Most points will be relatively close to the origin (within 1,000 units), so I can most likely optimize it by separating the sample space into disjoint chunks and filtering [smiley=vartriangle.gif]x2 [smiley=vartriangle.gif]y2 into the proper one. Even if I separated it into 1024 unit wide partitions that would take at most 10 comparisons.
IP Logged

x = (0x2B | ~0x2B)
x == the_question
towr
wu::riddles Moderator
Uberpuzzler
*****



Some people are average, some are just mean.

   


Gender: male
Posts: 13730
Re: Integer Square Root  
« Reply #4 on: Apr 28th, 2004, 10:16am »
Quote Quote Modify Modify

Here's a solution with a part in assembly Tongue
http://www.programmersheaven.com/zone3/cat414/16549.htm
IP Logged

Wikipedia, Google, Mathworld, Integer sequence DB
towr
wu::riddles Moderator
Uberpuzzler
*****



Some people are average, some are just mean.

   


Gender: male
Posts: 13730
Re: Integer Square Root  
« Reply #5 on: Apr 28th, 2004, 10:47am »
Quote Quote Modify Modify

given d^2 = (x1-x2)^2+(y1-y2)^2  
You can get a first guess for d by finding the position of the most significant bit, if it's at position i, take a=2^(i/2)
(takes 5 or 6 steps, depending on wether you have 32 or 64 bits)
then iterate
a = a+(d^2-a*a)/(2a)
untill (a+1)^2 > d^2  >= a^2
It should converge faster than binary search..
« Last Edit: Apr 28th, 2004, 12:25pm by towr » IP Logged

Wikipedia, Google, Mathworld, Integer sequence DB
towr
wu::riddles Moderator
Uberpuzzler
*****



Some people are average, some are just mean.

   


Gender: male
Posts: 13730
Re: Integer Square Root  
« Reply #6 on: Apr 28th, 2004, 1:23pm »
Quote Quote Modify Modify

The following seems to work (I've had the computer test it for every integer up to 2^31-1)
 
Code:
int isqrt(int square)
{
  int a=square, c, m=16;
  if (a >> m) m+=8; else m-=8;
  if (a >> m) m+=4; else m-=4;
  if (a >> m) m+=2; else m-=2;
  if (a >> m) m+=2;
 
  a = 1 << (m/2);
 
  while(c = (square-a*a)/(2*a))
    a+=c;
 
  return a-1;
}
« Last Edit: Apr 28th, 2004, 1:29pm by towr » IP Logged

Wikipedia, Google, Mathworld, Integer sequence DB
John_Gaughan
Uberpuzzler
*****



Behold, the power of cheese!

5187759 5187759   john23874   SnowmanJTG
WWW Email

Gender: male
Posts: 767
Re: Integer Square Root  
« Reply #7 on: Apr 28th, 2004, 5:42pm »
Quote Quote Modify Modify

Thanks towr, that helps. Now I need to do some testing and integrate it into my class.
IP Logged

x = (0x2B | ~0x2B)
x == the_question
Barukh
Uberpuzzler
*****






   


Gender: male
Posts: 2276
Re: Integer Square Root  
« Reply #8 on: Apr 29th, 2004, 12:17am »
Quote Quote Modify Modify

I am totally confused…  Shocked It seems you are overcomplicating things, John. Here are my considerations:
 
1. If the coordinates are 16 bits, then double precision (53 bits) is more than enough. So, calculating the square of the distance, converting it to double, taking a square and converting it back to integer will do the work.
 
2. If the coordinates are 32 bits, then you may use long double precision (64 bits – but you need to check your compiler supports this level of accuracy) and use sqrtl() function that works on long doubles. Then, the result you get may differ from the true one by at most 1.
 
3. As for the speed, I compared the sqrt() implementation with the towr’s isqrt() implementation (which, by the way, I found very elegant), and got the following numbers (running 100,000,000 iterations on Pentium4 machine, gcc –O3 compilation):
 
sqrt() : 1.84 sec
isqrt():  28.59 sec
IP Logged
John_Gaughan
Uberpuzzler
*****



Behold, the power of cheese!

5187759 5187759   john23874   SnowmanJTG
WWW Email

Gender: male
Posts: 767
Re: Integer Square Root  
« Reply #9 on: Apr 29th, 2004, 6:05am »
Quote Quote Modify Modify

on Apr 29th, 2004, 12:17am, Barukh wrote:
1. If the coordinates are 16 bits, then double precision (53 bits) is more than enough. So, calculating the square of the distance, converting it to double, taking a square and converting it back to integer will do the work.

The exact size of the integers involved is not all that important. The types will be 16 bit integers, and I believe that all CPUs supporting MMX or SSE can use those registers for 64 bit integer arithmetic. That would be most CPUs in the last decade.
 
Quote:
2. If the coordinates are 32 bits, then you may use long double precision (64 bits – but you need to check your compiler supports this level of accuracy) and use sqrtl() function that works on long doubles. Then, the result you get may differ from the true one by at most 1.

Long double functions are non-standard and generally inefficient on older hardware. Not everyone has a Pentium 4, and my program needs to run well even on older hardware.
 
Quote:
3. As for the speed, I compared the sqrt() implementation with the towr’s isqrt() implementation (which, by the way, I found very elegant), and got the following numbers (running 100,000,000 iterations on Pentium4 machine, gcc –O3 compilation):
 
sqrt() : 1.84 sec
isqrt():  28.59 sec

I find this odd. I do not have the time now (or yesterday) to test it out myself. It may take some tweaking by hand. I will also use gcc (g++ actually) to compile, so the libc should be the same or close enough to it. I imagine sqrt() is not something that changes much anymore between libc versions. All I remember from looking at libc's implementation of sqrt() is that I could probably do it faster given the (integer) constraints of the problem domain.
 
The timing looks decent, given that I will probably only need to do 1,000 calculations at most. More are possible, but extremely rare.
 
The fact that you run that on a Pentium 4 may be a factor too. It has very good floating point arithmetic, better than its predecessors. Anyway, I need to do some testing this weekend when I have time and I will share what I come up with.
 
If nothing else, it was a good exercise in CS Smiley
IP Logged

x = (0x2B | ~0x2B)
x == the_question
towr
wu::riddles Moderator
Uberpuzzler
*****



Some people are average, some are just mean.

   


Gender: male
Posts: 13730
Re: Integer Square Root  
« Reply #10 on: Apr 29th, 2004, 8:23am »
Quote Quote Modify Modify

The time would probably improve by making some variables registers
And I think math.h's sqrt also uses assembly  
(at least if I'm interpreting http://www.physik.uni-bielefeld.de/~okacz/nlibc/math_8h.html#a35 right.)
IP Logged

Wikipedia, Google, Mathworld, Integer sequence DB
Grimbal
wu::riddles Moderator
Uberpuzzler
*****






   


Gender: male
Posts: 7527
Re: Integer Square Root  
« Reply #11 on: May 6th, 2004, 1:36pm »
Quote Quote Modify Modify

Here is an integer square root that should be fast without being too complicated.  Faster method would involve lookup tables.
 
unsigned usqrt32c(unsigned long n)
{
    int i;
    unsigned d = 1U<<15;
    unsigned long d2 = 1UL<<30;
    unsigned result;
    unsigned long result2, trial;
    
    result = 0;
    result2 = 0;
    
    for (i = 16; i != 0; i--) {
        trial = result2 + ((unsigned long)result<<i) + d2;
        if (trial <= n) {
            result += d;
            result2 = trial;
        }
        d >>= 1;
        d2 >>= 2;
    }
    return result;
}
« Last Edit: Jan 23rd, 2005, 3:48pm by Grimbal » IP Logged
ChipBizGuy
Guest

Email

Re: Integer Square Root  
« Reply #12 on: Jul 16th, 2004, 1:06pm »
Quote Quote Modify Modify Remove Remove

I don't know if you still care, but I believe there is a better solution than just coding isqrt because you have additional information.  Let Dx = abs(x1-x2) and Dy = abs(y1-y2).  The minimum possible distance is max(Dx, Dy).  Then maximum is Dx+Dy.  Use these as the bounds of the binary search.  This reduces complexity to log(min(Dx,Dy)) compares.
 
Mark
IP Logged
Pages: 1  Reply Reply Notify of replies Notify of replies Send Topic Send Topic Print Print

« Previous topic | Next topic »

Powered by YaBB 1 Gold - SP 1.4!
Forum software copyright © 2000-2004 Yet another Bulletin Board