001: /*
002: * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
003: * Copyright (C) 2006 - JScience (http://jscience.org/)
004: * All rights reserved.
005: *
006: * Permission to use, copy, modify, and distribute this software is
007: * freely granted, provided that this notice is preserved.
008: */
009: package javax.measure.unit;
010:
011: import java.io.Serializable;
012:
013: import javax.measure.converter.ConversionException;
014: import javax.measure.converter.UnitConverter;
015: import javax.measure.quantity.Quantity;
016:
017: /**
018: * <p> This class represents units formed by the product of rational powers of
019: * existing units.</p>
020: *
021: * <p> This class maintains the canonical form of this product (simplest
022: * form after factorization). For example:
023: * <code>METER.pow(2).divide(METER)</code> returns
024: * <code>METER</code>.</p>
025: *
026: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
027: * @version 3.1, April 22, 2006
028: * @see Unit#times(Unit)
029: * @see Unit#divide(Unit)
030: * @see Unit#pow(int)
031: * @see Unit#root(int)
032: */
033: public final class ProductUnit<Q extends Quantity> extends
034: DerivedUnit<Q> {
035:
036: /**
037: * Holds the units composing this product unit.
038: */
039: private final Element[] _elements;
040:
041: /**
042: * Holds the hashcode (optimization).
043: */
044: private int _hashCode;
045:
046: /**
047: * Default constructor (used solely to create <code>ONE</code> instance).
048: */
049: ProductUnit() {
050: _elements = new Element[0];
051: }
052:
053: /**
054: * Copy constructor (allows for parameterization of product units).
055: *
056: * @param productUnit the product unit source.
057: * @throws ClassCastException if the specified unit is not
058: * a product unit.
059: */
060: public ProductUnit(Unit<?> productUnit) {
061: _elements = ((ProductUnit<?>) productUnit)._elements;
062: }
063:
064: /**
065: * Product unit constructor.
066: *
067: * @param elements the product elements.
068: */
069: private ProductUnit(Element[] elements) {
070: _elements = elements;
071: }
072:
073: /**
074: * Returns the unit defined from the product of the specifed elements.
075: *
076: * @param leftElems left multiplicand elements.
077: * @param rightElems right multiplicand elements.
078: * @return the corresponding unit.
079: */
080: @SuppressWarnings("unchecked")
081: private static Unit<? extends Quantity> getInstance(
082: Element[] leftElems, Element[] rightElems) {
083:
084: // Merges left elements with right elements.
085: Element[] result = new Element[leftElems.length
086: + rightElems.length];
087: int resultIndex = 0;
088: for (int i = 0; i < leftElems.length; i++) {
089: Unit unit = leftElems[i]._unit;
090: int p1 = leftElems[i]._pow;
091: int r1 = leftElems[i]._root;
092: int p2 = 0;
093: int r2 = 1;
094: for (int j = 0; j < rightElems.length; j++) {
095: if (unit.equals(rightElems[j]._unit)) {
096: p2 = rightElems[j]._pow;
097: r2 = rightElems[j]._root;
098: break; // No duplicate.
099: }
100: }
101: int pow = (p1 * r2) + (p2 * r1);
102: int root = r1 * r2;
103: if (pow != 0) {
104: int gcd = gcd(Math.abs(pow), root);
105: result[resultIndex++] = new Element(unit, pow / gcd,
106: root / gcd);
107: }
108: }
109:
110: // Appends remaining right elements not merged.
111: for (int i = 0; i < rightElems.length; i++) {
112: Unit unit = rightElems[i]._unit;
113: boolean hasBeenMerged = false;
114: for (int j = 0; j < leftElems.length; j++) {
115: if (unit.equals(leftElems[j]._unit)) {
116: hasBeenMerged = true;
117: break;
118: }
119: }
120: if (!hasBeenMerged) {
121: result[resultIndex++] = rightElems[i];
122: }
123: }
124:
125: // Returns or creates instance.
126: if (resultIndex == 0) {
127: return ONE;
128: } else if ((resultIndex == 1)
129: && (result[0]._pow == result[0]._root)) {
130: return result[0]._unit;
131: } else {
132: Element[] elems = new Element[resultIndex];
133: for (int i = 0; i < resultIndex; i++) {
134: elems[i] = result[i];
135: }
136: return new ProductUnit<Quantity>(elems);
137: }
138: }
139:
140: /**
141: * Returns the product of the specified units.
142: *
143: * @param left the left unit operand.
144: * @param right the right unit operand.
145: * @return <code>left * right</code>
146: */
147: static Unit<? extends Quantity> getProductInstance(Unit<?> left,
148: Unit<?> right) {
149: Element[] leftElems;
150: if (left instanceof ProductUnit) {
151: leftElems = ((ProductUnit<?>) left)._elements;
152: } else {
153: leftElems = new Element[] { new Element(left, 1, 1) };
154: }
155: Element[] rightElems;
156: if (right instanceof ProductUnit) {
157: rightElems = ((ProductUnit<?>) right)._elements;
158: } else {
159: rightElems = new Element[] { new Element(right, 1, 1) };
160: }
161: return getInstance(leftElems, rightElems);
162: }
163:
164: /**
165: * Returns the quotient of the specified units.
166: *
167: * @param left the dividend unit operand.
168: * @param right the divisor unit operand.
169: * @return <code>dividend / divisor</code>
170: */
171: static Unit<? extends Quantity> getQuotientInstance(Unit<?> left,
172: Unit<?> right) {
173: Element[] leftElems;
174: if (left instanceof ProductUnit) {
175: leftElems = ((ProductUnit<?>) left)._elements;
176: } else {
177: leftElems = new Element[] { new Element(left, 1, 1) };
178: }
179: Element[] rightElems;
180: if (right instanceof ProductUnit) {
181: Element[] elems = ((ProductUnit<?>) right)._elements;
182: rightElems = new Element[elems.length];
183: for (int i = 0; i < elems.length; i++) {
184: rightElems[i] = new Element(elems[i]._unit,
185: -elems[i]._pow, elems[i]._root);
186: }
187: } else {
188: rightElems = new Element[] { new Element(right, -1, 1) };
189: }
190: return getInstance(leftElems, rightElems);
191: }
192:
193: /**
194: * Returns the product unit corresponding to the specified root of
195: * the specified unit.
196: *
197: * @param unit the unit.
198: * @param n the root's order (n > 0).
199: * @return <code>unit^(1/nn)</code>
200: * @throws ArithmeticException if <code>n == 0</code>.
201: */
202: static Unit<? extends Quantity> getRootInstance(Unit<?> unit, int n) {
203: Element[] unitElems;
204: if (unit instanceof ProductUnit) {
205: Element[] elems = ((ProductUnit<?>) unit)._elements;
206: unitElems = new Element[elems.length];
207: for (int i = 0; i < elems.length; i++) {
208: int gcd = gcd(Math.abs(elems[i]._pow), elems[i]._root
209: * n);
210: unitElems[i] = new Element(elems[i]._unit,
211: elems[i]._pow / gcd, elems[i]._root * n / gcd);
212: }
213: } else {
214: unitElems = new Element[] { new Element(unit, 1, n) };
215: }
216: return getInstance(unitElems, new Element[0]);
217: }
218:
219: /**
220: * Returns the product unit corresponding to this unit raised to
221: * the specified exponent.
222: *
223: * @param unit the unit.
224: * @param nn the exponent (nn > 0).
225: * @return <code>unit^n</code>
226: */
227: static Unit<? extends Quantity> getPowInstance(Unit<?> unit, int n) {
228: Element[] unitElems;
229: if (unit instanceof ProductUnit) {
230: Element[] elems = ((ProductUnit<?>) unit)._elements;
231: unitElems = new Element[elems.length];
232: for (int i = 0; i < elems.length; i++) {
233: int gcd = gcd(Math.abs(elems[i]._pow * n),
234: elems[i]._root);
235: unitElems[i] = new Element(elems[i]._unit,
236: elems[i]._pow * n / gcd, elems[i]._root / gcd);
237: }
238: } else {
239: unitElems = new Element[] { new Element(unit, n, 1) };
240: }
241: return getInstance(unitElems, new Element[0]);
242: }
243:
244: /**
245: * Returns the number of units in this product.
246: *
247: * @return the number of units being multiplied.
248: */
249: public int getUnitCount() {
250: return _elements.length;
251: }
252:
253: /**
254: * Returns the unit at the specified position.
255: *
256: * @param index the index of the unit to return.
257: * @return the unit at the specified position.
258: * @throws IndexOutOfBoundsException if index is out of range
259: * <code>(index < 0 || index >= size())</code>.
260: */
261: @SuppressWarnings("unchecked")
262: public Unit<? extends Quantity> getUnit(int index) {
263: return _elements[index].getUnit();
264: }
265:
266: /**
267: * Returns the power exponent of the unit at the specified position.
268: *
269: * @param index the index of the unit to return.
270: * @return the unit power exponent at the specified position.
271: * @throws IndexOutOfBoundsException if index is out of range
272: * <code>(index < 0 || index >= size())</code>.
273: */
274: public int getUnitPow(int index) {
275: return _elements[index].getPow();
276: }
277:
278: /**
279: * Returns the root exponent of the unit at the specified position.
280: *
281: * @param index the index of the unit to return.
282: * @return the unit root exponent at the specified position.
283: * @throws IndexOutOfBoundsException if index is out of range
284: * <code>(index < 0 || index >= size())</code>.
285: */
286: public int getUnitRoot(int index) {
287: return _elements[index].getRoot();
288: }
289:
290: /**
291: * Indicates if this product unit is considered equals to the specified
292: * object.
293: *
294: * @param that the object to compare for equality.
295: * @return <code>true</code> if <code>this</code> and <code>that</code>
296: * are considered equals; <code>false</code>otherwise.
297: */
298: public boolean equals(Object that) {
299: if (this == that)
300: return true;
301: if (that instanceof ProductUnit) {
302: // Two products are equals if they have the same elements
303: // regardless of the elements' order.
304: Element[] elems = ((ProductUnit<?>) that)._elements;
305: if (_elements.length == elems.length) {
306: for (int i = 0; i < _elements.length; i++) {
307: boolean unitFound = false;
308: for (int j = 0; j < elems.length; j++) {
309: if (_elements[i]._unit.equals(elems[j]._unit)) {
310: if ((_elements[i]._pow != elems[j]._pow)
311: || (_elements[i]._root != elems[j]._root)) {
312: return false;
313: } else {
314: unitFound = true;
315: break;
316: }
317: }
318: }
319: if (!unitFound) {
320: return false;
321: }
322: }
323: return true;
324: }
325: }
326: return false;
327: }
328:
329: @Override
330: // Implements abstract method.
331: public int hashCode() {
332: if (_hashCode != 0)
333: return _hashCode;
334: int code = 0;
335: for (int i = 0; i < _elements.length; i++) {
336: code += _elements[i]._unit.hashCode()
337: * (_elements[i]._pow * 3 - _elements[i]._root * 2);
338: }
339: _hashCode = code;
340: return code;
341: }
342:
343: @Override
344: @SuppressWarnings("unchecked")
345: public Unit<? super Q> getStandardUnit() {
346: if (hasOnlyStandardUnit())
347: return this ;
348: Unit systemUnit = ONE;
349: for (int i = 0; i < _elements.length; i++) {
350: Unit unit = _elements[i]._unit.getStandardUnit();
351: unit = unit.pow(_elements[i]._pow);
352: unit = unit.root(_elements[i]._root);
353: systemUnit = systemUnit.times(unit);
354: }
355: return systemUnit;
356: }
357:
358: @Override
359: public UnitConverter toStandardUnit() {
360: if (hasOnlyStandardUnit())
361: return UnitConverter.IDENTITY;
362: UnitConverter converter = UnitConverter.IDENTITY;
363: for (int i = 0; i < _elements.length; i++) {
364: UnitConverter cvtr = _elements[i]._unit.toStandardUnit();
365: if (!cvtr.isLinear())
366: throw new ConversionException(_elements[i]._unit
367: + " is non-linear, cannot convert");
368: if (_elements[i]._root != 1)
369: throw new ConversionException(_elements[i]._unit
370: + " holds a base unit with fractional exponent");
371: int pow = _elements[i]._pow;
372: if (pow < 0) { // Negative power.
373: pow = -pow;
374: cvtr = cvtr.inverse();
375: }
376: for (int j = 0; j < pow; j++) {
377: converter = converter.concatenate(cvtr);
378: }
379: }
380: return converter;
381: }
382:
383: /**
384: * Indicates if this product unit is a standard unit.
385: *
386: * @return <code>true</code> if all elements are standard units;
387: * <code>false</code> otherwise.
388: */
389: private boolean hasOnlyStandardUnit() {
390: for (int i = 0; i < _elements.length; i++) {
391: Unit<?> u = _elements[i]._unit;
392: if (!u.isStandardUnit())
393: return false;
394: }
395: return true;
396: }
397:
398: /**
399: * Returns the greatest common divisor (Euclid's algorithm).
400: *
401: * @param m the first number.
402: * @param nn the second number.
403: * @return the greatest common divisor.
404: */
405: private static int gcd(int m, int n) {
406: if (n == 0) {
407: return m;
408: } else {
409: return gcd(n, m % n);
410: }
411: }
412:
413: /**
414: * Inner product element represents a rational power of a single unit.
415: */
416: private final static class Element implements Serializable {
417:
418: /**
419: * Holds the single unit.
420: */
421: private final Unit<?> _unit;
422:
423: /**
424: * Holds the power exponent.
425: */
426: private final int _pow;
427:
428: /**
429: * Holds the root exponent.
430: */
431: private final int _root;
432:
433: /**
434: * Structural constructor.
435: *
436: * @param unit the unit.
437: * @param pow the power exponent.
438: * @param root the root exponent.
439: */
440: private Element(Unit<?> unit, int pow, int root) {
441: _unit = unit;
442: _pow = pow;
443: _root = root;
444: }
445:
446: /**
447: * Returns this element's unit.
448: *
449: * @return the single unit.
450: */
451: public Unit<?> getUnit() {
452: return _unit;
453: }
454:
455: /**
456: * Returns the power exponent. The power exponent can be negative
457: * but is always different from zero.
458: *
459: * @return the power exponent of the single unit.
460: */
461: public int getPow() {
462: return _pow;
463: }
464:
465: /**
466: * Returns the root exponent. The root exponent is always greater
467: * than zero.
468: *
469: * @return the root exponent of the single unit.
470: */
471: public int getRoot() {
472: return _root;
473: }
474:
475: private static final long serialVersionUID = 1L;
476: }
477:
478: private static final long serialVersionUID = 1L;
479: }
|