001/* A sample implementation of the CQComparator that operates on instances 002 of Double. 003 004 Copyright (c) 1998-2014 The Regents of the University of California. 005 All rights reserved. 006 Permission is hereby granted, without written agreement and without 007 license or royalty fees, to use, copy, modify, and distribute this 008 software and its documentation for any purpose, provided that the above 009 copyright notice and the following two paragraphs appear in all copies 010 of this software. 011 012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 016 SUCH DAMAGE. 017 018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 023 ENHANCEMENTS, OR MODIFICATIONS. 024 025 PT_COPYRIGHT_VERSION_2 026 COPYRIGHTENDKEY 027 028 */ 029package ptolemy.actor.util.test; 030 031import ptolemy.actor.util.CQComparator; 032import ptolemy.actor.util.CalendarQueue; 033 034/////////////////////////////////////////////////////////////////// 035//// DoubleCQComparator 036 037/** 038 This class implements the CQComparator interface. It compares instances 039 of Double. Therefore, all arguments passed to its methods have to be of 040 type Double (or Double[] for the getBinWidth() method). If this is violated, 041 a ClassCastException will be thrown. This class is used to test the 042 CalendarQueue. 043 044 @author Lukito Muliadi 045 @version $Id$ 046 @since Ptolemy II 0.2 047 @Pt.ProposedRating Green (eal) 048 @Pt.AcceptedRating Yellow (liuj) 049 @see CQComparator 050 @see CalendarQueue 051 */ 052public class DoubleCQComparator implements CQComparator { 053 /////////////////////////////////////////////////////////////////// 054 //// public methods //// 055 056 /** Compare the two argument. Return a negative integer, 057 * zero, or a positive integer as the first argument is less than, 058 * equal to, or greater than the second. 059 * Both arguments have to be instances of Double, otherwise a 060 * ClassCastException will be thrown. 061 * @param object1 The first Double. 062 * @param object2 The second Double. 063 * @return A negative integer, zero, or a positive integer if the first 064 * argument is less than, equal to, or greater than the second. 065 * @exception ClassCastException If either argument is not an instance 066 * of Double. 067 */ 068 @Override 069 public int compare(Object object1, Object object2) { 070 Double a = (Double) object1; 071 Double b = (Double) object2; 072 073 // FindBugs: http://findbugs.sourceforge.net/bugDescriptions.html#CO_COMPARETO_INCORRECT_FLOATING 074 075 // "This method compares double or float values using pattern 076 // like this: val1 > val2 ? 1 : val1 < val2 ? -1 : 0. This 077 // pattern works incorrectly for -0.0 and NaN values which may 078 // result in incorrect sorting result or broken collection (if 079 // compared values are used as keys). Consider using 080 // Double.compare or Float.compare static methods which handle 081 // all the special cases correctly." 082 083 return a.compareTo(b); 084 085 // if (a.doubleValue() < b.doubleValue()) { 086 // return -1; 087 // } else if (a.doubleValue() > b.doubleValue()) { 088 // return 1; 089 // } else { 090 // return 0; 091 // } 092 } 093 094 /** Given an entry, a zero reference, and a bin width, return a 095 * virtual bin number for the entry. The virtual bin number is a 096 * quantized double. The calculation performed is: 097 * <p> 098 * <i>(entry - zeroReference) / binWidth</i>, 099 * </p> 100 * with the result cast to long. 101 * If the arguments are not instances of Double, then a 102 * ClassCastException will be thrown. 103 * @param entry The entry. 104 * @return The virtual bin number for the entry, according to the 105 * zero reference and the bin width. 106 * @exception ClassCastException If the arguments are not instances of 107 * Double. 108 */ 109 @Override 110 public long getVirtualBinNumber(Object entry) { 111 return (long) ((((Double) entry).doubleValue() 112 - _zeroReference.doubleValue()) / _binWidth.doubleValue()); 113 } 114 115 /** Given an array of Double objects, find the appropriate bin 116 * width. By 'appropriate', the bin width is chosen such that on average 117 * the number of entry in all non-empty bins is equal to one. 118 * If the argument is null, return the default bin width, which is 1.0 119 * for this implementation. 120 * 121 * @param entryArray An array of Double objects. 122 * @exception ClassCastException If one of the array elements is not 123 * an instance of Double. 124 */ 125 @Override 126 public void setBinWidth(Object[] entryArray) { 127 if (entryArray == null) { 128 // Reset to default. 129 _binWidth = Double.valueOf(1.0); 130 return; 131 } 132 133 double[] diff = new double[entryArray.length - 1]; 134 135 double average = 0; 136 137 for (int i = 1; i < entryArray.length; ++i) { 138 diff[i - 1] = ((Double) entryArray[i]).doubleValue() 139 - ((Double) entryArray[i - 1]).doubleValue(); 140 average = average + diff[i - 1]; 141 } 142 143 average = average / diff.length; 144 145 double effAverage = 0; 146 int nEffSamples = 0; 147 148 for (int i = 1; i < entryArray.length; ++i) { 149 if (diff[i - 1] < 2 * average) { 150 nEffSamples++; 151 effAverage = effAverage + diff[i - 1]; 152 } 153 } 154 155 // To avoid returning NaN or 0.0 for the width, if this is 156 // the result, leave the bin width unchanged. 157 if (effAverage == 0.0 || nEffSamples == 0) { 158 return; 159 } 160 161 effAverage = effAverage / nEffSamples; 162 _binWidth = Double.valueOf(3.0 * effAverage); 163 } 164 165 /** Set the zero reference, to be used in calculating the virtual 166 * bin number. 167 * @exception ClassCastException If the argument is not an instance 168 * of Double. 169 */ 170 @Override 171 public void setZeroReference(Object zeroReference) { 172 _zeroReference = (Double) zeroReference; 173 } 174 175 /////////////////////////////////////////////////////////////////// 176 //// private members //// 177 // The bin width. 178 private Double _binWidth = Double.valueOf(1.0); 179 180 // The zero reference. 181 private Double _zeroReference = Double.valueOf(0.0); 182}