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>DoubleRange</code> represents an inclusive range of <code>double</code>s.</p> 023 * 024 * @author Apache Software Foundation 025 * @since 2.0 026 * @version $Id: DoubleRange.java 905636 2010-02-02 14:03:32Z niallp $ 027 */ 028 public final class DoubleRange extends Range implements Serializable { 029 030 /** 031 * Required for serialization support. 032 * 033 * @see java.io.Serializable 034 */ 035 private static final long serialVersionUID = 71849363892740L; 036 037 /** 038 * The minimum number in this range (inclusive). 039 */ 040 private final double min; 041 /** 042 * The maximum number in this range (inclusive). 043 */ 044 private final double max; 045 046 /** 047 * Cached output minObject (class is immutable). 048 */ 049 private transient Double minObject = null; 050 /** 051 * Cached output maxObject (class is immutable). 052 */ 053 private transient Double 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>DoubleRange</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 DoubleRange(double number) { 071 super(); 072 if (Double.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>DoubleRange</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 DoubleRange(Number number) { 089 super(); 090 if (number == null) { 091 throw new IllegalArgumentException("The number must not be null"); 092 } 093 this.min = number.doubleValue(); 094 this.max = number.doubleValue(); 095 if (Double.isNaN(min) || Double.isNaN(max)) { 096 throw new IllegalArgumentException("The number must not be NaN"); 097 } 098 if (number instanceof Double) { 099 this.minObject = (Double) number; 100 this.maxObject = (Double) number; 101 } 102 } 103 104 /** 105 * <p>Constructs a new <code>DoubleRange</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 DoubleRange(double number1, double number2) { 116 super(); 117 if (Double.isNaN(number1) || Double.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>DoubleRange</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 DoubleRange(Number number1, Number number2) { 142 super(); 143 if (number1 == null || number2 == null) { 144 throw new IllegalArgumentException("The numbers must not be null"); 145 } 146 double number1val = number1.doubleValue(); 147 double number2val = number2.doubleValue(); 148 if (Double.isNaN(number1val) || Double.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 Double) { 155 this.minObject = (Double) number2; 156 } 157 if (number1 instanceof Double) { 158 this.maxObject = (Double) number1; 159 } 160 } else { 161 this.min = number1val; 162 this.max = number2val; 163 if (number1 instanceof Double) { 164 this.minObject = (Double) number1; 165 } 166 if (number2 instanceof Double) { 167 this.maxObject = (Double) 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 Double(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 * <p>This conversion can lose information for large values.</p> 222 * 223 * @return the minimum number in this range 224 */ 225 public float getMinimumFloat() { 226 return (float) min; 227 } 228 229 /** 230 * <p>Returns the maximum number in this range.</p> 231 * 232 * @return the maximum number in this range 233 */ 234 public Number getMaximumNumber() { 235 if (maxObject == null) { 236 maxObject = new Double(max); 237 } 238 return maxObject; 239 } 240 241 /** 242 * <p>Gets the maximum number in this range as a <code>long</code>.</p> 243 * 244 * <p>This conversion can lose information for large values or decimals.</p> 245 * 246 * @return the maximum number in this range 247 */ 248 public long getMaximumLong() { 249 return (long) max; 250 } 251 252 /** 253 * <p>Gets the maximum number in this range as a <code>int</code>.</p> 254 * 255 * <p>This conversion can lose information for large values or decimals.</p> 256 * 257 * @return the maximum number in this range 258 */ 259 public int getMaximumInteger() { 260 return (int) max; 261 } 262 263 /** 264 * <p>Gets the maximum number in this range as a <code>double</code>.</p> 265 * 266 * @return the maximum number in this range 267 */ 268 public double getMaximumDouble() { 269 return max; 270 } 271 272 /** 273 * <p>Gets the maximum number in this range as a <code>float</code>.</p> 274 * 275 * <p>This conversion can lose information for large values.</p> 276 * 277 * @return the maximum number in this range 278 */ 279 public float getMaximumFloat() { 280 return (float) max; 281 } 282 283 // Tests 284 //-------------------------------------------------------------------- 285 286 /** 287 * <p>Tests whether the specified <code>number</code> occurs within 288 * this range using <code>double</code> comparison.</p> 289 * 290 * <p><code>null</code> is handled and returns <code>false</code>.</p> 291 * 292 * @param number the number to test, may be <code>null</code> 293 * @return <code>true</code> if the specified number occurs within this range 294 */ 295 public boolean containsNumber(Number number) { 296 if (number == null) { 297 return false; 298 } 299 return containsDouble(number.doubleValue()); 300 } 301 302 /** 303 * <p>Tests whether the specified <code>double</code> occurs within 304 * this range using <code>double</code> comparison.</p> 305 * 306 * <p>This implementation overrides the superclass for performance as it is 307 * the most common case.</p> 308 * 309 * @param value the double to test 310 * @return <code>true</code> if the specified number occurs within this 311 * range by <code>double</code> comparison 312 */ 313 public boolean containsDouble(double value) { 314 return value >= min && value <= max; 315 } 316 317 // Range tests 318 //-------------------------------------------------------------------- 319 320 /** 321 * <p>Tests whether the specified range occurs entirely within this range 322 * using <code>double</code> comparison.</p> 323 * 324 * <p><code>null</code> is handled and returns <code>false</code>.</p> 325 * 326 * @param range the range to test, may be <code>null</code> 327 * @return <code>true</code> if the specified range occurs entirely within this range 328 * @throws IllegalArgumentException if the range is not of this type 329 */ 330 public boolean containsRange(Range range) { 331 if (range == null) { 332 return false; 333 } 334 return containsDouble(range.getMinimumDouble()) 335 && containsDouble(range.getMaximumDouble()); 336 } 337 338 /** 339 * <p>Tests whether the specified range overlaps with this range 340 * using <code>double</code> comparison.</p> 341 * 342 * <p><code>null</code> is handled and returns <code>false</code>.</p> 343 * 344 * @param range the range to test, may be <code>null</code> 345 * @return <code>true</code> if the specified range overlaps with this range 346 */ 347 public boolean overlapsRange(Range range) { 348 if (range == null) { 349 return false; 350 } 351 return range.containsDouble(min) 352 || range.containsDouble(max) 353 || containsDouble(range.getMinimumDouble()); 354 } 355 356 // Basics 357 //-------------------------------------------------------------------- 358 359 /** 360 * <p>Compares this range to another object to test if they are equal.</p>. 361 * 362 * <p>To be equal, the class, minimum and maximum must be equal.</p> 363 * 364 * @param obj the reference object with which to compare 365 * @return <code>true</code> if this object is equal 366 */ 367 public boolean equals(Object obj) { 368 if (obj == this) { 369 return true; 370 } 371 if (obj instanceof DoubleRange == false) { 372 return false; 373 } 374 DoubleRange range = (DoubleRange) obj; 375 return (Double.doubleToLongBits(min) == Double.doubleToLongBits(range.min) && 376 Double.doubleToLongBits(max) == Double.doubleToLongBits(range.max)); 377 } 378 379 /** 380 * <p>Gets a hashCode for the range.</p> 381 * 382 * @return a hash code value for this object 383 */ 384 public int hashCode() { 385 if (hashCode == 0) { 386 hashCode = 17; 387 hashCode = 37 * hashCode + getClass().hashCode(); 388 long lng = Double.doubleToLongBits(min); 389 hashCode = 37 * hashCode + ((int) (lng ^ (lng >> 32))); 390 lng = Double.doubleToLongBits(max); 391 hashCode = 37 * hashCode + ((int) (lng ^ (lng >> 32))); 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 }