2

hey how exactly can I find the square root of an integer using MIPS assembly?

Sly Cooper
  • 69
  • 1
  • 2
  • 7
  • 5
    Have you looked e.g. [here](http://en.wikipedia.org/wiki/Methods_of_computing_square_roots)? – Oliver Charlesworth Jul 25 '13 at 20:23
  • You can't in general find the square root exactly. – Kerrek SB Jul 25 '13 at 20:24
  • 1
    Are you asking if there's a square root instruction? There's not. You'll need to write a program. – Carl Norum Jul 25 '13 at 20:25
  • So all I would have to do is make an assembly function that gives the roots of the quadratic equation x^2 - S = 0, where S is the integer you want to find the square root of? But that would look complicated right with all the division and multiplication? plus the you have to take the square root of the discriminant too! – Sly Cooper Jul 25 '13 at 20:26
  • Yeah I did mean program, I need a general idea of how to write the program – Sly Cooper Jul 25 '13 at 20:26
  • I'm sure there is a library that exists that does it for you, and will probably be more efficient than whatever you come up with. This is not a trivial thing to do in assembly. – Mark Lakata Jul 25 '13 at 20:29
  • But I need to do it without importing anything. Plus im working on xspim and am a beginner at this – Sly Cooper Jul 25 '13 at 20:30
  • You didn't say whether you were looking for an integer result, but just that the operand is integer. Are you looking for an integer which, when squared, comes closest to your original integer? Or are you looking for a rational approximation to the square root of your number? – lurker Jul 25 '13 at 21:17

7 Answers7

9

We can use an algorithm like the one submitted for this question and adapt it as needed. Before getting into MIPS, lets look at an implementation in C:

//Function to compute sqroot(n)
int sqroot(int n) {
        int x = n;
        for (int i = 0; i < (n/2); i++)
             x = (x + n / x) / 2;

        return x;
}

The sqroot(n) function will compute and integer equivalent to the floor of the square root of n. So if you were to call sqroot(225) you would get 15 as expected, but sqroot(15) would return 3 instead of 3.87298.

From the C code, we can outline what the MIPS code will look like:

In calling function:
    Load the number to be squared into $a0
    jal root

root:
    Initialize $t0 = n, $t1 = i = 0, $t2 = x = n = $a0, $t3 = n/2

Loop:
    Divide n/x
    Add x to n/x
    Divide (x + n/x) by 2
    Check if $t1 < $t3
    If it is, branch back to loop
    Else, move x into return register $v0

Please Note:

  1. Be sure to Push and Pop the stack as needed. I left that out for simplicity.
  2. When dividing by a power of 2, you can use the srl instruction.
  3. For clarification and additional information on MIPS instructions, click here.
Community
  • 1
  • 1
5

I found Newton's method x = (x + n/x) / 2 unsatisfactory when operating with only integers, because the terminating condition is difficult to calculate accurately. n/2 is just a guess, and is almost always more iterations than necessary. Newton's method converges quadratically, and is not proportional to n, but rather sqrt(n). The other suggestion, "keep repeating until x stops changing" does not work either, because for non-perfect squares x will alternate between the floor and the ceiling of the root — because of integer mathematics the term n/x will alternate when x is slightly smaller or slightly larger than sqrt(n).


I took a digit-by-digit root calculation method from wikipedia, and created a MIPS version. It does not suffer from inefficiency (n/2) or ambiguity (floor(sqrt(n)) or ceil(sqrt(n))). Lookup table methods could return results more efficiently, but assuming a lookup table is unavailable, this is a good and reliable method.

First, I translated the C example to use only less-than (<) comparisons, because MIPS only provides a set-less-than slt comparison instruction.

int isqrt(int num) {
  int ret = 0;
  int bit = 1 << 30; // The second-to-top bit is set

  // "bit" starts at the highest power of four <= the argument.
  while (num < bit) {
    bit >>= 2;
  }

  while (bit != 0) {
    if (num < ret + bit) {
      ret >>= 1;
    } else {
      num -= ret + bit;
      ret = (ret >> 1) + bit;
    }
    bit >>= 2;
  }
  return ret;
}

Here is the resulting MIPS code:

isqrt:
  # v0 - return / root
  # t0 - bit
  # t1 - num
  # t2,t3 - temps
  move  $v0, $zero        # initalize return
  move  $t1, $a0          # move a0 to t1

  addi  $t0, $zero, 1
  sll   $t0, $t0, 30      # shift to second-to-top bit

isqrt_bit:
  slt   $t2, $t1, $t0     # num < bit
  beq   $t2, $zero, isqrt_loop

  srl   $t0, $t0, 2       # bit >> 2
  j     isqrt_bit

isqrt_loop:
  beq   $t0, $zero, isqrt_return

  add   $t3, $v0, $t0     # t3 = return + bit
  slt   $t2, $t1, $t3
  beq   $t2, $zero, isqrt_else

  srl   $v0, $v0, 1       # return >> 1
  j     isqrt_loop_end

isqrt_else:
  sub   $t1, $t1, $t3     # num -= return + bit
  srl   $v0, $v0, 1       # return >> 1
  add   $v0, $v0, $t0     # return + bit

isqrt_loop_end:
  srl   $t0, $t0, 2       # bit >> 2
  j     isqrt_loop

isqrt_return:
  jr  $ra

You call it like any other MIPS procedure:

addi  $a0, $zero, 15
jal   isqrt # v0 = result

This procedure always returns $v0 = floor(sqrt($a0)) for positive arguments.

Beware: the code enters an infinite loop for negative arguments. Sanitize your input before calling this procedure.

whitehat101
  • 2,262
  • 20
  • 18
3

It is not in MIPS, but assembly nonetheless. The basic algorithm I found was based on the fact that the first n odd numbers added together = n^2.

So if you take advantage of that by reversing the process and subtracting from the number you would like to take the square root of, you can loop through to get either the exact answer, or an approximation. I believe its the root + 1 for non-perfect squares.

The idea being that the number of times you loop through is n, which is your square root.

Hope this helps.

   mov eax, 9513135         ; eax = number to take square root of
    mov ebx, eax            ; make a copy of eax in ebx


    loopIt :
        sub ebx, count      ; count starts as 1, 3, 5, 7, 9
        inc count           ; count = even
        inc count           ; count = odd
        inc sqrt            ; gives sqrt value
        mov eax, sqrt
        cmp ebx, 0
        js timetoReturn     ; return value if signed num, aka goes over zero
        jnz loopIt


    timetoReturn :
        mov reg, eax            ; just outputting the value
okstory
  • 31
  • 4
1

You can try this algorithm, which gives the integer smaller than or equal to the square root of your number.

Suppose you want the square root of n. Then keep repeating the following calculations:

x = (x + n/x) / 2

Choose x = n to start and keep repeating until x stops changing.

Patrik
  • 2,591
  • 1
  • 18
  • 33
0

Here's a simple to understand algorithm for calculating the floor of the square root of a positive integer, in C:

int approx_sqrt(int x) {
    int result;
    for (int partialSum = 0, oddNum = 1; partialSum < x; partialSum += oddNum, oddNum +=2) result++;
    return result;
}

It relies on the same principle as okstory's answer, in a slightly different manner.

Theory: Progressively increasing odd numbers are added to a partialSum, as long as the partialSum is less than the operand. The result is equal to the number of odd numbers summed to produce the partialSum.

Alexander
  • 48,074
  • 8
  • 78
  • 121
0

You guys all wrong.

You can use sqrt.s or sqrt.d assembly code! ex) sqrt.s $f12, $f13

Don't waste your time to implementing those functions.

  • 2
    That's the floating-point square root instruction. This would be a valid answer if you include instructions to convert from integer to `double` and back, and say something about truncating vs. rounding to nearest in the conversion back to integer. In general, `float` can't exactly represent every 32-bit integer, so you may need `double` if numbers can be larger than 2^24. How slow is `sqrt.s` or `sqrt.d` on any real MIPS hardware vs. these integer loops? On modern x86, convert to FP and back for hardware sqrt is better than an integer loop for any but the simplest cases. – Peter Cordes May 20 '19 at 03:35
0

If you want to calculate the square root of an integer in mips you will first need to convert the integer to floating-point. Assuming the number you want to take square root of is stored in $t1 then its conversion to floating point will look like this

mtc1 $t1, $f1
cvt.s.w $f1, $f1

Now you can calculate the square root using sqrt.s function.

sqrt.s $f1,$f1

so now $f1 will hold the square root of integer that was stored in $t1