function complexEigs (arr, N, prec, type, findVectors = true) {
    // TODO check if any row/col are zero except the diagonal

    // make sure corresponding rows and columns have similar magnitude
    // important because of numerical stability
    // MODIFIES arr by side effect!
    const R = balance(arr, N, prec, type, findVectors)

    // R is the row transformation matrix
    // arr = A' = R A R^-1, A is the original matrix
    // (if findVectors is false, R is undefined)
    // (And so to return to original matrix: A = R^-1 arr R)

    // TODO if magnitudes of elements vary over many orders,
    // move greatest elements to the top left corner

    // using similarity transformations, reduce the matrix
    // to Hessenberg form (upper triangular plus one subdiagonal row)
    // updates the transformation matrix R with new row operationsq
    // MODIFIES arr by side effect!
    reduceToHessenberg(arr, N, prec, type, findVectors, R)
    // still true that original A = R^-1 arr R)

    // find eigenvalues
    const { values, C } = iterateUntilTriangular(arr, N, prec, type, findVectors)

    // values is the list of eigenvalues, C is the column
    // transformation matrix that transforms arr, the hessenberg
    // matrix, to upper triangular
    // (So U = C^-1 arr C and the relationship between current arr
    // and original A is unchanged.)

    if (findVectors) {
      const eigenvectors = findEigenvectors(arr, N, C, R, values, prec, type)
      return { values, eigenvectors }
    }

    return { values }
  }
@param {number[][]} arr the matrix to find eigenvalues of
@param {number} N size of the matrix
@param {number|BigNumber} prec precision, anything lower will be considered zero
@param {'number'|'BigNumber'|'Complex'} type
@param {boolean} findVectors should we find eigenvectors?

@returns {{ values: number[], vectors: number[][] }}