KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jscience > physics > units > ProductUnit


1 /*
2  * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
3  * Copyright (C) 2005 - JScience (http://jscience.org/)
4  * All rights reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software is
7  * freely granted, provided that this notice is preserved.
8  */

9 package org.jscience.physics.units;
10
11 import java.io.Serializable JavaDoc;
12 import org.jscience.physics.quantities.Quantity;
13
14 import javolution.lang.MathLib;
15
16 /**
17  * <p> This class represents a product unit. Product units are formed by
18  * the product of rational powers of existing units.</p>
19  * <p> This class maintains the canonical form of this product (simplest
20  * form after factorization). For example:
21  * <code>METER.pow(2).divide(METER)</code> returns
22  * <code>METER</code>.</p>
23  *
24  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
25  * @version 1.1, May 24, 2005
26  * @see Unit#times(Unit)
27  * @see Unit#divide(Unit)
28  * @see Unit#pow(int)
29  * @see Unit#root(int)
30  */

31 public final class ProductUnit<Q extends Quantity> extends DerivedUnit<Q> {
32
33     /**
34      * Holds the units composing this product unit.
35      */

36     private final Element[] _elements;
37
38     /**
39      * Default constructor (used solely to create <code>ONE</code> instance).
40      */

41     ProductUnit() {
42         _elements = new Element[0];
43     }
44
45     /**
46      * Product unit constructor.
47      *
48      * @param elements the product elements.
49      */

50     private ProductUnit(Element[] elements) {
51         _elements = elements;
52     }
53
54     /**
55      * Returns the unit defined from the product of the specifed elements.
56      *
57      * @param leftElems left multiplicand elements.
58      * @param rightElems right multiplicand elements.
59      * @return the corresponding unit.
60      */

61     static Unit getInstance(Element[] leftElems, Element[] rightElems) {
62
63         // Merges left elements with right elements.
64
Element[] result = new Element[leftElems.length + rightElems.length];
65         int resultIndex = 0;
66         for (int i = 0; i < leftElems.length; i++) {
67             Unit unit = leftElems[i]._unit;
68             int p1 = leftElems[i]._pow;
69             int r1 = leftElems[i]._root;
70             int p2 = 0;
71             int r2 = 1;
72             for (int j = 0; j < rightElems.length; j++) {
73                 if (unit == rightElems[j]._unit) {
74                     p2 = rightElems[j]._pow;
75                     r2 = rightElems[j]._root;
76                     break; // No duplicate.
77
}
78             }
79             int pow = (p1 * r2) + (p2 * r1);
80             int root = r1 * r2;
81             if (pow != 0) {
82                 int gcd = gcd(MathLib.abs(pow), root);
83                 result[resultIndex++] = new Element(unit, pow / gcd, root / gcd);
84             }
85         }
86
87         // Appends remaining right elements not merged.
88
for (int i = 0; i < rightElems.length; i++) {
89             Unit unit = rightElems[i]._unit;
90             boolean hasBeenMerged = false;
91             for (int j = 0; j < leftElems.length; j++) {
92                 if (unit == leftElems[j]._unit) {
93                     hasBeenMerged = true;
94                     break;
95                 }
96             }
97             if (!hasBeenMerged) {
98                 result[resultIndex++] = rightElems[i];
99             }
100         }
101
102         // Returns or creates instance.
103
if (resultIndex == 0) {
104             return ONE;
105         } else if ((resultIndex == 1) && (result[0]._pow == result[0]._root)) {
106             return result[0]._unit;
107         } else {
108             Element[] elems = new Element[resultIndex];
109             for (int i = 0; i < resultIndex; i++) {
110                 elems[i] = result[i];
111             }
112             return getInstance(new ProductUnit(elems));
113         }
114     }
115
116     /**
117      * Returns the product of the specified units.
118      *
119      * @param left the left unit operand.
120      * @param right the right unit operand.
121      * @return <code>left * right</code>
122      */

123     static Unit getProductInstance(Unit left, Unit right) {
124         Element[] leftElems;
125         if (left instanceof ProductUnit) {
126             leftElems = ((ProductUnit) left)._elements;
127         } else {
128             leftElems = new Element[] { new Element(left, 1, 1) };
129         }
130         Element[] rightElems;
131         if (right instanceof ProductUnit) {
132             rightElems = ((ProductUnit) right)._elements;
133         } else {
134             rightElems = new Element[] { new Element(right, 1, 1) };
135         }
136         return getInstance(leftElems, rightElems);
137     }
138
139     /**
140      * Returns the quotient of the specified units.
141      *
142      * @param left the dividend unit operand.
143      * @param right the divisor unit operand.
144      * @return <code>dividend / divisor</code>
145      */

146     static Unit getQuotientInstance(Unit left, Unit right) {
147         Element[] leftElems;
148         if (left instanceof ProductUnit) {
149             leftElems = ((ProductUnit) left)._elements;
150         } else {
151             leftElems = new Element[] { new Element(left, 1, 1) };
152         }
153         Element[] rightElems;
154         if (right instanceof ProductUnit) {
155             Element[] elems = ((ProductUnit) right)._elements;
156             rightElems = new Element[elems.length];
157             for (int i = 0; i < elems.length; i++) {
158                 rightElems[i] = new Element(elems[i]._unit, -elems[i]._pow,
159                         elems[i]._root);
160             }
161         } else {
162             rightElems = new Element[] { new Element(right, -1, 1) };
163         }
164         return getInstance(leftElems, rightElems);
165     }
166
167     /**
168      * Returns the product unit corresponding to the specified root of
169      * the specified unit.
170      *
171      * @param unit the unit.
172      * @param n the root's order (n &gt; 0).
173      * @return <code>unit^(1/nn)</code>
174      * @throws ArithmeticException if <code>n == 0</code>.
175      */

176     static Unit getRootInstance(Unit unit, int n) {
177         Element[] unitElems;
178         if (unit instanceof ProductUnit) {
179             Element[] elems = ((ProductUnit) unit)._elements;
180             unitElems = new Element[elems.length];
181             for (int i = 0; i < elems.length; i++) {
182                 int gcd = gcd(MathLib.abs(elems[i]._pow), elems[i]._root * n);
183                 unitElems[i] = new Element(elems[i]._unit, elems[i]._pow / gcd,
184                         elems[i]._root * n / gcd);
185             }
186         } else {
187             unitElems = new Element[] { new Element(unit, 1, n) };
188         }
189         return getInstance(unitElems, new Element[0]);
190     }
191
192     /**
193      * Returns the product unit corresponding to this unit raised to
194      * the specified exponent.
195      *
196      * @param unit the unit.
197      * @param nn the exponent (nn &gt; 0).
198      * @return <code>unit^n</code>
199      */

200     static Unit getPowInstance(Unit unit, int n) {
201         Element[] unitElems;
202         if (unit instanceof ProductUnit) {
203             Element[] elems = ((ProductUnit) unit)._elements;
204             unitElems = new Element[elems.length];
205             for (int i = 0; i < elems.length; i++) {
206                 int gcd = gcd(MathLib.abs(elems[i]._pow * n), elems[i]._root);
207                 unitElems[i] = new Element(elems[i]._unit, elems[i]._pow * n
208                         / gcd, elems[i]._root / gcd);
209             }
210         } else {
211             unitElems = new Element[] { new Element(unit, n, 1) };
212         }
213         return getInstance(unitElems, new Element[0]);
214     }
215
216     /**
217      * Returns the number of units in this product.
218      *
219      * @return the number of units being multiplied.
220      */

221     public int size() {
222         return _elements.length;
223     }
224
225     /**
226      * Returns the product element at the specified position.
227      *
228      * @param index the index of the element to return.
229      * @return the element at the specified position.
230      * @throws IndexOutOfBoundsException if index is out of range
231      * <code>(index &lt; 0 || index &gt;= size())</code>.
232      */

233     public Element get(int index) {
234         return _elements[index];
235     }
236
237     // Implements abstract method.
238
protected boolean equalsImpl(Object JavaDoc that) {
239         if (that instanceof ProductUnit) {
240             // Two products are equals if they have the same elements
241
// regardless of the elements' order.
242
Element[] elems = ((ProductUnit) that)._elements;
243             if (_elements.length == elems.length) {
244                 for (int i = 0; i < _elements.length; i++) {
245                     boolean unitFound = false;
246                     for (int j = 0; j < elems.length; j++) {
247                         if (_elements[i]._unit == elems[j]._unit) {
248                             if ((_elements[i]._pow != elems[j]._pow)
249                                     || (_elements[i]._root != elems[j]._root)) {
250                                 return false;
251                             } else {
252                                 unitFound = true;
253                                 break;
254                             }
255                         }
256                     }
257                     if (!unitFound) {
258                         return false;
259                     }
260                 }
261                 return true;
262             }
263         }
264         return false;
265     }
266
267     // Implements abstract method.
268
protected int hashCodeImpl() {
269         int code = 0;
270         for (int i = 0; i < _elements.length; i++) {
271             code += _elements[i]._unit.hashCode()
272                     * (_elements[i]._pow * 3 - _elements[i]._root * 2);
273         }
274         return code;
275     }
276
277     // Implements abstract method.
278
protected Unit<Q> getParentUnitImpl() {
279         if (isProductOfBaseUnits()) return this;
280         Unit parentUnit = ONE;
281         for (int i = 0; i < _elements.length; i++) {
282             Unit unit = _elements[i]._unit.getParentUnit();
283             unit = unit.pow(_elements[i]._pow);
284             unit = unit.root(_elements[i]._root);
285             parentUnit = parentUnit.times(unit);
286         }
287         return parentUnit;
288     }
289
290     // Implements abstract method.
291
protected Converter toParentUnitImpl() {
292         if (isProductOfBaseUnits()) return Converter.IDENTITY;
293         double factor = 1.0;
294         for (int i = 0; i < _elements.length; i++) {
295             Converter cvtr = _elements[i]._unit.toParentUnit();
296             if (cvtr.isLinear()) {
297                 factor *= MathLib.pow(cvtr.derivative(0),
298                         ((double) _elements[i]._pow)
299                                 / ((double) _elements[i]._root));
300             } else {
301                 // Non-linear, cannot convert.
302
throw new ConversionException(_elements[i]._unit
303                         + " is non-linear, cannot convert");
304             }
305         }
306         if (MathLib.abs(factor - 1.0) < 1e-9) {
307             return Converter.IDENTITY;
308         } else {
309             return new MultiplyConverter(factor);
310         }
311     }
312     
313     /**
314      * Indicates if this unit is a product of base units exclusively.
315      *
316      * @return <code>true</code> if all elements are base units;
317      * <code>false</code> otherwise.
318      */

319     private boolean isProductOfBaseUnits() {
320         for (int i = 0; i < _elements.length; i++) {
321             if (!(_elements[i]._unit instanceof BaseUnit)) {
322                 return false;
323             }
324         }
325         return true;
326     }
327
328     /**
329      * Returns the greatest common divisor (Euclid's algorithm).
330      *
331      * @param m the first number.
332      * @param nn the second number.
333      * @return the greatest common divisor.
334      */

335     private static int gcd(int m, int n) {
336         if (n == 0) {
337             return m;
338         } else {
339             return gcd(n, m % n);
340         }
341     }
342
343     /**
344      * Inner product element represents a rational power of a single unit.
345      */

346     public final static class Element implements Serializable JavaDoc {
347
348         /**
349          * Holds the single unit.
350          */

351         private final Unit _unit;
352
353         /**
354          * Holds the power exponent.
355          */

356         private final int _pow;
357
358         /**
359          * Holds the root exponent.
360          */

361         private final int _root;
362
363         /**
364          * Structural constructor.
365          *
366          * @param unit the unit.
367          * @param pow the power exponent.
368          * @param root the root exponent.
369          */

370         private Element(Unit unit, int pow, int root) {
371             _unit = unit;
372             _pow = pow;
373             _root = root;
374         }
375
376         /**
377          * Returns this element's unit.
378          *
379          * @return the single unit.
380          */

381         public Unit getUnit() {
382             return _unit;
383         }
384
385         /**
386          * Returns the power exponent. The power exponent can be negative
387          * but is always different from zero.
388          *
389          * @return the power exponent of the single unit.
390          */

391         public int getPow() {
392             return _pow;
393         }
394
395         /**
396          * Returns the root exponent. The root exponent is always greater
397          * than zero.
398          *
399          * @return the root exponent of the single unit.
400          */

401         public int getRoot() {
402             return _root;
403         }
404
405         private static final long serialVersionUID = 1L;
406     }
407
408     private static final long serialVersionUID = 1L;
409 }
Popular Tags