1

I use the EJML library in my project. I have written a method that calculates the variance of a SimpleMatrix row vector. At some point, I noticed that I get a variance > 0.0 when passing an equal-element vector to this method.

I wrote this to investigate further and was surprised to find that the last line prints false although no output was produced by the previous print.

// rowVec is a 1xn SimpleMatrix of equal double elements
double one = rowVec.get(0);
for (int i = 0; i < rowVec.getNumElements(); i++) {
    if (rowVec.get(i) - one != 0 || rowVec.get(i) != one) {
        System.out.println(rowVec.get(i)); // no output here
    }
}
// why false below???
System.out.println(one == (rowVec.elementSum() / rowVec.getNumElements()));
// why true below???
System.out.println(one*rowVec.getNumElements() < rowVec.elementSum());

Can somebody please explain why the mean value of an equal-element vector is greater than one of its elements?

Follow-up: Solved my problem with:

/**
 * Calculates the variance of the argument matrix rounding atoms to the 10th
 * significant figure.
 */
public static double variance(SimpleMatrix m) {
    Preconditions.checkArgument(m != null, "Matrix argument is null.");
    Preconditions.checkArgument(m.getNumElements() != 0, "Matrix argument empty.");
    if (m.getNumElements() == 1) return 0;

    double mean = m.elementSum() / m.getNumElements();
    double sqDiviations = 0;
    for (int i = 0; i < m.getNumElements(); i++) {
        sqDiviations += Math.pow(decimalRoundTo(mean - m.get(i), 10), 2);
    }
    return sqDiviations / m.getNumElements();
}

/** Rounds a double to the specified number of significant figures. */
public static double decimalRoundTo(double d, int significantFigures) {
    double correctionTerm = Math.pow(10, significantFigures);
    return Math.round(d * correctionTerm) / correctionTerm;
}
suxumuxu
  • 121
  • 1
  • 1
  • 10

1 Answers1

4

Floating-point arithmetic is inexact. When you add up n identical doubles, and divide the result by n, you don't always get the number you started with.

For example, the following:

double x = 0.1;
double y = x + x + x;
System.out.println(y / 3. - x);

prints

1.3877787807814457E-17

I highly recommend What Every Computer Scientist Should Know About Floating-Point Arithmetic.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • How should I work within, say, 5 significant digits in this case? – suxumuxu Mar 29 '13 at 10:52
  • @suxumuxu: That depends on the broader context in which you are performing the computations, so only you can answer that. – NPE Mar 29 '13 at 10:54
  • @suxumuxu Take the difference, do Math.abs on it to get a positive number and check whether it's smaller than some treshold, I think. – thejh Mar 29 '13 at 10:54
  • I guess I should have searched a bit more :] The answer seems a bit obvious now, making me feel sorry for taking 10 minutes of your time. Thanks. – suxumuxu Mar 29 '13 at 11:07