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>FloatRange</code> represents an inclusive range of <code>float</code>s.</p>
  58. *
  59. * @author Stephen Colebourne
  60. * @since 2.0
  61. * @version $Id: FloatRange.java,v 1.5 2003/08/18 02:22:24 bayard Exp $
  62. */
  63. public final class FloatRange extends Range implements Serializable {
  64. private static final long serialVersionUID = 71849363892750L;
  65. /**
  66. * The minimum number in this range (inclusive).
  67. */
  68. private final float min;
  69. /**
  70. * The maximum number in this range (inclusive).
  71. */
  72. private final float max;
  73. /**
  74. * Cached output minObject (class is immutable).
  75. */
  76. private transient Float minObject = null;
  77. /**
  78. * Cached output maxObject (class is immutable).
  79. */
  80. private transient Float 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>FloatRange</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 FloatRange(float number) {
  97. super();
  98. if (Float.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>FloatRange</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 FloatRange(Number number) {
  114. super();
  115. if (number == null) {
  116. throw new IllegalArgumentException("The number must not be null");
  117. }
  118. this.min = number.floatValue();
  119. this.max = number.floatValue();
  120. if (Float.isNaN(min) || Float.isNaN(max)) {
  121. throw new IllegalArgumentException("The number must not be NaN");
  122. }
  123. if (number instanceof Float) {
  124. this.minObject = (Float) number;
  125. this.maxObject = (Float) number;
  126. }
  127. }
  128. /**
  129. * <p>Constructs a new <code>FloatRange</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 FloatRange(float number1, float number2) {
  140. super();
  141. if (Float.isNaN(number1) || Float.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>FloatRange</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 FloatRange(Number number1, Number number2) {
  165. super();
  166. if (number1 == null || number2 == null) {
  167. throw new IllegalArgumentException("The numbers must not be null");
  168. }
  169. float number1val = number1.floatValue();
  170. float number2val = number2.floatValue();
  171. if (Float.isNaN(number1val) || Float.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 Float) {
  178. this.minObject = (Float) number2;
  179. }
  180. if (number1 instanceof Float) {
  181. this.maxObject = (Float) number1;
  182. }
  183. } else {
  184. this.min = number1val;
  185. this.max = number2val;
  186. if (number1 instanceof Float) {
  187. this.minObject = (Float) number1;
  188. }
  189. if (number2 instanceof Float) {
  190. this.maxObject = (Float) 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 Float(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. * @return the minimum number in this range
  239. */
  240. public float getMinimumFloat() {
  241. return min;
  242. }
  243. /**
  244. * <p>Returns the maximum number in this range.</p>
  245. *
  246. * @return the maximum number in this range
  247. */
  248. public Number getMaximumNumber() {
  249. if (maxObject == null) {
  250. maxObject = new Float(max);
  251. }
  252. return maxObject;
  253. }
  254. /**
  255. * <p>Gets the maximum number in this range as a <code>long</code>.</p>
  256. *
  257. * <p>This conversion can lose information for large values or decimals.</p>
  258. *
  259. * @return the maximum number in this range
  260. */
  261. public long getMaximumLong() {
  262. return (long) max;
  263. }
  264. /**
  265. * <p>Gets the maximum number in this range as a <code>int</code>.</p>
  266. *
  267. * <p>This conversion can lose information for large values or decimals.</p>
  268. *
  269. * @return the maximum number in this range
  270. */
  271. public int getMaximumInteger() {
  272. return (int) max;
  273. }
  274. /**
  275. * <p>Gets the maximum number in this range as a <code>double</code>.</p>
  276. *
  277. * @return the maximum number in this range
  278. */
  279. public double getMaximumDouble() {
  280. return max;
  281. }
  282. /**
  283. * <p>Gets the maximum number in this range as a <code>float</code>.</p>
  284. *
  285. * @return the maximum number in this range
  286. */
  287. public float getMaximumFloat() {
  288. return max;
  289. }
  290. // Tests
  291. //--------------------------------------------------------------------
  292. /**
  293. * <p>Tests whether the specified <code>number</code> occurs within
  294. * this range using <code>float</code> comparison.</p>
  295. *
  296. * <p><code>null</code> is handled and returns <code>false</code>.</p>
  297. *
  298. * @param number the number to test, may be <code>null</code>
  299. * @return <code>true</code> if the specified number occurs within this range
  300. */
  301. public boolean containsNumber(Number number) {
  302. if (number == null) {
  303. return false;
  304. }
  305. return containsFloat(number.floatValue());
  306. }
  307. /**
  308. * <p>Tests whether the specified <code>float</code> occurs within
  309. * this range using <code>float</code> comparison.</p>
  310. *
  311. * <p>This implementation overrides the superclass for performance as it is
  312. * the most common case.</p>
  313. *
  314. * @param value the float to test
  315. * @return <code>true</code> if the specified number occurs within this
  316. * range by <code>float</code> comparison
  317. */
  318. public boolean containsFloat(float value) {
  319. return (value >= min && value <= max);
  320. }
  321. // Range tests
  322. //--------------------------------------------------------------------
  323. /**
  324. * <p>Tests whether the specified range occurs entirely within this range
  325. * using <code>float</code> comparison.</p>
  326. *
  327. * <p><code>null</code> is handled and returns <code>false</code>.</p>
  328. *
  329. * @param range the range to test, may be <code>null</code>
  330. * @return <code>true</code> if the specified range occurs entirely within this range
  331. * @throws IllegalArgumentException if the range is not of this type
  332. */
  333. public boolean containsRange(Range range) {
  334. if (range == null) {
  335. return false;
  336. }
  337. return containsFloat(range.getMinimumFloat()) &&
  338. containsFloat(range.getMaximumFloat());
  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) ||
  354. range.containsFloat(max) ||
  355. containsFloat(range.getMinimumFloat());
  356. }
  357. // Basics
  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 FloatRange == false) {
  372. return false;
  373. }
  374. FloatRange range = (FloatRange) obj;
  375. return (Float.floatToIntBits(min) == Float.floatToIntBits(range.min) &&
  376. Float.floatToIntBits(max) == Float.floatToIntBits(range.max));
  377. }
  378. /**
  379. * <p>Gets a hashCode for the range.</p>
  380. *
  381. * @return a hash code value for this object
  382. */
  383. public int hashCode() {
  384. if (hashCode == 0) {
  385. hashCode = 17;
  386. hashCode = 37 * hashCode + getClass().hashCode();
  387. hashCode = 37 * hashCode + Float.floatToIntBits(min);
  388. hashCode = 37 * hashCode + Float.floatToIntBits(max);
  389. }
  390. return hashCode;
  391. }
  392. /**
  393. * <p>Gets the range as a <code>String</code>.</p>
  394. *
  395. * <p>The format of the String is 'Range[<i>min</i>,<i>max</i>]'.</p>
  396. *
  397. * @return the <code>String</code> representation of this range
  398. */
  399. public String toString() {
  400. if (toString == null) {
  401. StringBuffer buf = new StringBuffer(32);
  402. buf.append("Range[");
  403. buf.append(min);
  404. buf.append(',');
  405. buf.append(max);
  406. buf.append(']');
  407. toString = buf.toString();
  408. }
  409. return toString;
  410. }
  411. }