protected void updateA( int w )
    {
        // much of the code below is equivalent to the rank1Update function
        // however, since &tau; has already been computed there is no need to
        // recompute it, saving a few multiplication operations
//        for( int i = w+1; i < numCols; i++ ) {
//            double val = 0;
//
//            for( int k = w; k < numRows; k++ ) {
//                val += u[k]*dataQR[k*numCols +i];
//            }
//            v[i] = gamma*val;
//        }

        // This is functionally the same as the above code but the order has been changed
        // to avoid jumping the cpu cache
        for( int i = w+1; i < numCols; i++ ) {
            v[i] = u[w]*dataQR[w*numCols +i];
        }

        for( int k = w+1; k < numRows; k++ ) {
            int indexQR = k*numCols+w+1;
            for( int i = w+1; i < numCols; i++ ) {
//                v[i] += u[k]*dataQR[k*numCols +i];
                v[i] += u[k]*dataQR[indexQR++];
            }
        }

        for( int i = w+1; i < numCols; i++ ) {
            v[i] *= gamma;
        }

        // end of reordered code

        for( int i = w; i < numRows; i++ ) {
            double valU = u[i];

            int indexQR = i*numCols+w+1;
            for( int j = w+1; j < numCols; j++ ) {
//                dataQR[i*numCols+j] -= valU*v[j];
                dataQR[indexQR++] -= valU*v[j];
            }
        }

        if( w < numCols ) {
            dataQR[w+w*numCols] = -tau;
        }

        // save the Q matrix in the lower portion of QR
        for( int i = w+1; i < numRows; i++ ) {
            dataQR[w+i*numCols] = u[i];
        }
    }