public class Example {
  
  /**
   * Precondition: A is a (non-decreasing) sorted array of length at least 1, x is an integer
   * Postcondition: Return an integer t such that A[t] == x, or
   *                else return A.length if no such t exists.
   */
  public static int binSearch(int[] A, int x) {
    int f = 0, l = A.length-1, m = 0;
    while (f != l) {
      m = (f + l) / 2;
      if (A[m] >= x) {
        l = m;
      }
      else {
        f = m + 1;
      }
    }
    if (A[f] == x) {
      return f;
    }
    else {
      return A.length; // semaphore
    }
  }
  
  /**
   * Precondition: m is a natural number, n is an integer
   * Postcondition: Return m*n
   */
  public static int mult(int m, int n) {
    int x = m, y = n, z = 0;
    
    while (x != 0) {
      if (x % 2 == 1) {
        z += y;
      }
      x = (int)Math.floor(x / 2.0); // /= 2; // right shift
      y *= 2; // left shift
    }
    
    return z;
  }
  
  /**
   * Precondition: 0 <= f <= l <= A.length - 1 and A[f..l] is sorted
   * Postcondition: return t such that f <= t <= l and A[t]==x, if such
   *                  t exists, otherwise return A.length
   */
  public static int recBinSearch(int[] A, int f, int l, int x) {
    if (f == l) {
      if (A[f] == x) {
        return f;
      }
      else {
        return A.length;
      }
    }
    else { // f != l
      int m = (f + l) / 2;
      if (A[m] >= x) {
        return recBinSearch(A, f, m, x);
      }
      else { // A[m] < x
        return recBinSearch(A, m+1, l, x);
      }
    }
  }
  
  /**
   * Preconditions: 0 <= f <= l <= A.length - 1, and
   *                A[f..m] and A[m+1,l] are sorted
   * Postcondition: A[f..l] has the same elements as before invocation; and
   *                  all other elements of A are the same.
   */
  
  public static void merge(int[] A, int f, int m, int l) {
    int[] aux = new int[l+1]; // auxiliary array
    int i = f, j = m+1, k = f; // indices into A and aux
    
    // merge subarrays until one is exhausted
    while (i <= m && j <= l) {
      if (A[i] < A[j]) {
        aux[k] = A[i];
        i += 1;
      }
      else {
        aux[k] = A[j];
        j += 1;
      }
      k += 1;
    }
    
    // determine the bounds of the unexhausted array
    int high = 0, low = 0;
    if (i > m) {
      low = j;
      high = l;
    }
    else {
      low = i;
      high = m;
    }
    
    // copy the remainder of the unexhausted array
    for (int t = low; t <= high; t++) {
      aux[k] = A[t];
      k += 1;
    }
    
    // copy aux to A[f..l]
    for (int t = f; t <= l; t++) {
      A[t] = aux[t];
    }
  }
  

  /**
   * Precondition: 0 <= f <= l <= A.length - 1
   * Postcondition: A[f..l] has the same elements as before, in sorted order,
   *                  and all other elements of A are unchanged.
   */
  public static void mergeSort(int[] A, int f, int l) {
    if (f == l) {
      return; // all done
    }
    else {
      int m = (f + l) / 2;
      mergeSort(A, f, m); // sort from f to m
      mergeSort(A, m+1, l); // sort from m+1 to l
      merge(A, f, m, l); // merge sorted sub-arrays
    }
  }
}