Loops that Search


Loops that search

Some loops are used to look for something. For example, suppose that you have an integer n and you want to find the first prime number that is larger than n. The idea is to start at n + 1, and to count upwards. We use variable k to do that. As soon as a value of k is found that is prime, we stop. We assume that function isPrime(k) is available.

  Define
    nextPrime(n: Integer) : Integer by

    nextPrime(n) = k |
      Let k = n + 1.
      While not(isPrime(k)) do
        Relet k = k + 1.
      %While
  %Define
The big difference between a search loop and an accumulation loop is that an accumulation loop has to look at all values in a given range, but a search loop can stop as soon as it finds what it is looking for, so sometimes it ends very early.


Case study: Check whether a number is prime

We have used function isPrime(n). Let's define it, using a loop. Integer n is prime if n > 1 and n does not have any factors except 1 and n.

The idea is to search for a factor of n in the list of numbers 2, 3, 4, ..., n-1. We need one variable (say, k) to count from 2 to n-1. As soon as a factor is found, we know that n is not prime.

This time there is a twist. If n is prime, then we will not find a factor. Search loops usually need to decide what to do when the value being sought is not found. In this case, it is just a matter of saying that n is prime.

  Define 
    isPrime(n: Integer): Boolean by

    isPrime(n) = r |
      Let k = 2.
      While k < n and n `mod` k =/= 0 do
        Relet k = k + 1.
      %While

      Let r = false.
      If k == n then
        Relet r = true.
      %If
  %Define

When the loop is done, k will be n if no factor was found. It is tempting to write, at that point,

    If k == n then
      Let r = true.
    else
      Let r = false.
    %If

But that introduces a problem of context. Recall that variables that are created inside an If-statement can only be used in that same If-statement. Since r is created inside the If-statement, it is only available inside the If-statement. You can fix that by writing open in front of the If-statement. So it would work to write

    open If k == n then
      Let r = true.
    else
      Let r = false.
    %If

An even simpler way to do that would be just to write

    Let r = k == n.
Then r is true if k == n is true, and r is false if k == n is false. So a shortened definition of function isPrime is as follows.

  Define 
    isPrime(n: Integer): Boolean by

    isPrime(n) = r |
      Let k = 2.
      While k < n and n `mod` k =/= 0 do
        Relet k = k + 1.
      %While
      Let r = k == n.
  %Define

Problems

  1. [solve] Using a loop, define function any7s(n), which takes an integer n and returns true if the usual (base 10) representation of n contains a 7. For example, any7s(274) = true, but any7s(99) = false. Write Define ... %Define around your definition.

    (Hint. Successively divide the number by 10. You are searching for a number whose rightmost digit is a 7. The search is exhausted when the number is 0. For example, when n is 3791, you look at 3791, 379, 37, and stop, because the rightmost digit of 37 is 7. When n is 999, you look at 999, 99, 9, 0, and stop because the search has reached 0. So only keep searching when you current number is not 0 and does not have rightmost digit 7.)

  2. [solve] Using a loop, define a function anyRs(s) that yields true if string s contains the character 'R'. For example, anyRs("MyRabbit") = true, but anyRs("myrabbit") = false. Write Define ... %Define around the definition.

    Be careful writing conditions. Do not try to compute s_k when k > length(s), since that will cause an error. Remember the short-circuiting property of the and and or operators.


Summary

A search loop stops as soon as it encounters what it is looking for.