/*
VisAD system for interactive analysis and visualization of numerical
data.  Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA

$Id: ArithProg.java,v 1.14 2009-03-02 23:35:48 curtis Exp $
*/

package visad.data.in;

import visad.VisADException;


/**
 * Provides support for determining if a sequence of numeric values corresponds
 * to an arithmetic progression and, if so, the progression parameters.
 *
 * @author Steven R. Emmerson
 */
public class ArithProg
{
    protected long		n;
    protected double		first = Double.NaN;
    protected double		last = Double.NaN;
    protected double            meanDel = Double.NaN;
    protected boolean		isConsistent = true;
    protected final double	fEps = 5e-5f;	// 5 * C FLT_EPS
    protected final double	dEps = 5e-9;	// 5 * C DBL_EPS
    private final double[]      dValues = new double[1];
    private final float[]       fValues = new float[1];

    /**
     * Accumulates a set of floats.  Indicates whether or not the sequence is
     * consistent with the arithmetic progression so far.
     *
     * @param values		The values to accumulate.
     * @return			False if the difference between any current
     *				and previous value normalized by the current
     *				increment differs from unity by more than the
     *				nearness threshold; otherwise, true.
     * @throws VisADException	{@link #isConsistent()} was false before this
     *				method was invoked.
     * @precondition		isConsistent() is true.
     * @postcondition		A subsequent getNumber() will return
     *				values.length more than previously
     *				if the function returns true.
     * @postcondition		A subsequent getLast() will return the
     *				value argument if the function returns true.
     */
    public synchronized boolean accumulate(float[] values)
	throws VisADException
    {
	if (!isConsistent())
	    throw new VisADException(
		getClass().getName() + ".accumulate(float[]): " +
		"Sequence isn't an arithmetic progression");
	for (int i = 0; i < values.length; i++)
	{
	    double value = values[i];
	    if (n == 0)
	    {
		first = value;
	    }
	    else if (n == 1)
	    {
		meanDel = value - first;
	    }
	    else if (isConsistent)
	    {
		accum(value, fEps);
	    }
	    last = value;
	    n++;
	}
	return isConsistent;
    }

    /**
     * Accumulates a set of doubles.  Indicates whether or not the sequence is
     * consistent with the arithmetic progression so far.
     *
     * @param values		The values to accumulate.
     * @return			False if the difference between any current
     *				and previous value normalized by the current
     *				increment differs from unity by more than the
     *				nearness threshold; otherwise, true.
     * @throws VisADException	{@link #isConsistent()} was false before this
     *				method was invoked.
     * @precondition		isConsistent() is true.
     * @postcondition		A subsequent getNumber() will return
     *				values.length more than previously
     *				if the function returns true.
     * @postcondition		A subsequent getLast() will return the
     *				value argument if the function returns true.
     */
    public synchronized boolean accumulate(double[] values)
	throws VisADException
    {
	if (!isConsistent())
	    throw new VisADException(
		getClass().getName() + ".accumulate(double[]): " +
		"Sequence isn't an arithmetic progression");
	for (int i = 0; i < values.length; i++)
	{
	    double value = values[i];
	    if (n == 0)
	    {
		first = value;
	    }
	    else if (n == 1)
	    {
		meanDel = value - first;
	    }
	    else if (isConsistent)
	    {
		accum(value, dEps);
	    }
	    last = value;
	    n++;
	}
	return isConsistent;
    }

    private void accum(double value, double eps)
    {
	double uncLast = last*eps;
	double uncValue = value*eps;
	double var = uncLast*uncLast + uncValue*uncValue;
	double err = value - (last + meanDel);
	if (err*err > var)
	{
	    isConsistent = false;
	}
	else
	{
	    meanDel = (value - first) / n;
	}
    }

    /**
     * Accumulates a value.  Indicate whether or not the value is
     * consistent with the arithmetic progression so far.
     *
     * @param value		The value to accumulate.
     * @return			False if the difference between any current
     *				and previous value normalized by the current
     *				increment differs from unity by more than the
     *				nearness threshold; otherwise, true.
     * @throws VisADException	The sequence isn't an arithmetic progression.
     * @precondition		isConsistent() is true.
     * @postcondition		A subsequent getNumber() will return
     *				values.length more than previously
     *				if the function returns true.
     * @postcondition		A subsequent getLast() will return the
     *				value argument if the function returns true.
     */
    public final synchronized boolean accumulate(float value)
	throws VisADException
    {
	if (!isConsistent())
	    throw new VisADException(
		getClass().getName() + ".accumulate(double): " +
		"Sequence isn't an arithmetic progression");
        fValues[0] = value;
	return accumulate(fValues);
    }

