Various number-related routines and classes that are frequently used : Number « Data Type « Java






Various number-related routines and classes that are frequently used

    
/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


/**
 * Various number-related routines and classes that are frequently used.
 * 
 * @author barclay
 */
public class Number {
  /**
   * Default number of decimal places to round to:
   */
  public static final int DECIMAL_PLACES = 2;

  /**
   * Round a float to the default number of decimal places.
   * 
   * @param value
   *          The value to round.
   * @return The rounded value as a float.
   * @see #DECIMAL_PLACES
   */
  public static float Round(float value) {
    return Round(value, DECIMAL_PLACES);
  }

  /**
   * Round a float to the specified number of decimal places.
   * 
   * @param value
   *          The value to round.
   * @param places
   *          The number of decimal points.
   * @return The rounded value as a float.
   */
  public static float Round(float value, int places) {
    float p = (float) Math.pow(10, places);
    value = value * p;
    float tmp = Math.round(value);
    return (float) tmp / p;
  }

  /**
   * Clamp a <code>value</code> to <code>min</code> or <code>max</code>,
   * inclusive.
   * 
   * @param value
   *          The value to clamp.
   * @param min
   *          The minimum value.
   * @param max
   *          The maximum value.
   * @return If <code>value</code> is greater than <code>max</code> then
   *         <code>max</code>, else if <code>value</code> is less than
   *         <code>min</code> then <code>min</code>, else <code>value</code>.
   */
  public static float Clamp(float value, float min, float max) {
    if (value > max)
      return max;
    if (value < min)
      return min;
    return value;
  }

  public enum TrendState {
    DOWN_15_GOOD,
    DOWN_15_BAD,
    DOWN_30_GOOD,
    DOWN_30_BAD,
    DOWN_45_GOOD,
    DOWN_45_BAD,
    UP_15_GOOD,
    UP_15_BAD,
    UP_30_GOOD,
    UP_30_BAD,
    UP_45_GOOD,
    UP_45_BAD,
    DOWN_15,
    UP_15,
    FLAT,
    FLAT_GOAL,
    UNKNOWN
  };

