Source code: edu/ucsb/ccs/jaqual/standard/InRange.java
1 package edu.ucsb.ccs.jaqual.standard;
2
3 import edu.ucsb.ccs.jaqual.Assertion;
4
5 /**
6 * An assertion to determine if a number falls in a given range. The
7 * assertion supports both integer and floating point comparison. You
8 * can specify whether or not the bounding values are included or
9 * excluded from the range.
10 *
11 * @author Parker Abercrombie
12 * @version $Id: InRange.java,v 1.3 2002/07/13 09:08:10 parkera Exp $
13 */
14
15 public class InRange implements Assertion {
16
17 /**
18 * Constant to indicate the bound is inclusive. The bounding value
19 * is included in the range.
20 */
21 public static final int INCLUSIVE = 0;
22
23 /**
24 * Constant to indicate the bound is exclusive. The bounding value
25 * is not included in the range.
26 */
27 public static final int EXCLUSIVE = 1;
28
29 /**
30 * Constant to indicate the comparison is performed using only
31 * integer values. Floating point values will be rounded.
32 */
33 protected static final int INTEGER_COMPARISON = 0;
34
35 /**
36 * Constant to indicate the comparison is performed using floating
37 * point values and a tolerance.
38 */
39 protected static final int FLOAT_COMPARISON = 1;
40
41 /**
42 * The comparison mode to use for the lower bound, either INCLUSIVE
43 * or EXCLUSIVE.
44 */
45 protected int lowerMode;
46
47 /**
48 * The comparison mode to use for the upper bound, either INCLUSIVE
49 * or EXCLUSIVE.
50 */
51 protected int upperMode;
52
53 /**
54 * Maximum bound for integer comparison.
55 */
56 protected long intMin;
57
58 /**
59 * Minimum bound for integer comparison.
60 */
61 protected long intMax;
62
63 /**
64 * Minimum bound for floating point comparison.
65 */
66 protected double realMin;
67
68 /**
69 * Maximum bound for floating point comparison.
70 */
71 protected double realMax;
72
73 /**
74 * The tolerance to use when comparing floating point numbers.
75 */
76 protected double tolerance;
77
78 /**
79 * The comparison type, either INTEGER_COMPARISON or
80 * FLOAT_COMPARISON.
81 */
82 protected int comparisonType;
83
84 /**
85 * Create an assertion to test that a value falls in the interval
86 * [minVal, maxVal]. The bounds are inclusive, and the values are
87 * integers.
88 *
89 * @param minVal the lower bound.
90 * @param maxVal the upper bound.
91 */
92 public InRange (long minVal, long maxVal) {
93 this(minVal, maxVal, INCLUSIVE, INCLUSIVE);
94 }
95
96 /**
97 * Create an assertion to test that a value falls between `minVal'
98 * and `maxVal'. The values are integers.
99 *
100 * @param minVal the lower bound.
101 * @param maxVal the upper bound.
102 * @param mode the comparison mode to use for both bounds, either
103 * INCLUSIVE or EXCLUSIVE.
104 */
105 public InRange (long minVal, long maxVal, int mode) {
106 this(minVal, maxVal, mode, mode);
107 }
108
109 /**
110 * Create an assertion to test that a value falls between `minVal'
111 * and `maxVal'. The values are integers.
112 *
113 * @param minVal the lower bound.
114 * @param maxVal the upper bound.
115 * @param lowerMode the comparison mode to use for the lower bound, either
116 * INCLUSIVE or EXCLUSIVE.
117 * @param upperMode the comparison mode to use for the upper bound, either
118 * INCLUSIVE or EXCLUSIVE.
119 */
120 public InRange (long minVal, long maxVal, int lowerMode, int upperMode) {
121 comparisonType = INTEGER_COMPARISON;
122 intMin = minVal;
123 intMax = maxVal;
124 this.lowerMode = lowerMode;
125 this.upperMode = upperMode;
126 }
127
128 /**
129 * Create an assertion to test that a value falls in the interval
130 * [minVal, maxVal]. The bounds are inclusive, and the values are
131 * floating point.
132 *
133 * @param minVal the lower bound.
134 * @param maxVal the upper bound.
135 * @param tolerance the tolerance to use in the floating point
136 * comparison.
137 */
138 public InRange (double minVal, double maxVal, double tolerance) {
139 this(minVal, maxVal, tolerance, INCLUSIVE, INCLUSIVE);
140 }
141
142 /**
143 * Create an assertion to test that a value falls in the interval
144 * [minVal, maxVal]. The values are floating point.
145 *
146 * @param minVal the lower bound.
147 * @param maxVal the upper bound.
148 * @param tolerance the tolerance to use in the floating point
149 * comparison.
150 * @param mode the comparison mode to use for both bounds, either
151 * INCLUSIVE or EXCLUSIVE.
152 */
153 public InRange (double minVal, double maxVal, double tolerance, int mode) {
154 this(minVal, maxVal, tolerance, mode, mode);
155 }
156
157 /**
158 * Create an assertion to test that a value falls in the interval
159 * [minVal, maxVal]. The values are floating point.
160 *
161 * @param minVal the lower bound.
162 * @param maxVal the upper bound.
163 * @param tolerance the tolerance to use in the floating point
164 * comparison.
165 * @param lowerMode the comparison mode to use for the lower bound, either
166 * INCLUSIVE or EXCLUSIVE.
167 * @param upperMode the comparison mode to use for the upper bound, either
168 * INCLUSIVE or EXCLUSIVE.
169 */
170 public InRange (double minVal, double maxVal, double tolerance,
171 int lowerMode, int upperMode) {
172 comparisonType = FLOAT_COMPARISON;
173 realMin = minVal;
174 realMax = maxVal;
175 this.lowerMode = lowerMode;
176 this.upperMode = upperMode;
177 this.tolerance = tolerance;
178 }
179
180 /**
181 * Determine if a value is in the allowed range. If the comparison
182 * type is FLOAT_COMPARISON, the comparison is performed using a
183 * tolerance.
184 *
185 * @param o the value to examine. This must be an instance of
186 * java.lang.Number.
187 *
188 * @exception IllegalArgumentException if `o' is not an instance of
189 * java.lang.Number.
190 */
191 public boolean eval (Object o) throws IllegalArgumentException {
192 if (o instanceof Number) {
193 if (comparisonType == INTEGER_COMPARISON) {
194 long val = ((Number) o).longValue();
195 if ((lowerMode == INCLUSIVE) && (upperMode == INCLUSIVE)) {
196 return (val >= intMin) && (val <= intMax);
197 } else if ((lowerMode == INCLUSIVE) && (upperMode == EXCLUSIVE)) {
198 return (val >= intMin) && (val < intMax);
199 } else if ((lowerMode == EXCLUSIVE) && (upperMode == INCLUSIVE)) {
200 return (val > intMin) && (val <= intMax);
201 } else {
202 // assert((lowerMode == EXCLUSIVE) && (upperMode == EXCLUSIVE));
203 return (val > intMin) && (val < intMax);
204 }
205 } else {
206 // assert(comparisonType == FLOAT_COMPARISON);
207 double val = ((Number) o).doubleValue();
208
209 if ((lowerMode == INCLUSIVE) && (upperMode == INCLUSIVE)) {
210 return (compare(val, realMin) >= 0) && (compare(val, realMax) <= 0);
211 } else if ((lowerMode == INCLUSIVE) && (upperMode == EXCLUSIVE)) {
212 return (compare(val, realMin) >= 0) && (compare(val, realMax) < 0);
213 } else if ((lowerMode == EXCLUSIVE) && (upperMode == INCLUSIVE)) {
214 return (compare(val, realMin) > 0) && (compare(val, realMax) <= 0);
215 } else {
216 // assert((lowerMode == EXCLUSIVE) && (upperMode == EXCLUSIVE));
217 return (compare(val, realMin) > 0) && (compare(val, realMax) < 0);
218 }
219 }
220 } else {
221 throw new IllegalArgumentException("Object is not an instance of java.lang.Number");
222 }
223 }
224
225 /**
226 * Compare two floating point numbers.
227 *
228 * @return 0 if the numbers are equal (within a tolerance defined
229 * by `tolerance').<br>
230 * 1 if `val1' > `val2'.<br>
231 * -1 if `val1' < `val'.
232 */
233 protected int compare (double val1, double val2) {
234 double diff = Math.abs(val1 - val2);
235 if (diff <= tolerance) {
236 return 0;
237 } else if (val1 > val2) {
238 return 1;
239 } else {
240 return -1;
241 }
242 }
243
244 protected boolean _Invariant () {
245 return ((comparisonType == INTEGER_COMPARISON)
246 || (comparisonType == FLOAT_COMPARISON))
247 && ((lowerMode == INCLUSIVE) || (lowerMode == EXCLUSIVE))
248 && ((upperMode == INCLUSIVE) || (upperMode == EXCLUSIVE));
249 }
250 }