public static void doubleCenterSymmetric(double[][] m) {
    final int size = m.length;
    // Storage for mean values - initially all 0.
    double[] means = new double[size];
    for(int x = 0; x < m.length; x++) {
      final double[] rowx = m[x];
      // We already added "x" values in previous iterations.
      // Fake-add 0: mean + (0 - mean) / (x + 1)
      double rmean = means[x] - means[x] / (x + 1);
      for(int y = x + 1; y < rowx.length; y++) {
        final double nv = rowx[y];
        final double dx = nv - rmean, dy = nv - means[y];
        // For x < y, this is the yth entry.
        rmean += dx / (y + 1);
        // For y > x, this is the xth entry
        means[y] += dy / (x + 1);
      }
      means[x] = rmean;
    }
    // Compute total mean by averaging column means.
    double mean = means[0];
    for(int x = 1; x < size; x++) {
      double dm = means[x] - mean;
      mean += dm / (x + 1);
    }
    // Row and column center; also make symmetric.
    for(int x = 0; x < size; x++) {
      m[x][x] = -2. * means[x] + mean;
      for(int y = x + 1; y < size; y++) {
        final double nv = m[x][y] - means[x] - means[y] + mean;
        m[x][y] = nv;
        m[y][x] = nv;
      }
    }
  }
public static void doubleCenterSymmetric ( double [ ] [ ] m ) { final int size = m . length ; double [ ] means = new double [ size ] ; for ( int x = 0 ; x < m . length ; x ++ ) { final double [ ] rowx = m [ x ] ; double rmean = means [ x ] - means [ x ] / ( x + 1 ) ; for ( int y = x + 1 ; y < rowx . length ; y ++ ) { final double nv = rowx [ y ] ; final double dx = nv - rmean , dy = nv - means [ y ] ; rmean += dx / ( y + 1 ) ; means [ y ] += dy / ( x + 1 ) ; } means [ x ] = rmean ; } double mean = means [ 0 ] ; for ( int x = 1 ; x < size ; x ++ ) { double dm = means [ x ] - mean ; mean += dm / ( x + 1 ) ; } for ( int x = 0 ; x < size ; x ++ ) { m [ x ] [ x ] = - 2. * means [ x ] + mean ; for ( int y = x + 1 ; y < size ; y ++ ) { final double nv = m [ x ] [ y ] - means [ x ] - means [ y ] + mean ; m [ x ] [ y ] = nv ; m [ y ] [ x ] = nv ; } } }
Double-center the given matrix (only upper triangle is used).

For improved numerical precision, we perform incremental updates to the
mean values, instead of computing a large sum and then performing division.

@param m Matrix to double-center.