001: /*
002: * <copyright>
003: *
004: * Copyright 2002-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.core.adaptivity;
028:
029: import java.util.HashMap;
030: import java.util.Map;
031:
032: /**
033: * Helper methods for dealing with Comparable values.
034: **/
035: public class ComparableHelper {
036: /**
037: * Maps the class of the Comparable to a minimum value for that type
038: **/
039: private static Map minimumValue = new HashMap();
040:
041: /**
042: * Maps the class of the Comparable to a maximum value for that type
043: **/
044: private static Map maximumValue = new HashMap();
045:
046: /**
047: * A String have the "maximum" value. Obviously, there is no true
048: * maximum, but this String should be greater than any String likely
049: * to encountered in the US.
050: **/
051: private static final String ffffString = "\uffff";
052:
053: /**
054: * Initialize the minimumValue and maximumValue Maps.
055: **/
056: static {
057: maximumValue.put(String.class, ComparableHelper.ffffString);
058: maximumValue.put(Double.class, new Double(Double.MAX_VALUE));
059: maximumValue.put(Float.class, new Float(Float.MAX_VALUE));
060: maximumValue.put(Long.class, new Long(Long.MAX_VALUE));
061: maximumValue.put(Integer.class, new Integer(Integer.MAX_VALUE));
062: minimumValue.put(String.class, "");
063: minimumValue.put(Double.class, new Double(Double.MIN_VALUE));
064: minimumValue.put(Float.class, new Float(Float.MIN_VALUE));
065: minimumValue.put(Long.class, new Long(Long.MIN_VALUE));
066: minimumValue.put(Integer.class, new Integer(Integer.MIN_VALUE));
067: }
068:
069: /**
070: * Get a value of the same type as the supplied value having the
071: * maximum value for that type. This is not possible, in general,
072: * but we approximate the values where necessary.
073: **/
074: public static Comparable getMax(Comparable v) {
075: return (Comparable) maximumValue.get(v.getClass());
076: }
077:
078: /**
079: * Get a value of the same type as the supplied value having the
080: * minimum value for that type. This is not possible, in general,
081: * but we approximate the values where necessary.
082: **/
083: public static Comparable getMin(Comparable v) {
084: return (Comparable) minimumValue.get(v.getClass());
085: }
086:
087: /**
088: * Get a value of the same type as the supplied value having the
089: * next greater value for that type. Not implemented for all
090: * Comparables.
091: **/
092: public static Comparable increment(Comparable v) {
093: Class vClass = v.getClass();
094: if (vClass == String.class)
095: return ((String) v) + "\0000";
096: if (vClass == Double.class) {
097: double d = ((Double) v).doubleValue();
098: return new Double(incrementDouble(d));
099: }
100: if (vClass == Integer.class)
101: return new Integer(((Integer) v).intValue() + 1);
102: return v;
103: }
104:
105: /**
106: * Get a value of the same type as the supplied value having the
107: * next smaller value for that type. Not implemented for all
108: * Comparables.
109: **/
110: public static Comparable decrement(Comparable v) {
111: Class vClass = v.getClass();
112: if (vClass == String.class)
113: return decrementString((String) v);
114: if (vClass == Double.class) {
115: double d = ((Double) v).doubleValue();
116: return new Double(-incrementDouble(-d));
117: }
118: if (vClass == Integer.class)
119: return new Integer(((Integer) v).intValue() - 1);
120: return v;
121: }
122:
123: /**
124: * Decrementing a String is impossible (it would be infinitely
125: * long). We approximate by returning a String of the same length.
126: **/
127: private static String decrementString(String s) {
128: int l = s.length();
129: char lastChar = s.charAt(l - 1);
130: String head = s.substring(0, l - 1);
131: String tail;
132: if (lastChar == '\u0000') {
133: head = decrementString(head);
134: tail = ComparableHelper.ffffString;
135: } else {
136: tail = new String(new char[] { (char) (lastChar - 1) });
137: }
138: return head + tail;
139: }
140:
141: /**
142: * Increment a double to the next representable value. The result is
143: * such that there is no representation for any values between the
144: * given value and the result.
145: **/
146: private static double incrementDouble(double v) {
147: long bits = Double.doubleToLongBits(v);
148: long m = (bits & 0xfffffffffffffL); // The significand
149: long s = bits & 0x8000000000000000L; // The sign
150: int e = (int) ((bits >> 52) & 0x7ffL); // The exponent
151: if (s == 0L) { // Positive numbers
152: if (m == 0x000fffffffffffffL) {
153: m = 0; // Carry results in 0
154: e++; // and increments the exponent
155: } else {
156: m += 1L; // Carry is not a problem, just increment
157: }
158: } else { // Negative numbers
159: if (m == 0x0000000000000000L) {
160: if (e > 0) {
161: m = 0x000fffffffffffffL; // Borrow results in all ones
162: e--; // and decrements the exponent
163: } else { // Negative zero shouldn't happen
164: m = 1; // But, return smallest
165: s = 0; // positive non-zero value
166: e = 0; // if it does
167: }
168: } else { // Simple case
169: m -= 1L; // Just decrement the significand
170: if (m == 0L && e == 0) {
171: s = 0; // Avoid negative zero.
172: }
173: }
174: }
175: bits = s | (((long) e) << 52) | m;
176: return Double.longBitsToDouble(bits);
177: }
178:
179: public static Comparable add(Comparable l, Comparable r) {
180: if (l.getClass() == String.class
181: || r.getClass() == String.class)
182: return l.toString() + r.toString();
183: if (l instanceof Number && r instanceof Number) {
184: Number ln = (Number) l;
185: Number rn = (Number) r;
186: if (ln instanceof Double || rn instanceof Double) {
187: return new Double(ln.doubleValue() + rn.doubleValue());
188: }
189: if (ln instanceof Long || rn instanceof Long) {
190: return new Long(ln.longValue() + rn.longValue());
191: }
192: if (ln instanceof Integer || rn instanceof Integer) {
193: return new Integer(ln.intValue() + rn.intValue());
194: }
195: }
196: throw new IllegalArgumentException("Unimplemented arithmetic");
197: }
198:
199: public static Comparable subtract(Comparable l, Comparable r) {
200: if (l.getClass() == String.class
201: || r.getClass() == String.class) {
202: throw new IllegalArgumentException(
203: "Strings cannot be subtracted");
204: }
205: if (l instanceof Number && r instanceof Number) {
206: Number ln = (Number) l;
207: Number rn = (Number) r;
208: if (ln instanceof Double || rn instanceof Double) {
209: return new Double(ln.doubleValue() - rn.doubleValue());
210: }
211: if (ln instanceof Long || rn instanceof Long) {
212: return new Long(ln.longValue() - rn.longValue());
213: }
214: if (ln instanceof Integer || rn instanceof Integer) {
215: return new Integer(ln.intValue() - rn.intValue());
216: }
217: }
218: throw new IllegalArgumentException("Unimplemented arithmetic");
219: }
220:
221: public static Comparable multiply(Comparable l, Comparable r) {
222: if (l.getClass() == String.class
223: || r.getClass() == String.class) {
224: throw new IllegalArgumentException(
225: "Strings cannot be multiplied");
226: }
227: if (l instanceof Number && r instanceof Number) {
228: Number ln = (Number) l;
229: Number rn = (Number) r;
230: if (ln instanceof Double || rn instanceof Double) {
231: return new Double(ln.doubleValue() * rn.doubleValue());
232: }
233: if (ln instanceof Long || rn instanceof Long) {
234: return new Long(ln.longValue() * rn.longValue());
235: }
236: if (ln instanceof Integer || rn instanceof Integer) {
237: return new Integer(ln.intValue() * rn.intValue());
238: }
239: }
240: throw new IllegalArgumentException("Unimplemented arithmetic");
241: }
242:
243: public static Comparable divide(Comparable l, Comparable r) {
244: if (l.getClass() == String.class
245: || r.getClass() == String.class) {
246: throw new IllegalArgumentException(
247: "Strings cannot be divided");
248: }
249: if (l instanceof Number && r instanceof Number) {
250: Number ln = (Number) l;
251: Number rn = (Number) r;
252: if (ln instanceof Double || rn instanceof Double) {
253: return new Double(ln.doubleValue() / rn.doubleValue());
254: }
255: if (ln instanceof Long || rn instanceof Long) {
256: return new Long(ln.longValue() / rn.longValue());
257: }
258: if (ln instanceof Integer || rn instanceof Integer) {
259: return new Integer(ln.intValue() / rn.intValue());
260: }
261: }
262: throw new IllegalArgumentException("Unimplemented arithmetic");
263: }
264:
265: public static Comparable negate(Comparable v) {
266: if (v.getClass() == String.class) {
267: throw new IllegalArgumentException(
268: "Strings cannot be negated");
269: }
270: if (v instanceof Number) {
271: Number nv = (Number) v;
272: if (nv instanceof Double)
273: return new Double(-nv.doubleValue());
274: if (nv instanceof Long)
275: return new Long(-nv.longValue());
276: if (nv instanceof Integer)
277: return new Integer(-nv.intValue());
278: }
279: throw new IllegalArgumentException("Unimplemented arithmetic");
280: }
281:
282: /**
283: * Tests (should be moved to regress)
284: **/
285: public static void main(String[] args) {
286: long[] testBits = { 0x0010000000000000L, 0x0008000000000000L,
287: 0x0004000000000000L, 0x0002000000000000L,
288: 0x001fffffffffffffL, 0x000fffffffffffffL,
289: 0x0007ffffffffffffL, 0x0003ffffffffffffL, };
290: for (int i = 0; i < testBits.length; i++) {
291: double v = Double.longBitsToDouble(testBits[i]);
292: double iv = incrementDouble(v);
293: double av = (v + iv) * 0.5;
294: System.out.println(" v=" + v);
295: System.out.println(" iv=" + iv);
296: System.out.println(" av=" + av);
297: System.out.println(" v<iv=" + (v < iv));
298: System.out.println(" v<av=" + (v < av));
299: System.out.println("av<iv=" + (av < iv));
300: }
301: System.out.println("decrement(A)=" + decrement("A"));
302: System.out.println("increment(A)=" + increment("A"));
303: }
304: }
|