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 Stephen Colebourne
025: * @since 2.0
026: * @version $Id: FloatRange.java 437554 2006-08-28 06:21:41Z bayard $
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(
074: "The number must not be NaN");
075: }
076: this .min = number;
077: this .max = number;
078: }
079:
080: /**
081: * <p>Constructs a new <code>FloatRange</code> using the specified
082: * number as both the minimum and maximum in this range.</p>
083: *
084: * @param number the number to use for this range, must not
085: * be <code>null</code>
086: * @throws IllegalArgumentException if the number is <code>null</code>
087: * @throws IllegalArgumentException if the number is <code>NaN</code>
088: */
089: public FloatRange(Number number) {
090: super ();
091: if (number == null) {
092: throw new IllegalArgumentException(
093: "The number must not be null");
094: }
095: this .min = number.floatValue();
096: this .max = number.floatValue();
097: if (Float.isNaN(min) || Float.isNaN(max)) {
098: throw new IllegalArgumentException(
099: "The number must not be NaN");
100: }
101: if (number instanceof Float) {
102: this .minObject = (Float) number;
103: this .maxObject = (Float) number;
104: }
105: }
106:
107: /**
108: * <p>Constructs a new <code>FloatRange</code> with the specified
109: * minimum and maximum numbers (both inclusive).</p>
110: *
111: * <p>The arguments may be passed in the order (min,max) or (max,min). The
112: * getMinimum and getMaximum methods will return the correct values.</p>
113: *
114: * @param number1 first number that defines the edge of the range, inclusive
115: * @param number2 second number that defines the edge of the range, inclusive
116: * @throws IllegalArgumentException if either number is <code>NaN</code>
117: */
118: public FloatRange(float number1, float number2) {
119: super ();
120: if (Float.isNaN(number1) || Float.isNaN(number2)) {
121: throw new IllegalArgumentException(
122: "The numbers must not be NaN");
123: }
124: if (number2 < number1) {
125: this .min = number2;
126: this .max = number1;
127: } else {
128: this .min = number1;
129: this .max = number2;
130: }
131: }
132:
133: /**
134: * <p>Constructs a new <code>FloatRange</code> with the specified
135: * minimum and maximum numbers (both inclusive).</p>
136: *
137: * <p>The arguments may be passed in the order (min,max) or (max,min). The
138: * getMinimum and getMaximum methods will return the correct values.</p>
139: *
140: * @param number1 first number that defines the edge of the range, inclusive
141: * @param number2 second number that defines the edge of the range, inclusive
142: * @throws IllegalArgumentException if either number is <code>null</code>
143: * @throws IllegalArgumentException if either number is <code>NaN</code>
144: */
145: public FloatRange(Number number1, Number number2) {
146: super ();
147: if (number1 == null || number2 == null) {
148: throw new IllegalArgumentException(
149: "The numbers must not be null");
150: }
151: float number1val = number1.floatValue();
152: float number2val = number2.floatValue();
153: if (Float.isNaN(number1val) || Float.isNaN(number2val)) {
154: throw new IllegalArgumentException(
155: "The numbers must not be NaN");
156: }
157: if (number2val < number1val) {
158: this .min = number2val;
159: this .max = number1val;
160: if (number2 instanceof Float) {
161: this .minObject = (Float) number2;
162: }
163: if (number1 instanceof Float) {
164: this .maxObject = (Float) number1;
165: }
166: } else {
167: this .min = number1val;
168: this .max = number2val;
169: if (number1 instanceof Float) {
170: this .minObject = (Float) number1;
171: }
172: if (number2 instanceof Float) {
173: this .maxObject = (Float) number2;
174: }
175: }
176: }
177:
178: // Accessors
179: //--------------------------------------------------------------------
180:
181: /**
182: * <p>Returns the minimum number in this range.</p>
183: *
184: * @return the minimum number in this range
185: */
186: public Number getMinimumNumber() {
187: if (minObject == null) {
188: minObject = new Float(min);
189: }
190: return minObject;
191: }
192:
193: /**
194: * <p>Gets the minimum number in this range as a <code>long</code>.</p>
195: *
196: * <p>This conversion can lose information for large values or decimals.</p>
197: *
198: * @return the minimum number in this range
199: */
200: public long getMinimumLong() {
201: return (long) min;
202: }
203:
204: /**
205: * <p>Gets the minimum number in this range as a <code>int</code>.</p>
206: *
207: * <p>This conversion can lose information for large values or decimals.</p>
208: *
209: * @return the minimum number in this range
210: */
211: public int getMinimumInteger() {
212: return (int) min;
213: }
214:
215: /**
216: * <p>Gets the minimum number in this range as a <code>double</code>.</p>
217: *
218: * @return the minimum number in this range
219: */
220: public double getMinimumDouble() {
221: return min;
222: }
223:
224: /**
225: * <p>Gets the minimum number in this range as a <code>float</code>.</p>
226: *
227: * @return the minimum number in this range
228: */
229: public float getMinimumFloat() {
230: return min;
231: }
232:
233: /**
234: * <p>Returns the maximum number in this range.</p>
235: *
236: * @return the maximum number in this range
237: */
238: public Number getMaximumNumber() {
239: if (maxObject == null) {
240: maxObject = new Float(max);
241: }
242: return maxObject;
243: }
244:
245: /**
246: * <p>Gets the maximum number in this range as a <code>long</code>.</p>
247: *
248: * <p>This conversion can lose information for large values or decimals.</p>
249: *
250: * @return the maximum number in this range
251: */
252: public long getMaximumLong() {
253: return (long) max;
254: }
255:
256: /**
257: * <p>Gets the maximum number in this range as a <code>int</code>.</p>
258: *
259: * <p>This conversion can lose information for large values or decimals.</p>
260: *
261: * @return the maximum number in this range
262: */
263: public int getMaximumInteger() {
264: return (int) max;
265: }
266:
267: /**
268: * <p>Gets the maximum number in this range as a <code>double</code>.</p>
269: *
270: * @return the maximum number in this range
271: */
272: public double getMaximumDouble() {
273: return max;
274: }
275:
276: /**
277: * <p>Gets the maximum number in this range as a <code>float</code>.</p>
278: *
279: * @return the maximum number in this range
280: */
281: public float getMaximumFloat() {
282: return max;
283: }
284:
285: // Tests
286: //--------------------------------------------------------------------
287:
288: /**
289: * <p>Tests whether the specified <code>number</code> occurs within
290: * this range using <code>float</code> comparison.</p>
291: *
292: * <p><code>null</code> is handled and returns <code>false</code>.</p>
293: *
294: * @param number the number to test, may be <code>null</code>
295: * @return <code>true</code> if the specified number occurs within this range
296: */
297: public boolean containsNumber(Number number) {
298: if (number == null) {
299: return false;
300: }
301: return containsFloat(number.floatValue());
302: }
303:
304: /**
305: * <p>Tests whether the specified <code>float</code> occurs within
306: * this range using <code>float</code> comparison.</p>
307: *
308: * <p>This implementation overrides the superclass for performance as it is
309: * the most common case.</p>
310: *
311: * @param value the float to test
312: * @return <code>true</code> if the specified number occurs within this
313: * range by <code>float</code> comparison
314: */
315: public boolean containsFloat(float value) {
316: return value >= min && value <= max;
317: }
318:
319: // Range tests
320: //--------------------------------------------------------------------
321:
322: /**
323: * <p>Tests whether the specified range occurs entirely within this range
324: * using <code>float</code> comparison.</p>
325: *
326: * <p><code>null</code> is handled and returns <code>false</code>.</p>
327: *
328: * @param range the range to test, may be <code>null</code>
329: * @return <code>true</code> if the specified range occurs entirely within this range
330: * @throws IllegalArgumentException if the range is not of this type
331: */
332: public boolean containsRange(Range range) {
333: if (range == null) {
334: return false;
335: }
336: return containsFloat(range.getMinimumFloat())
337: && containsFloat(range.getMaximumFloat());
338: }
339:
340: /**
341: * <p>Tests whether the specified range overlaps with this range
342: * using <code>float</code> comparison.</p>
343: *
344: * <p><code>null</code> is handled and returns <code>false</code>.</p>
345: *
346: * @param range the range to test, may be <code>null</code>
347: * @return <code>true</code> if the specified range overlaps with this range
348: */
349: public boolean overlapsRange(Range range) {
350: if (range == null) {
351: return false;
352: }
353: return range.containsFloat(min) || range.containsFloat(max)
354: || containsFloat(range.getMinimumFloat());
355: }
356:
357: // Basics
358: //--------------------------------------------------------------------
359:
360: /**
361: * <p>Compares this range to another object to test if they are equal.</p>.
362: *
363: * <p>To be equal, the class, minimum and maximum must be equal.</p>
364: *
365: * @param obj the reference object with which to compare
366: * @return <code>true</code> if this object is equal
367: */
368: public boolean equals(Object obj) {
369: if (obj == this ) {
370: return true;
371: }
372: if (obj instanceof FloatRange == false) {
373: return false;
374: }
375: FloatRange range = (FloatRange) obj;
376: return (Float.floatToIntBits(min) == Float
377: .floatToIntBits(range.min) && Float.floatToIntBits(max) == Float
378: .floatToIntBits(range.max));
379: }
380:
381: /**
382: * <p>Gets a hashCode for the range.</p>
383: *
384: * @return a hash code value for this object
385: */
386: public int hashCode() {
387: if (hashCode == 0) {
388: hashCode = 17;
389: hashCode = 37 * hashCode + getClass().hashCode();
390: hashCode = 37 * hashCode + Float.floatToIntBits(min);
391: hashCode = 37 * hashCode + Float.floatToIntBits(max);
392: }
393: return hashCode;
394: }
395:
396: /**
397: * <p>Gets the range as a <code>String</code>.</p>
398: *
399: * <p>The format of the String is 'Range[<i>min</i>,<i>max</i>]'.</p>
400: *
401: * @return the <code>String</code> representation of this range
402: */
403: public String toString() {
404: if (toString == null) {
405: StringBuffer buf = new StringBuffer(32);
406: buf.append("Range[");
407: buf.append(min);
408: buf.append(',');
409: buf.append(max);
410: buf.append(']');
411: toString = buf.toString();
412: }
413: return toString;
414: }
415:
416: }
|