1. /* ====================================================================
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 2002-2003 The Apache Software Foundation. All rights
  5. * reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if
  20. * any, must include the following acknowledgement:
  21. * "This product includes software developed by the
  22. * Apache Software Foundation (http://www.apache.org/)."
  23. * Alternately, this acknowledgement may appear in the software itself,
  24. * if and wherever such third-party acknowledgements normally appear.
  25. *
  26. * 4. The names "The Jakarta Project", "Commons", and "Apache Software
  27. * Foundation" must not be used to endorse or promote products derived
  28. * from this software without prior written permission. For written
  29. * permission, please contact apache@apache.org.
  30. *
  31. * 5. Products derived from this software may not be called "Apache"
  32. * nor may "Apache" appear in their names without prior written
  33. * permission of the Apache Software Foundation.
  34. *
  35. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46. * SUCH DAMAGE.
  47. * ====================================================================
  48. *
  49. * This software consists of voluntary contributions made by many
  50. * individuals on behalf of the Apache Software Foundation. For more
  51. * information on the Apache Software Foundation, please see
  52. * <http://www.apache.org/>.
  53. */
  54. package org.apache.commons.lang.math;
  55. import java.io.Serializable;
  56. /**
  57. * <p><code>DoubleRange</code> represents an inclusive range of <code>double</code>s.</p>
  58. *
  59. * @author Stephen Colebourne
  60. * @since 2.0
  61. * @version $Id: DoubleRange.java,v 1.5 2003/08/18 02:22:24 bayard Exp $
  62. */
  63. public final class DoubleRange extends Range implements Serializable {
  64. private static final long serialVersionUID = 71849363892740L;
  65. /**
  66. * The minimum number in this range (inclusive).
  67. */
  68. private final double min;
  69. /**
  70. * The maximum number in this range (inclusive).
  71. */
  72. private final double max;
  73. /**
  74. * Cached output minObject (class is immutable).
  75. */
  76. private transient Double minObject = null;
  77. /**
  78. * Cached output maxObject (class is immutable).
  79. */
  80. private transient Double maxObject = null;
  81. /**
  82. * Cached output hashCode (class is immutable).
  83. */
  84. private transient int hashCode = 0;
  85. /**
  86. * Cached output toString (class is immutable).
  87. */
  88. private transient String toString = null;
  89. /**
  90. * <p>Constructs a new <code>DoubleRange</code> using the specified
  91. * number as both the minimum and maximum in this range.</p>
  92. *
  93. * @param number the number to use for this range
  94. * @throws IllegalArgumentException if the number is <code>NaN</code>
  95. */
  96. public DoubleRange(double number) {
  97. super();
  98. if (Double.isNaN(number)) {
  99. throw new IllegalArgumentException("The number must not be NaN");
  100. }
  101. this.min = number;
  102. this.max = number;
  103. }
  104. /**
  105. * <p>Constructs a new <code>DoubleRange</code> using the specified
  106. * number as both the minimum and maximum in this range.</p>
  107. *
  108. * @param number the number to use for this range, must not
  109. * be <code>null</code>
  110. * @throws IllegalArgumentException if the number is <code>null</code>
  111. * @throws IllegalArgumentException if the number is <code>NaN</code>
  112. */
  113. public DoubleRange(Number number) {
  114. super();
  115. if (number == null) {
  116. throw new IllegalArgumentException("The number must not be null");
  117. }
  118. this.min = number.doubleValue();
  119. this.max = number.doubleValue();
  120. if (Double.isNaN(min) || Double.isNaN(max)) {
  121. throw new IllegalArgumentException("The number must not be NaN");
  122. }
  123. if (number instanceof Double) {
  124. this.minObject = (Double) number;
  125. this.maxObject = (Double) number;
  126. }
  127. }
  128. /**
  129. * <p>Constructs a new <code>DoubleRange</code> with the specified
  130. * minimum and maximum numbers (both inclusive).</p>
  131. *
  132. * <p>The arguments may be passed in the order (min,max) or (max,min). The
  133. * getMinimum and getMaximum methods will return the correct values.</p>
  134. *
  135. * @param number1 first number that defines the edge of the range, inclusive
  136. * @param number2 second number that defines the edge of the range, inclusive
  137. * @throws IllegalArgumentException if either number is <code>NaN</code>
  138. */
  139. public DoubleRange(double number1, double number2) {
  140. super();
  141. if (Double.isNaN(number1) || Double.isNaN(number2)) {
  142. throw new IllegalArgumentException("The numbers must not be NaN");
  143. }
  144. if (number2 < number1) {
  145. this.min = number2;
  146. this.max = number1;
  147. } else {
  148. this.min = number1;
  149. this.max = number2;
  150. }
  151. }
  152. /**
  153. * <p>Constructs a new <code>DoubleRange</code> with the specified
  154. * minimum and maximum numbers (both inclusive).</p>
  155. *
  156. * <p>The arguments may be passed in the order (min,max) or (max,min). The
  157. * getMinimum and getMaximum methods will return the correct values.</p>
  158. *
  159. * @param number1 first number that defines the edge of the range, inclusive
  160. * @param number2 second number that defines the edge of the range, inclusive
  161. * @throws IllegalArgumentException if either number is <code>null</code>
  162. * @throws IllegalArgumentException if either number is <code>NaN</code>
  163. */
  164. public DoubleRange(Number number1, Number number2) {
  165. super();
  166. if (number1 == null || number2 == null) {
  167. throw new IllegalArgumentException("The numbers must not be null");
  168. }
  169. double number1val = number1.doubleValue();
  170. double number2val = number2.doubleValue();
  171. if (Double.isNaN(number1val) || Double.isNaN(number2val)) {
  172. throw new IllegalArgumentException("The numbers must not be NaN");
  173. }
  174. if (number2val < number1val) {
  175. this.min = number2val;
  176. this.max = number1val;
  177. if (number2 instanceof Double) {
  178. this.minObject = (Double) number2;
  179. }
  180. if (number1 instanceof Double) {
  181. this.maxObject = (Double) number1;
  182. }
  183. } else {
  184. this.min = number1val;
  185. this.max = number2val;
  186. if (number1 instanceof Double) {
  187. this.minObject = (Double) number1;
  188. }
  189. if (number2 instanceof Double) {
  190. this.maxObject = (Double) number2;
  191. }
  192. }
  193. }
  194. // Accessors
  195. //--------------------------------------------------------------------
  196. /**
  197. * <p>Returns the minimum number in this range.</p>
  198. *
  199. * @return the minimum number in this range
  200. */
  201. public Number getMinimumNumber() {
  202. if (minObject == null) {
  203. minObject = new Double(min);
  204. }
  205. return minObject;
  206. }
  207. /**
  208. * <p>Gets the minimum number in this range as a <code>long</code>.</p>
  209. *
  210. * <p>This conversion can lose information for large values or decimals.</p>
  211. *
  212. * @return the minimum number in this range
  213. */
  214. public long getMinimumLong() {
  215. return (long) min;
  216. }
  217. /**
  218. * <p>Gets the minimum number in this range as a <code>int</code>.</p>
  219. *
  220. * <p>This conversion can lose information for large values or decimals.</p>
  221. *
  222. * @return the minimum number in this range
  223. */
  224. public int getMinimumInteger() {
  225. return (int) min;
  226. }
  227. /**
  228. * <p>Gets the minimum number in this range as a <code>double</code>.</p>
  229. *
  230. * @return the minimum number in this range
  231. */
  232. public double getMinimumDouble() {
  233. return min;
  234. }
  235. /**
  236. * <p>Gets the minimum number in this range as a <code>float</code>.</p>
  237. *
  238. * <p>This conversion can lose information for large values.</p>
  239. *
  240. * @return the minimum number in this range
  241. */
  242. public float getMinimumFloat() {
  243. return (float) min;
  244. }
  245. /**
  246. * <p>Returns the maximum number in this range.</p>
  247. *
  248. * @return the maximum number in this range
  249. */
  250. public Number getMaximumNumber() {
  251. if (maxObject == null) {
  252. maxObject = new Double(max);
  253. }
  254. return maxObject;
  255. }
  256. /**
  257. * <p>Gets the maximum number in this range as a <code>long</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 long getMaximumLong() {
  264. return (long) max;
  265. }
  266. /**
  267. * <p>Gets the maximum number in this range as a <code>int</code>.</p>
  268. *
  269. * <p>This conversion can lose information for large values or decimals.</p>
  270. *
  271. * @return the maximum number in this range
  272. */
  273. public int getMaximumInteger() {
  274. return (int) max;
  275. }
  276. /**
  277. * <p>Gets the maximum number in this range as a <code>double</code>.</p>
  278. *
  279. * @return the maximum number in this range
  280. */
  281. public double getMaximumDouble() {
  282. return max;
  283. }
  284. /**
  285. * <p>Gets the maximum number in this range as a <code>float</code>.</p>
  286. *
  287. * <p>This conversion can lose information for large values.</p>
  288. *
  289. * @return the maximum number in this range
  290. */
  291. public float getMaximumFloat() {
  292. return (float) max;
  293. }
  294. // Tests
  295. //--------------------------------------------------------------------
  296. /**
  297. * <p>Tests whether the specified <code>number</code> occurs within
  298. * this range using <code>double</code> comparison.</p>
  299. *
  300. * <p><code>null</code> is handled and returns <code>false</code>.</p>
  301. *
  302. * @param number the number to test, may be <code>null</code>
  303. * @return <code>true</code> if the specified number occurs within this range
  304. */
  305. public boolean containsNumber(Number number) {
  306. if (number == null) {
  307. return false;
  308. }
  309. return containsDouble(number.doubleValue());
  310. }
  311. /**
  312. * <p>Tests whether the specified <code>double</code> occurs within
  313. * this range using <code>double</code> comparison.</p>
  314. *
  315. * <p>This implementation overrides the superclass for performance as it is
  316. * the most common case.</p>
  317. *
  318. * @param value the double to test
  319. * @return <code>true</code> if the specified number occurs within this
  320. * range by <code>double</code> comparison
  321. */
  322. public boolean containsDouble(double value) {
  323. return (value >= min && value <= max);
  324. }
  325. // Range tests
  326. //--------------------------------------------------------------------
  327. /**
  328. * <p>Tests whether the specified range occurs entirely within this range
  329. * using <code>double</code> comparison.</p>
  330. *
  331. * <p><code>null</code> is handled and returns <code>false</code>.</p>
  332. *
  333. * @param range the range to test, may be <code>null</code>
  334. * @return <code>true</code> if the specified range occurs entirely within this range
  335. * @throws IllegalArgumentException if the range is not of this type
  336. */
  337. public boolean containsRange(Range range) {
  338. if (range == null) {
  339. return false;
  340. }
  341. return containsDouble(range.getMinimumDouble())
  342. && containsDouble(range.getMaximumDouble());
  343. }
  344. /**
  345. * <p>Tests whether the specified range overlaps with this range
  346. * using <code>double</code> comparison.</p>
  347. *
  348. * <p><code>null</code> is handled and returns <code>false</code>.</p>
  349. *
  350. * @param range the range to test, may be <code>null</code>
  351. * @return <code>true</code> if the specified range overlaps with this range
  352. */
  353. public boolean overlapsRange(Range range) {
  354. if (range == null) {
  355. return false;
  356. }
  357. return range.containsDouble(min)
  358. || range.containsDouble(max)
  359. || containsDouble(range.getMinimumDouble());
  360. }
  361. // Basics
  362. //--------------------------------------------------------------------
  363. /**
  364. * <p>Compares this range to another object to test if they are equal.</p>.
  365. *
  366. * <p>To be equal, the class, minimum and maximum must be equal.</p>
  367. *
  368. * @param obj the reference object with which to compare
  369. * @return <code>true</code> if this object is equal
  370. */
  371. public boolean equals(Object obj) {
  372. if (obj == this) {
  373. return true;
  374. }
  375. if (obj instanceof DoubleRange == false) {
  376. return false;
  377. }
  378. DoubleRange range = (DoubleRange) obj;
  379. return (Double.doubleToLongBits(min) == Double.doubleToLongBits(range.min) &&
  380. Double.doubleToLongBits(max) == Double.doubleToLongBits(range.max));
  381. }
  382. /**
  383. * <p>Gets a hashCode for the range.</p>
  384. *
  385. * @return a hash code value for this object
  386. */
  387. public int hashCode() {
  388. if (hashCode == 0) {
  389. hashCode = 17;
  390. hashCode = 37 * hashCode + getClass().hashCode();
  391. long lng = Double.doubleToLongBits(min);
  392. hashCode = 37 * hashCode + ((int) (lng ^ (lng >> 32)));
  393. lng = Double.doubleToLongBits(max);
  394. hashCode = 37 * hashCode + ((int) (lng ^ (lng >> 32)));
  395. }
  396. return hashCode;
  397. }
  398. /**
  399. * <p>Gets the range as a <code>String</code>.</p>
  400. *
  401. * <p>The format of the String is 'Range[<i>min</i>,<i>max</i>]'.</p>
  402. *
  403. * @return the <code>String</code> representation of this range
  404. */
  405. public String toString() {
  406. if (toString == null) {
  407. StringBuffer buf = new StringBuffer(32);
  408. buf.append("Range[");
  409. buf.append(min);
  410. buf.append(',');
  411. buf.append(max);
  412. buf.append(']');
  413. toString = buf.toString();
  414. }
  415. return toString;
  416. }
  417. }