  public static TrendState getTrendState(float oldTrend, float newTrend,
      float goal, float sensitivity, float stdDev) {
    sensitivity = sensitivity * stdDev;
    float half = sensitivity / 2.0f;
    float quarter = sensitivity / 4.0f;

    if (oldTrend == newTrend) {
      // truly flat trend
      if (newTrend == goal)
        // perfect!
        return TrendState.FLAT_GOAL;
      else if (newTrend < goal && newTrend + quarter > goal)
        // flat near the goal!
        return TrendState.FLAT_GOAL;
      else if (newTrend > goal && newTrend - quarter < goal)
        // flat near the goal!
        return TrendState.FLAT_GOAL;
      else
        return TrendState.FLAT;
    } else if (oldTrend > newTrend) {
      // going down
      if (oldTrend > goal && newTrend > goal) {
        // toward goal
        if (oldTrend - newTrend > sensitivity)
          // huge drop
          return TrendState.DOWN_45_GOOD;
        else if (oldTrend - newTrend > half)
          // big drop
          return TrendState.DOWN_30_GOOD;
        else if (oldTrend - newTrend > quarter)
          // little drop
          return TrendState.DOWN_15_GOOD;
        else {
          // under bounds for flat
          if (newTrend - quarter < goal)
            // flat near the goal!
            return TrendState.FLAT_GOAL;
          else
            // flat elsewhere
            return TrendState.FLAT;
        }
      } else if (oldTrend < goal && newTrend < goal) {
        // away from goal
        if (oldTrend - newTrend > sensitivity)
          // huge drop
          return TrendState.DOWN_45_BAD;
        else if (oldTrend - newTrend > half)
          // big drop
          return TrendState.DOWN_30_BAD;
        else if (oldTrend - newTrend > quarter)
          // little drop
          return TrendState.DOWN_15_BAD;
        else {
          // under bounds for flat
          if (newTrend + quarter > goal)
            // flat near the goal!
            return TrendState.FLAT_GOAL;
          else
            // flat elsewhere
            return TrendState.FLAT;
        }
      } else
        // crossing goal line
        return TrendState.DOWN_15;
    } else if (oldTrend < newTrend) {
      // going up
      if (oldTrend < goal && newTrend < goal) {
        // toward goal
        if (newTrend - oldTrend > sensitivity)
          // big rise
          return TrendState.UP_45_GOOD;
        else if (newTrend - oldTrend > half)
          // little rise
          return TrendState.UP_30_GOOD;
        else if (newTrend - oldTrend > quarter)
          // little rise
          return TrendState.UP_15_GOOD;
        else {
          // under bounds for flat
          if (newTrend + quarter > goal)
            // flat near the goal!
            return TrendState.FLAT_GOAL;
          else
            // flat elsewhere
            return TrendState.FLAT;
        }
      } else if (oldTrend > goal && newTrend > goal) {
        // away from goal
        if (newTrend - oldTrend > sensitivity)
          // big rise
          return TrendState.UP_45_BAD;
        else if (newTrend - oldTrend > half)
          // little rise
          return TrendState.UP_30_BAD;
        else if (newTrend - oldTrend > quarter)
          // little rise
          return TrendState.UP_15_BAD;
        else {
          // under bounds for flat
          if (newTrend - quarter < goal)
            // flat near the goal!
            return TrendState.FLAT_GOAL;
          else
            // flat elsewhere
            return TrendState.FLAT;
        }
      } else {
        // crossing goal line
        return TrendState.UP_15;
      }
    } else
      // ??
      return TrendState.UNKNOWN;
  }
  /**
   * An exponentially smoothed weighted moving average. Not thread safe. Trend
   * is calculated thusly: <br>
   * <code>
   * trend[n] := trend[n-1] + smoothing_percentage * (value[n] - value[n-1])
   * </code>
   * 
   * @author barclay
   */
  public static class Trend {
    /**
     * Default smoothing percentage. This value will be used to scale the
     * previous entry by multiplying the previous entry's value and adding that
     * to the current value, so a smoothing percentage of 0.1 is 10%.
     */
    private static final float DEFAULT_SMOOTHING = 0.1f;

    private int mNEntries = 0;
    private float mSmoothing = DEFAULT_SMOOTHING;
    private float mSum = 0.0f;
    private boolean mFirst = true;
    private float mTrendLast = 0.0f;

    public float mTrendPrev = 0.0f;
    public float mTrend = 0.0f;
    public float mMin = 0.0f;
    public float mMax = 0.0f;
    public float mMean = 0.0f;

    /**
     * Default constructor. Set the smoothing percentage to the default.
     * 
     * @see #DEFAULT_SMOOTHING
     */
    public Trend() {
    }

    /**
     * Constructor
     * 
     * @param smoothing
     *          Sets the smoothing percentage to the specified value.
     * @see #DEFAULT_SMOOTHING
     */
    public Trend(float smoothing) {
      mSmoothing = smoothing;
    }

    /**
     * Copy Constructor
     * 
     * @param source
     *          Returns a new instance of Trend with all data set to source.
     * @see #DEFAULT_SMOOTHING
     */
    public Trend(Trend source) {
      mNEntries = source.mNEntries;
      mSmoothing = source.mSmoothing;
      mSum = source.mSum;
      mFirst = source.mFirst;
      mTrendLast = source.mTrendLast;
      mTrendPrev = source.mTrendPrev;
      mTrend = source.mTrend;
      mMin = source.mMin;
      mMax = source.mMax;
      mMean = source.mMean;
    }

    /**
     * Return the smoothing constant used by the Trend.
     * 
     * @return The smoothing constant as a float.
     */
    public float getSmoothing() {
      return mSmoothing;
    }

