Adventure Game Studio

AGS Support => Advanced Technical Forum => Topic started by: scotch on Wed 22/10/2003 22:05:58

Title: Square Root
Post by: scotch on Wed 22/10/2003 22:05:58
Edit by strazer:

AGS 2.7 Beta 8 introduced the Maths.Sqrt function.




In case anyone needs to find the square root of something or the distance between two points (how far apart two characters are, for instance) I thought I'd post these.

I needed to find the square root of something for a gui, and since ags doesn't have a sqrt() function, and there isn't a plugin for it I had to write one, so with the help of Annie, and Newton here it is
(along with abs() sqr() and point_distance() which I just find save time)


function abs(int number) { if(number<0) number=number*(-1); return number;}

function sqr(int number) {
  return (number*number);
  }

function sqrt(int number) {
  number=abs(number);
  if(number==0)number=1;
  int guess=Random(number)+1;
  int previousguess;
  int result= -1;
  int maxiterations=10;
  while(result!=previousguess && maxiterations>0) {
    result = (number/guess+guess)/2;
    previousguess=guess;
    guess=result;
    maxiterations--;
    }
return result;
    }


function point_distance(int x1,int y1,int x2,int y2) {
  return sqrt((sqr(x1-x2)+sqr(y1-y2)));
  }


I am terrible at maths.. so they may well be scripted extremely badly but they seem to work in my game.
Title: Re:Square Root
Post by: SSH on Thu 23/10/2003 14:22:48
Of course, you can just work with the squared numbers most of the time. Why bother finding the root? If you want to know if the distance is less than 46

if (srq(x1-x2)+sqr(y1+y2)  < srq(40)) ...

or comparing two calculated  distances, etc.

So make sure you're not slowing things down by making things too difficult for yourself!
Title: Re:Square Root
Post by: a-v-o on Sat 25/10/2003 02:09:08
In my test I realized that your algorithm can e.g. give 3 as sqrt (8), because 2 and 3 are alternating in result until maxiterations is zero.

Also sqrt(0) should be zero not one.

Instead of using a maximum number of iterations, the algorithm below stops when alternating values in result are detected.

function sqrt(int number)
{
 int result = 0;
 if(number > 0)
 {
   int previousguess = -1;
   int guess = -1;
   result = 1;
   while((result != previousguess) && (result != guess))
   {
     previousguess = guess;
     guess = result;
     result = (number / guess + guess) / 2;
   }
   if (guess < result) { result = guess; }
 }
 else if (number < 0)
 {
   result = -1; // error
 }
 return result;
}

Title: Re:Square Root
Post by: scotch on Sat 25/10/2003 02:47:44
Thanks a-v-o :)
Title: Re:Square Root
Post by: Kennedy on Sat 25/10/2003 07:08:45
If I recal there is an exact forula for determining square roots, but it involves using the natural log.
Title: Re:Square Root
Post by: OneThinkingGal and ._. on Sun 26/10/2003 17:48:28
Yes, but neither AGS nor the math plugin has any capability for log() functions. That's why I recommended Newton's method.  :)
Title: Re:Square Root
Post by: Gilbert on Mon 27/10/2003 03:14:40
And the lack of decimals.

Anyway, here is a way to do it without using iterations (so can be slow for LARGE numbers, but should work for most cases), it can return the square root rounded to the nearest integer (tested):

function sqrt(int num){
num=abs(num); //well you may use the same abs()
int i=0;
while (i*i<num) i++;
int temp = i*i-num;
if (temp){
 i--;
 temp = (num-(i*i))*4;
 if (temp>(4*i)+1)i++;
 }
return i;
}
Title: Re:Square Root
Post by: a-v-o on Mon 27/10/2003 16:19:38
Hey Gilbot,

Quote
int i=0;
while (i*i<num) i++;

This is really the easiest way to get the integer square root and I used it in the flashlight plugin to calculate the circle.

Strange that I haven't thought at it at my last post. ???
Title: Re:Square Root
Post by: Scorpiorus on Wed 29/10/2003 23:18:39
Just another modification of Newton's formula. Returns the rounded value. Good at large values where it takes about 3-4 iterations to calculate the root:

function abs(int a) { if (a<0) return -a; else return a; }
function mod(int a, int b) { return a - (b*(a/b)); }

function sqrt_fast(int L) {

 int temp, div, result = abs(L);

 if      (L <= 0) return 0;
 else if (L < 5       ) div = L;
 else if (L < 256     ) div = 7;
 else if (L < 65536   ) div = 63;
 else if (L < 16777216) div = 1023;
 else                   div = 16383;
 
 while (1) {
   temp = L/div + div;
   div = temp/2;
   div += temp & 1;
   if (result > div) result = div;
   else {
     if (L/result == result-1 && mod(L,result)==0) result--;
     return result;
   }
 
 }

}

~Cheers