    /**
     * Accumulates a value.  Indicate whether or not the value is
     * consistent with the arithmetic progression so far.
     *
     * @param value		The value to accumulate.
     * @return			False if the difference between any current
     *				and previous value normalized by the current
     *				increment differs from unity by more than the
     *				nearness threshold; otherwise, true.
     * @throws VisADException	The sequence isn't an arithmetic progression.
     * @precondition		isConsistent() is true.
     * @postcondition		A subsequent getNumber() will return
     *				values.length more than previously
     *				if the function returns true.
     * @postcondition		A subsequent getLast() will return the
     *				value argument if the function returns true.
     */
    public final synchronized boolean accumulate(double value)
	throws VisADException
    {
	if (!isConsistent())
	    throw new VisADException(
		getClass().getName() + ".accumulate(double): " +
		"Sequence isn't an arithmetic progression");
        dValues[0] = value;
	return accumulate(dValues);
    }

    /**
     * Indicates whether or not the sequence so far is consistent with an
     * arithmetic progression.
     *
     * @return			true if and only if the sequence
     *				of values seen so far is consistent with an
     *				arithmetic progression.
     */
    public synchronized final boolean isConsistent() 
    {
	return isConsistent;
    }

    /**
     * Gets the number of values.  Only meaningfull if {@link #isConsistent()}
     * is true.
     *
     * @return			The number of values accumulated so far.
     * @throws VisADException	The sequence isn't an arithmetic progression.
     * @require			isConsistent() is true.
     */
    public synchronized final long getNumber() 
	throws VisADException
    {
	if (!isConsistent())
	    throw new VisADException(
		getClass().getName() + ".getNumber(): " +
		"Sequence isn't an arithmetic progression");
	return n;
    }

    /**
     * Gets the first value.
     *
     * @return			The first accumulated value.
     * @throws VisADException	The sequence isn't an arithmetic progression.
     * @require			isConsistent() is true.
     */
    public synchronized final double getFirst() 
	throws VisADException
    {
	if (!isConsistent())
	    throw new VisADException(
		getClass().getName() + ".getFirst(): " +
		"Sequence isn't an arithmetic progression");
	return first;
    }

    /**
     * Returns the "last" value accumulated.  It is only meaningfull if
     * {@link #isConsistent} is true.
     *
     * @return			The last accumulated value.
     * @throws VisADException	The sequence isn't an arithmetic progression.
     */
    public synchronized final double getLast()
	throws VisADException
    {
	if (!isConsistent())
	    throw new VisADException(
		getClass().getName() + ".getLast(): " +
		"Sequence isn't an arithmetic progression");
	return last;
    }

    /**
     * Gets the current common difference.  Only meaningfull if {@link 
     * #isConsistent()} is true.
     *
     * @return			The computed common difference so far.
     * @throws VisADException	The sequence isn't an arithmetic progression.
     * @require			isConsistent() is true.
     */
    public synchronized final double getCommonDifference() 
	throws VisADException
    {
	if (!isConsistent())
	    throw new VisADException(
		getClass().getName() + ".getCommonDifference(): " +
		"Sequence isn't an arithmetic progression");
	return meanDel;
    }

    public static void main(String[] args)
        throws Exception
    {
	double[] lats = {
	    39.2, 39.21, 39.22, 39.23, 39.24, 39.25, 39.26, 39.27, 39.28, 39.29,
	    39.3, 39.31, 39.32, 39.33, 39.34, 39.35, 39.36, 39.37, 39.38, 39.39,
	    39.4, 39.41, 39.42, 39.43, 39.44, 39.45, 39.46, 39.47, 39.48, 39.49,
	    39.5, 39.51, 39.52, 39.53, 39.54, 39.55, 39.56, 39.57, 39.58, 39.59,
	    39.6, 39.61, 39.62, 39.63, 39.64, 39.65, 39.66, 39.67, 39.68, 39.69,
	    39.7, 39.71, 39.72, 39.73, 39.74, 39.75, 39.76, 39.77, 39.78, 39.79,
	    39.8, 39.81, 39.82, 39.83, 39.84, 39.85, 39.86, 39.87, 39.88, 39.89,
	    39.9, 39.91, 39.92, 39.93, 39.94, 39.95, 39.96, 39.97, 39.98, 39.99,
	    40 };
	ArithProg ap = new ArithProg();
	ap.accumulate(lats);
    }
}

 

Ads help maintain this website.