    /**
     * Update the trend with a new value. The value is implicitly "later" in the
     * sequence than all previous values.
     * 
     * @param val
     *          The value to add to the series.
     */
    public void update(float val) {
      mNEntries++;
      mSum += val;

      float oldMean = mMean;
      mMean += (val - oldMean) / mNEntries;

      // T(n) = T(n-1) + 0.1(V(n) - T(n-1))
      // : T(n) is the trend number for day n
      // : V(n) is the value number for day n
      // : S is the smoothing factor (default 0.1)
      if (mFirst == true) {
        mFirst = false;
        mTrend = val;
        mMin = val;
        mMax = val;
      } else {
        mTrend = mTrendLast + (mSmoothing * (val - mTrendLast));
        if (mTrend < mMin)
          mMin = mTrend;
        if (mTrend > mMax)
          mMax = mTrend;
      }
      mTrendPrev = mTrendLast;
      mTrendLast = mTrend;
    }
  }

  /**
   * Class for keeping track of various statistics intended to be updated
   * incrementally, including total number of updates, sum, mean, variance, and
   * standard deviation of the series. Not thread safe.
   * 
   * @author barclay
   */
  public static class RunningStats {
    public int mNDatapoints = 0;
    public int mNEntries = 0;
    public float mSum = 0.0f;
    public float mMean = 0.0f;
    public float mEntryMean = 0.0f;
    public float mVarSum = 0.0f;
    public float mVar = 0.0f;
    public float mStdDev = 0.0f;

    /**
     * Sole constructor. Initializes all stats to 0.
     */
    public RunningStats() {
    }

    /**
     * Copy Constructor
     * 
     * @param source
     *          Returns a new instance of RunningStats with all data set to
     *          source.
     */
    public RunningStats(RunningStats source) {
      mNDatapoints = source.mNDatapoints;
      mNEntries = source.mNEntries;
      mSum = source.mSum;
      mMean = source.mMean;
      mEntryMean = source.mEntryMean;
      mVarSum = source.mVarSum;
      mVar = source.mVar;
      mStdDev = source.mStdDev;
    }

    /**
     * update the statistics with the specified value. The value may be an
     * aggregate of several other values, as indicated by the second parameter.
     * A separate value will be recored for per-entry and and per-update means.
     * 
     * @param val
     *          The value to update the statistics with.
     * @param nEntries
     *          The number of entries this value is an aggregate of.
     */
    public void update(float val, int nEntries) {
      mNDatapoints++;
      mNEntries += nEntries;
      mSum += val;

      // Mean is calculated thusly to avoid float expansion and contraction,
      // which
      // would minimize accuracy.
      float oldMean = mMean;
      mMean += (val - oldMean) / mNDatapoints;
      mVarSum += (val - oldMean) * (val - mMean);
      mVar = mVarSum / mNDatapoints;
      mStdDev = (float) Math.sqrt(mVar);

      if (mNEntries > 0) {
        float oldEntryMean = mEntryMean;
        mEntryMean += (val - oldEntryMean) / mNEntries;
      }

      return;
    }
  }

  /**
   * Class for keeping track of the Standard Deviation over the last X values.
   * 
   * @author barclay
   */
  public static class WindowedStdDev {
    private Lock mLock;
    private ArrayList<Float> mValues;
    private int mHistory;

    /**
     * Sole constructor. Initializes all stats to 0.
     */
    public WindowedStdDev(int history) {
      mHistory = history;
      mValues = new ArrayList<Float>(mHistory);
      mLock = new ReentrantLock();
    }

    /**
     * Copy Constructor
     * 
     * @param source
     *          Returns a new instance of WindowedStdDev with all data set to
     *          source.
     */
    public WindowedStdDev(WindowedStdDev source) {
      mLock = new ReentrantLock();
      source.waitForLock();
      mHistory = source.mHistory;
      mValues = new ArrayList<Float>(mHistory);
      for (int i = 0; i < source.mValues.size(); i++) {
        try {
          mValues.add(new Float(source.mValues.get(i)));          
        } catch(IndexOutOfBoundsException e) {
          break;
        }
      }
      source.unlock();
    }

