001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.lang.math;
018
019 import java.io.Serializable;
020
021 /**
022 * <p><code>FloatRange</code> represents an inclusive range of <code>float</code>s.</p>
023 *
024 * @author Apache Software Foundation
025 * @since 2.0
026 * @version $Id: FloatRange.java 905636 2010-02-02 14:03:32Z niallp $
027 */
028 public final class FloatRange extends Range implements Serializable {
029
030 /**
031 * Required for serialization support.
032 *
033 * @see java.io.Serializable
034 */
035 private static final long serialVersionUID = 71849363892750L;
036
037 /**
038 * The minimum number in this range (inclusive).
039 */
040 private final float min;
041 /**
042 * The maximum number in this range (inclusive).
043 */
044 private final float max;
045
046 /**
047 * Cached output minObject (class is immutable).
048 */
049 private transient Float minObject = null;
050 /**
051 * Cached output maxObject (class is immutable).
052 */
053 private transient Float maxObject = null;
054 /**
055 * Cached output hashCode (class is immutable).
056 */
057 private transient int hashCode = 0;
058 /**
059 * Cached output toString (class is immutable).
060 */
061 private transient String toString = null;
062
063 /**
064 * <p>Constructs a new <code>FloatRange</code> using the specified
065 * number as both the minimum and maximum in this range.</p>
066 *
067 * @param number the number to use for this range
068 * @throws IllegalArgumentException if the number is <code>NaN</code>
069 */
070 public FloatRange(float number) {
071 super();
072 if (Float.isNaN(number)) {
073 throw new IllegalArgumentException("The number must not be NaN");
074 }
075 this.min = number;
076 this.max = number;
077 }
078
079 /**
080 * <p>Constructs a new <code>FloatRange</code> using the specified
081 * number as both the minimum and maximum in this range.</p>
082 *
083 * @param number the number to use for this range, must not
084 * be <code>null</code>
085 * @throws IllegalArgumentException if the number is <code>null</code>
086 * @throws IllegalArgumentException if the number is <code>NaN</code>
087 */
088 public FloatRange(Number number) {
089 super();
090 if (number == null) {
091 throw new IllegalArgumentException("The number must not be null");
092 }
093 this.min = number.floatValue();
094 this.max = number.floatValue();
095 if (Float.isNaN(min) || Float.isNaN(max)) {
096 throw new IllegalArgumentException("The number must not be NaN");
097 }
098 if (number instanceof Float) {
099 this.minObject = (Float) number;
100 this.maxObject = (Float) number;
101 }
102 }
103
104 /**
105 * <p>Constructs a new <code>FloatRange</code> with the specified
106 * minimum and maximum numbers (both inclusive).</p>
107 *
108 * <p>The arguments may be passed in the order (min,max) or (max,min). The
109 * getMinimum and getMaximum methods will return the correct values.</p>
110 *
111 * @param number1 first number that defines the edge of the range, inclusive
112 * @param number2 second number that defines the edge of the range, inclusive
113 * @throws IllegalArgumentException if either number is <code>NaN</code>
114 */
115 public FloatRange(float number1, float number2) {
116 super();
117 if (Float.isNaN(number1) || Float.isNaN(number2)) {
118 throw new IllegalArgumentException("The numbers must not be NaN");
119 }
120 if (number2 < number1) {
121 this.min = number2;
122 this.max = number1;
123 } else {
124 this.min = number1;
125 this.max = number2;
126 }
127 }
128
129 /**
130 * <p>Constructs a new <code>FloatRange</code> with the specified
131 * minimum and maximum numbers (both inclusive).</p>
132 *
133 * <p>The arguments may be passed in the order (min,max) or (max,min). The
134 * getMinimum and getMaximum methods will return the correct values.</p>
135 *
136 * @param number1 first number that defines the edge of the range, inclusive
137 * @param number2 second number that defines the edge of the range, inclusive
138 * @throws IllegalArgumentException if either number is <code>null</code>
139 * @throws IllegalArgumentException if either number is <code>NaN</code>
140 */
141 public FloatRange(Number number1, Number number2) {
142 super();
143 if (number1 == null || number2 == null) {
144 throw new IllegalArgumentException("The numbers must not be null");
145 }
146 float number1val = number1.floatValue();
147 float number2val = number2.floatValue();
148 if (Float.isNaN(number1val) || Float.isNaN(number2val)) {
149 throw new IllegalArgumentException("The numbers must not be NaN");
150 }
151 if (number2val < number1val) {
152 this.min = number2val;
153 this.max = number1val;
154 if (number2 instanceof Float) {
155 this.minObject = (Float) number2;
156 }
157 if (number1 instanceof Float) {
158 this.maxObject = (Float) number1;
159 }
160 } else {
161 this.min = number1val;
162 this.max = number2val;
163 if (number1 instanceof Float) {
164 this.minObject = (Float) number1;
165 }
166 if (number2 instanceof Float) {
167 this.maxObject = (Float) number2;
168 }
169 }
170 }
171
172 // Accessors
173 //--------------------------------------------------------------------
174
175 /**
176 * <p>Returns the minimum number in this range.</p>
177 *
178 * @return the minimum number in this range
179 */
180 public Number getMinimumNumber() {
181 if (minObject == null) {
182 minObject = new Float(min);
183 }
184 return minObject;
185 }
186
187 /**
188 * <p>Gets the minimum number in this range as a <code>long</code>.</p>
189 *
190 * <p>This conversion can lose information for large values or decimals.</p>
191 *
192 * @return the minimum number in this range
193 */
194 public long getMinimumLong() {
195 return (long) min;
196 }
197
198 /**
199 * <p>Gets the minimum number in this range as a <code>int</code>.</p>
200 *
201 * <p>This conversion can lose information for large values or decimals.</p>
202 *
203 * @return the minimum number in this range
204 */
205 public int getMinimumInteger() {
206 return (int) min;
207 }
208
209 /**
210 * <p>Gets the minimum number in this range as a <code>double</code>.</p>
211 *
212 * @return the minimum number in this range
213 */
214 public double getMinimumDouble() {
215 return min;
216 }
217
218 /**
219 * <p>Gets the minimum number in this range as a <code>float</code>.</p>
220 *
221 * @return the minimum number in this range
222 */
223 public float getMinimumFloat() {
224 return min;
225 }
226
227 /**
228 * <p>Returns the maximum number in this range.</p>
229 *
230 * @return the maximum number in this range
231 */
232 public Number getMaximumNumber() {
233 if (maxObject == null) {
234 maxObject = new Float(max);
235 }
236 return maxObject;
237 }
238
239 /**
240 * <p>Gets the maximum number in this range as a <code>long</code>.</p>
241 *
242 * <p>This conversion can lose information for large values or decimals.</p>
243 *
244 * @return the maximum number in this range
245 */
246 public long getMaximumLong() {
247 return (long) max;
248 }
249
250 /**
251 * <p>Gets the maximum number in this range as a <code>int</code>.</p>
252 *
253 * <p>This conversion can lose information for large values or decimals.</p>
254 *
255 * @return the maximum number in this range
256 */
257 public int getMaximumInteger() {
258 return (int) max;
259 }
260
261 /**
262 * <p>Gets the maximum number in this range as a <code>double</code>.</p>
263 *
264 * @return the maximum number in this range
265 */
266 public double getMaximumDouble() {
267 return max;
268 }
269
270 /**
271 * <p>Gets the maximum number in this range as a <code>float</code>.</p>
272 *
273 * @return the maximum number in this range
274 */
275 public float getMaximumFloat() {
276 return max;
277 }
278
279 // Tests
280 //--------------------------------------------------------------------
281
282 /**
283 * <p>Tests whether the specified <code>number</code> occurs within
284 * this range using <code>float</code> comparison.</p>
285 *
286 * <p><code>null</code> is handled and returns <code>false</code>.</p>
287 *
288 * @param number the number to test, may be <code>null</code>
289 * @return <code>true</code> if the specified number occurs within this range
290 */
291 public boolean containsNumber(Number number) {
292 if (number == null) {
293 return false;
294 }
295 return containsFloat(number.floatValue());
296 }
297
298 /**
299 * <p>Tests whether the specified <code>float</code> occurs within
300 * this range using <code>float</code> comparison.</p>
301 *
302 * <p>This implementation overrides the superclass for performance as it is
303 * the most common case.</p>
304 *
305 * @param value the float to test
306 * @return <code>true</code> if the specified number occurs within this
307 * range by <code>float</code> comparison
308 */
309 public boolean containsFloat(float value) {
310 return value >= min && value <= max;
311 }
312
313 // Range tests
314 //--------------------------------------------------------------------
315
316 /**
317 * <p>Tests whether the specified range occurs entirely within this range
318 * using <code>float</code> comparison.</p>
319 *
320 * <p><code>null</code> is handled and returns <code>false</code>.</p>
321 *
322 * @param range the range to test, may be <code>null</code>
323 * @return <code>true</code> if the specified range occurs entirely within this range
324 * @throws IllegalArgumentException if the range is not of this type
325 */
326 public boolean containsRange(Range range) {
327 if (range == null) {
328 return false;
329 }
330 return containsFloat(range.getMinimumFloat()) &&
331 containsFloat(range.getMaximumFloat());
332 }
333
334 /**
335 * <p>Tests whether the specified range overlaps with this range
336 * using <code>float</code> comparison.</p>
337 *
338 * <p><code>null</code> is handled and returns <code>false</code>.</p>
339 *
340 * @param range the range to test, may be <code>null</code>
341 * @return <code>true</code> if the specified range overlaps with this range
342 */
343 public boolean overlapsRange(Range range) {
344 if (range == null) {
345 return false;
346 }
347 return range.containsFloat(min) ||
348 range.containsFloat(max) ||
349 containsFloat(range.getMinimumFloat());
350 }
351
352 // Basics
353 //--------------------------------------------------------------------
354
355 /**
356 * <p>Compares this range to another object to test if they are equal.</p>.
357 *
358 * <p>To be equal, the class, minimum and maximum must be equal.</p>
359 *
360 * @param obj the reference object with which to compare
361 * @return <code>true</code> if this object is equal
362 */
363 public boolean equals(Object obj) {
364 if (obj == this) {
365 return true;
366 }
367 if (obj instanceof FloatRange == false) {
368 return false;
369 }
370 FloatRange range = (FloatRange) obj;
371 return (Float.floatToIntBits(min) == Float.floatToIntBits(range.min) &&
372 Float.floatToIntBits(max) == Float.floatToIntBits(range.max));
373 }
374
375 /**
376 * <p>Gets a hashCode for the range.</p>
377 *
378 * @return a hash code value for this object
379 */
380 public int hashCode() {
381 if (hashCode == 0) {
382 hashCode = 17;
383 hashCode = 37 * hashCode + getClass().hashCode();
384 hashCode = 37 * hashCode + Float.floatToIntBits(min);
385 hashCode = 37 * hashCode + Float.floatToIntBits(max);
386 }
387 return hashCode;
388 }
389
390 /**
391 * <p>Gets the range as a <code>String</code>.</p>
392 *
393 * <p>The format of the String is 'Range[<i>min</i>,<i>max</i>]'.</p>
394 *
395 * @return the <code>String</code> representation of this range
396 */
397 public String toString() {
398 if (toString == null) {
399 StringBuffer buf = new StringBuffer(32);
400 buf.append("Range[");
401 buf.append(min);
402 buf.append(',');
403 buf.append(max);
404 buf.append(']');
405 toString = buf.toString();
406 }
407 return toString;
408 }
409
410 }