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 }