    public void waitForLock() {
      while (lock() == false) {
      }
    }

    public boolean lock() {
      try {
        return mLock.tryLock(250L, TimeUnit.MILLISECONDS);
      } catch (InterruptedException e) {
        return false;
      }
    }

    public void unlock() {
      mLock.unlock();
    }

    /**
     * update the std dev with the specified value.
     * 
     * @param val
     *          The value to update the statistics with.
     */
    public void update(float val) {
      waitForLock();
      mValues.add(new Float(val));
      if (mValues.size() > mHistory) {
        try {
          mValues.remove(0);
        } catch(IndexOutOfBoundsException e) {
          // nothing
        }
      }
      unlock();
      return;
    }

    /**
     * Fetch current Standard Deviation.
     * 
     * @param val
     *          The value to update the statistics with.
     */
    public float getStandardDev() {
      float mean = 0.0f;
      float meanSqr = 0.0f;
      float variance = 0.0f;
      float delta = 0.0f;
      float val = 0.0f;

      waitForLock();

      int nValues = mValues.size();
      for (int i = 0; i < nValues; i++) {
        try {
          val = mValues.get(i);
          delta = val - mean;
          mean = mean + delta / (i + 1);
          meanSqr = meanSqr + delta * (val - mean);
        } catch(IndexOutOfBoundsException e) {
          break;
        }
      }
      unlock();
      
      variance = meanSqr / nValues;
      return (float) Math.sqrt(variance);
    }
  }

  /**
   * Performs a standard Pearson linear correlation on multiple series of data
   * at one, returning the results in a matrix.
   * 
   * @author barclay
   */
  public static class LinearMatrixCorrelation {
    private int mNumSeries = 0;
    private int mNEntries = 0;

    private Float[] mSum;
    private Float[] mMean;
    private Float[] mSumSquare;
    private Float[] mStdDev;
    private Float[][] mSumCoproduct;
    private Float[][] mCovariance;
    private Float[][] mCorrelation;

    /**
     * Constructor. Allocates internal data structures and zero's out the output
     * matrix data.
     * 
     * @param numSeries
     *          The number of series that will be included in each call to
     *          <code>update()</code>.
     */
    public LinearMatrixCorrelation(int numSeries) {
      mNumSeries = numSeries;

      mSum = new Float[numSeries];
      mMean = new Float[numSeries];
      mSumSquare = new Float[numSeries];
      mStdDev = new Float[numSeries];

      mSumCoproduct = new Float[numSeries][];
      mCovariance = new Float[numSeries][];
      mCorrelation = new Float[numSeries][];

      for (int i = 0; i < numSeries; i++) {
        mSum[i] = 0.0f;
        mMean[i] = 0.0f;
        mSumSquare[i] = 0.0f;
        mStdDev[i] = 0.0f;

        mSumCoproduct[i] = new Float[numSeries];
        mCovariance[i] = new Float[numSeries];
        mCorrelation[i] = new Float[numSeries];

        for (int j = 0; j < numSeries; j++) {
          mSumCoproduct[i][j] = 0.0f;
          mCovariance[i][j] = 0.0f;
          mCorrelation[i][j] = 0.0f;
        }
      }
    }

