2
\$\begingroup\$

(See the previous iteration.)

Now all operations of the data structure work in exact constant time, yet it came with the price: the state of this set maybe non-sensical. A user may end up with the set with negative number of elements in it. Basically, the client programmer must keep track of how he/she work with this set.

StatisticsNumberSet.java

package net.coderodde.stat;

/**
 * This class provides the means for rapid statistics queries.
 * 
 * @author Rodion "rodde" Efremov
 * @version 1.618 (Mar 28, 2017)
 */
public class StatisticsNumberSet {

    /**
     * Holds the sum of all elements in this set.
     */
    private double sum;

    /**
     * Holds the sum of square of each element in this set.
     */
    private double squareSum;

    /**
     * Holds the number of elements currently in this set.
     */
    private int size;

    /**
     * Adds the given number to this set.
     * 
     * @param number the number to add.
     */
    public void add(double number) {
        checkNumberIsFinite(number);
        sum += number;
        squareSum += number * number;
        size++;
    }

    /**
     * Converts and adds the given number to this set.
     * 
     * @param number the number to add.
     */
    public void add(Number number) {
        add(number.doubleValue());
    }

    /**
     * Removes the given number from this set.
     * 
     * @param number the number to remove.
     */
    public void remove(double number) {
        checkNumberIsFinite(number);
        sum -= number;
        squareSum -= number * number;
        size--;
    }

    /**
     * Converts and removes the given number from this set.
     * 
     * @param number the number to remove.
     */
    public void remove(Number number) {
        remove(number.doubleValue());
    }

    /**
     * Resets the state of this set to an empty set.
     */
    public void clear() {
        sum = 0.0;
        squareSum = 0.0;
        size = 0;
    }

    /**
     * Returns the number of elements in this set.
     * 
     * @return the size of this set.
     */
    public int size() {
        return size;
    }

    /**
     * Computes the average of this set.
     * 
     * @return the average.
     */
    public double getAverage() {
        return sum / size;
    }

    /**
     * Computes the variance of this set.
     * 
     * @return the variance. 
     */
    public double getVariance() {
        double step1 = squareSum - sum * sum / size;
        return step1 / (size - 1);
    }

    /**
     * Computes the standard deviation of this set.
     * 
     * @return the standard deviation.
     */
    public strictfp double getStandardDeviation() {
        return Math.sqrt(getVariance());
    }

    /**
     * Returns the textual representation of the state of this set.
     * 
     * @return the textual representation.
     */
    @Override
    public String toString() {
        return "[Size = " + size + ", average = " + getAverage() +
               ", s.d. = " + getStandardDeviation() + ", variance = " + 
                getVariance() + "]";
    }

    public static void main(String[] args) {
        StatisticsNumberSet set = new StatisticsNumberSet();

        set.add(1);
        set.add(1.0f);
        set.add((byte) 3);

        System.out.println(set);

        set.remove(1.0f);

        System.out.println(set);

        set.clear();

        System.out.println(set);
    }

    private void checkNumberIsFinite(double number) {
        if (Double.isNaN(number)) {
            throw new IllegalArgumentException("number is NaN");
        }

        if (Double.isInfinite(number)) {
            throw new IllegalArgumentException("number is +Inf or -Inf");
        }
    }
}

As always, any critique is much appreciated.

\$\endgroup\$
1
\$\begingroup\$

This is not a Set. A Set contains no duplicate elements. You should rename the class, perhaps to a Bag or a MultiSet.

I'm also worried about this bit:

/**
 * Computes the variance of this set.
 * 
 * @return the variance. 
 */
public double getVariance() {
    double step1 = squareSum - sum * sum / size;
    return step1 / (size - 1);
}

/**
 * Computes the standard deviation of this set.
 * 
 * @return the standard deviation.
 */
public strictfp double getStandardDeviation() {
    return Math.sqrt(getVariance());
}

Either strictfp cascades, and you calculate the variance twice, but in different ways for toString(), or it doesn't, and in that case, no math is being done in this method and the keyword can go.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Oops, strictfp was not intended to make it to the post: JVM does not seem to throw exception whenever dividing by (double) zero, so I thought to try strictfp. \$\endgroup\$ – coderodde Mar 28 '17 at 15:32
  • \$\begingroup\$ @coderodde the not throwing exception part is part of the IEEE standard, I believe. \$\endgroup\$ – Pimgd Mar 28 '17 at 15:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.