    /**
     * Adds a vector (array) of values, 1 per series, to the calculations.
     * Graphically, all values are considered to be the at the same X (or Y)
     * position, and the values in the array argument denote the corresponding Y
     * (or X) value specific to the each series. Thus, the parameter x is an
     * array of values x[0 .. numSeries-1], one value per series, all of which
     * occured at the same "time." If a series has no such value, the entry in
     * the array should be null, as the length of the array must match the
     * <code>numSeries</code> past into the constructor at each invocation.
     * 
     * @param x
     *          The values for each series as Floats.
     * @return true if the input acceptable, else false if the length of
     *         <code>x[]</code> does not match <code>numSeries</code> or a value
     *         less than 1 was passed to the constructor.
     * @see LinearMatrixCorrelation#LinearMatrixCorrelation
     */
    public boolean update(Float[] x) {
      float oldMean;

      if (x.length != mNumSeries)
        return false;

      if (mNEntries + 1 > mNumSeries)
        return false;

      mNEntries++;

      float sweep = (mNEntries - 1.0f) / mNEntries;
      for (int i = 0; i < x.length; i++) {
        if (x[i] != null) {
          mSum[i] += x[i];
          oldMean = mMean[i];
          mMean[i] += (x[i] - oldMean) / mNEntries;
          mSumSquare[i] += (x[i] - oldMean) * (x[i] - mMean[i]);
          mStdDev[i] = (float) Math.sqrt(mSumSquare[i] * sweep);
        }
      }

      for (int i = 0; i < x.length; i++) {
        if (x[i] != null) {
          for (int j = i + 1; j < x.length; j++) {
            if (x[j] != null) {
              mSumCoproduct[i][j] += (x[i] - mMean[i]) * (x[j] - mMean[j]);
              mCovariance[i][j] = mSumCoproduct[i][j] * sweep;
              mCorrelation[i][j] = mCovariance[i][j]
                  / (mStdDev[i] * mStdDev[j]);
              mCorrelation[j][i] = mCovariance[i][j]
                  / (mStdDev[i] * mStdDev[j]);
              mCorrelation[i][j] = mCovariance[i][j]
                  / (mStdDev[i] * mStdDev[j]);
            }
          }
        }
        mCorrelation[i][i] = 1.0f;
      }

      return true;
    }

    /**
     * Returns a reference to the correlation output matrix. The upper right
     * triangle is a mirror of the lower left, and the dividing diagonal the
     * identity correlation, i.e., 1.0f. In order to run through the matrix
     * without duplicates (e.g., processing both output[i][j] and output[j][i],
     * use a construct like: <br>
     * 
     * <pre>
     * for (int i = 0; i &lt; output.length; i++) {
     *   for (int j = i+1; j &lt; output.length; j++) {
     *     if (output[i][j] != null) { ... }
     *   }
     * }
     * </pre>
     * 
     * Note that any correlations that could not be calculated, either due to
     * lack of datapoints or structure of the data, will be null.
     * 
     * @return Float[][], the output correlation matrix.
     */
    public Float[][] getCorrelations() {
      return mCorrelation;
    }

    /**
     * Return a string interpretation of the linear correlation value. Note that
     * this is highly dependent on the data being correlated, and should be no
     * means be taken as gospel.
     * 
     * @param c
     *          The correlation value, should be -1.0f <= c <= 1.0f.
     * @return A string interpretation.
     */
    public static String correlationToString(float c) {
      if (c > 0.5)
        return "Strong";
      if (c < -0.5)
        return "Inverse Strong";
      if (c > 0.3)
        return "Medium";
      if (c < -0.3)
        return "Inverse Medium";
      return "Weak";
    }
  }
}

   
    
    
    
  








Related examples in the same category

1.Methods for number conversion and parsing
2.Get Digit Number String
3.Convert to numbers
4.Check Number properties and convert from Number
5.Check if number are in a given range
6.Turns a string value into a java.lang.Number.
7.Provides IEEE-754r variants of NumberUtils methods.
8.Checks whether the String a valid Java number.
9.Specifies sizes of various types in bytes.
10.Class to represent 16-bit unsigned integers.
11.Implements an integer object wrapper which allows changing the integer value.Implements an integer object wrapper which allows changing the integer value.
12.Mixed Radix Number
13.This class allows a number to be converted to it's unsigned value.
14.Numbers will be equals if enough decimals are equals, without thinking about approximations.
15.Ternary Numnber
16.Implements a long object wrapper which allows changing the long value.
17.Convert the given number into an instance of the given target class.