1 | /* |
2 | * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences. |
3 | * Copyright (C) 2006 - 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 javax.measure.unit; |
10 | |
11 | import java.io.Serializable; |
12 | |
13 | import javax.measure.converter.ConversionException; |
14 | import javax.measure.converter.UnitConverter; |
15 | import javax.measure.quantity.Quantity; |
16 | |
17 | /** |
18 | * <p> This class represents units formed by the product of rational powers of |
19 | * existing units.</p> |
20 | * |
21 | * <p> This class maintains the canonical form of this product (simplest |
22 | * form after factorization). For example: |
23 | * <code>METER.pow(2).divide(METER)</code> returns |
24 | * <code>METER</code>.</p> |
25 | * |
26 | * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> |
27 | * @version 3.1, April 22, 2006 |
28 | * @see Unit#times(Unit) |
29 | * @see Unit#divide(Unit) |
30 | * @see Unit#pow(int) |
31 | * @see Unit#root(int) |
32 | */ |
33 | public final class ProductUnit<Q extends Quantity> extends DerivedUnit<Q> { |
34 | |
35 | /** |
36 | * Holds the units composing this product unit. |
37 | */ |
38 | private final Element[] _elements; |
39 | |
40 | /** |
41 | * Holds the hashcode (optimization). |
42 | */ |
43 | private int _hashCode; |
44 | |
45 | /** |
46 | * Default constructor (used solely to create <code>ONE</code> instance). |
47 | */ |
48 | ProductUnit() { |
49 | _elements = new Element[0]; |
50 | } |
51 | |
52 | /** |
53 | * Copy constructor (allows for parameterization of product units). |
54 | * |
55 | * @param productUnit the product unit source. |
56 | * @throws ClassCastException if the specified unit is not |
57 | * a product unit. |
58 | */ |
59 | public ProductUnit(Unit<?> productUnit) { |
60 | _elements = ((ProductUnit<?>)productUnit)._elements; |
61 | } |
62 | |
63 | /** |
64 | * Product unit constructor. |
65 | * |
66 | * @param elements the product elements. |
67 | */ |
68 | private ProductUnit(Element[] elements) { |
69 | _elements = elements; |
70 | } |
71 | |
72 | /** |
73 | * Returns the unit defined from the product of the specifed elements. |
74 | * |
75 | * @param leftElems left multiplicand elements. |
76 | * @param rightElems right multiplicand elements. |
77 | * @return the corresponding unit. |
78 | */ |
79 | @SuppressWarnings("unchecked") |
80 | private static Unit<? extends Quantity> getInstance(Element[] leftElems, |
81 | Element[] rightElems) { |
82 | |
83 | // Merges left elements with right elements. |
84 | Element[] result = new Element[leftElems.length + rightElems.length]; |
85 | int resultIndex = 0; |
86 | for (int i = 0; i < leftElems.length; i++) { |
87 | Unit unit = leftElems[i]._unit; |
88 | int p1 = leftElems[i]._pow; |
89 | int r1 = leftElems[i]._root; |
90 | int p2 = 0; |
91 | int r2 = 1; |
92 | for (int j = 0; j < rightElems.length; j++) { |
93 | if (unit.equals(rightElems[j]._unit)) { |
94 | p2 = rightElems[j]._pow; |
95 | r2 = rightElems[j]._root; |
96 | break; // No duplicate. |
97 | } |
98 | } |
99 | int pow = (p1 * r2) + (p2 * r1); |
100 | int root = r1 * r2; |
101 | if (pow != 0) { |
102 | int gcd = gcd(Math.abs(pow), root); |
103 | result[resultIndex++] = new Element(unit, pow / gcd, root / gcd); |
104 | } |
105 | } |
106 | |
107 | // Appends remaining right elements not merged. |
108 | for (int i = 0; i < rightElems.length; i++) { |
109 | Unit unit = rightElems[i]._unit; |
110 | boolean hasBeenMerged = false; |
111 | for (int j = 0; j < leftElems.length; j++) { |
112 | if (unit.equals(leftElems[j]._unit)) { |
113 | hasBeenMerged = true; |
114 | break; |
115 | } |
116 | } |
117 | if (!hasBeenMerged) { |
118 | result[resultIndex++] = rightElems[i]; |
119 | } |
120 | } |
121 | |
122 | // Returns or creates instance. |
123 | if (resultIndex == 0) { |
124 | return ONE; |
125 | } else if ((resultIndex == 1) && (result[0]._pow == result[0]._root)) { |
126 | return result[0]._unit; |
127 | } else { |
128 | Element[] elems = new Element[resultIndex]; |
129 | for (int i = 0; i < resultIndex; i++) { |
130 | elems[i] = result[i]; |
131 | } |
132 | return new ProductUnit<Quantity>(elems); |
133 | } |
134 | } |
135 | |
136 | /** |
137 | * Returns the product of the specified units. |
138 | * |
139 | * @param left the left unit operand. |
140 | * @param right the right unit operand. |
141 | * @return <code>left * right</code> |
142 | */ |
143 | static Unit<? extends Quantity> getProductInstance(Unit<?> left, Unit<?> right) { |
144 | Element[] leftElems; |
145 | if (left instanceof ProductUnit) { |
146 | leftElems = ((ProductUnit<?>) left)._elements; |
147 | } else { |
148 | leftElems = new Element[] { new Element(left, 1, 1) }; |
149 | } |
150 | Element[] rightElems; |
151 | if (right instanceof ProductUnit) { |
152 | rightElems = ((ProductUnit<?>) right)._elements; |
153 | } else { |
154 | rightElems = new Element[] { new Element(right, 1, 1) }; |
155 | } |
156 | return getInstance(leftElems, rightElems); |
157 | } |
158 | |
159 | /** |
160 | * Returns the quotient of the specified units. |
161 | * |
162 | * @param left the dividend unit operand. |
163 | * @param right the divisor unit operand. |
164 | * @return <code>dividend / divisor</code> |
165 | */ |
166 | static Unit<? extends Quantity> getQuotientInstance(Unit<?> left, Unit<?> right) { |
167 | Element[] leftElems; |
168 | if (left instanceof ProductUnit) { |
169 | leftElems = ((ProductUnit<?>) left)._elements; |
170 | } else { |
171 | leftElems = new Element[] { new Element(left, 1, 1) }; |
172 | } |
173 | Element[] rightElems; |
174 | if (right instanceof ProductUnit) { |
175 | Element[] elems = ((ProductUnit<?>) right)._elements; |
176 | rightElems = new Element[elems.length]; |
177 | for (int i = 0; i < elems.length; i++) { |
178 | rightElems[i] = new Element(elems[i]._unit, -elems[i]._pow, |
179 | elems[i]._root); |
180 | } |
181 | } else { |
182 | rightElems = new Element[] { new Element(right, -1, 1) }; |
183 | } |
184 | return getInstance(leftElems, rightElems); |
185 | } |
186 | |
187 | /** |
188 | * Returns the product unit corresponding to the specified root of |
189 | * the specified unit. |
190 | * |
191 | * @param unit the unit. |
192 | * @param n the root's order (n > 0). |
193 | * @return <code>unit^(1/nn)</code> |
194 | * @throws ArithmeticException if <code>n == 0</code>. |
195 | */ |
196 | static Unit<? extends Quantity> getRootInstance(Unit<?> unit, int n) { |
197 | Element[] unitElems; |
198 | if (unit instanceof ProductUnit) { |
199 | Element[] elems = ((ProductUnit<?>) unit)._elements; |
200 | unitElems = new Element[elems.length]; |
201 | for (int i = 0; i < elems.length; i++) { |
202 | int gcd = gcd(Math.abs(elems[i]._pow), elems[i]._root * n); |
203 | unitElems[i] = new Element(elems[i]._unit, elems[i]._pow / gcd, |
204 | elems[i]._root * n / gcd); |
205 | } |
206 | } else { |
207 | unitElems = new Element[] { new Element(unit, 1, n) }; |
208 | } |
209 | return getInstance(unitElems, new Element[0]); |
210 | } |
211 | |
212 | /** |
213 | * Returns the product unit corresponding to this unit raised to |
214 | * the specified exponent. |
215 | * |
216 | * @param unit the unit. |
217 | * @param nn the exponent (nn > 0). |
218 | * @return <code>unit^n</code> |
219 | */ |
220 | static Unit<? extends Quantity> getPowInstance(Unit<?> unit, int n) { |
221 | Element[] unitElems; |
222 | if (unit instanceof ProductUnit) { |
223 | Element[] elems = ((ProductUnit<?>) unit)._elements; |
224 | unitElems = new Element[elems.length]; |
225 | for (int i = 0; i < elems.length; i++) { |
226 | int gcd = gcd(Math.abs(elems[i]._pow * n), elems[i]._root); |
227 | unitElems[i] = new Element(elems[i]._unit, elems[i]._pow * n |
228 | / gcd, elems[i]._root / gcd); |
229 | } |
230 | } else { |
231 | unitElems = new Element[] { new Element(unit, n, 1) }; |
232 | } |
233 | return getInstance(unitElems, new Element[0]); |
234 | } |
235 | |
236 | /** |
237 | * Returns the number of units in this product. |
238 | * |
239 | * @return the number of units being multiplied. |
240 | */ |
241 | public int getUnitCount() { |
242 | return _elements.length; |
243 | } |
244 | |
245 | /** |
246 | * Returns the unit at the specified position. |
247 | * |
248 | * @param index the index of the unit to return. |
249 | * @return the unit at the specified position. |
250 | * @throws IndexOutOfBoundsException if index is out of range |
251 | * <code>(index < 0 || index >= size())</code>. |
252 | */ |
253 | @SuppressWarnings("unchecked") |
254 | public Unit<? extends Quantity> getUnit(int index) { |
255 | return _elements[index].getUnit(); |
256 | } |
257 | |
258 | /** |
259 | * Returns the power exponent of the unit at the specified position. |
260 | * |
261 | * @param index the index of the unit to return. |
262 | * @return the unit power exponent at the specified position. |
263 | * @throws IndexOutOfBoundsException if index is out of range |
264 | * <code>(index < 0 || index >= size())</code>. |
265 | */ |
266 | public int getUnitPow(int index) { |
267 | return _elements[index].getPow(); |
268 | } |
269 | |
270 | /** |
271 | * Returns the root exponent of the unit at the specified position. |
272 | * |
273 | * @param index the index of the unit to return. |
274 | * @return the unit root exponent at the specified position. |
275 | * @throws IndexOutOfBoundsException if index is out of range |
276 | * <code>(index < 0 || index >= size())</code>. |
277 | */ |
278 | public int getUnitRoot(int index) { |
279 | return _elements[index].getRoot(); |
280 | } |
281 | |
282 | /** |
283 | * Indicates if this product unit is considered equals to the specified |
284 | * object. |
285 | * |
286 | * @param that the object to compare for equality. |
287 | * @return <code>true</code> if <code>this</code> and <code>that</code> |
288 | * are considered equals; <code>false</code>otherwise. |
289 | */ |
290 | public boolean equals(Object that) { |
291 | if (this == that) |
292 | return true; |
293 | if (that instanceof ProductUnit) { |
294 | // Two products are equals if they have the same elements |
295 | // regardless of the elements' order. |
296 | Element[] elems = ((ProductUnit<?>) that)._elements; |
297 | if (_elements.length == elems.length) { |
298 | for (int i = 0; i < _elements.length; i++) { |
299 | boolean unitFound = false; |
300 | for (int j = 0; j < elems.length; j++) { |
301 | if (_elements[i]._unit.equals(elems[j]._unit)) { |
302 | if ((_elements[i]._pow != elems[j]._pow) |
303 | || (_elements[i]._root != elems[j]._root)) { |
304 | return false; |
305 | } else { |
306 | unitFound = true; |
307 | break; |
308 | } |
309 | } |
310 | } |
311 | if (!unitFound) { |
312 | return false; |
313 | } |
314 | } |
315 | return true; |
316 | } |
317 | } |
318 | return false; |
319 | } |
320 | |
321 | @Override |
322 | // Implements abstract method. |
323 | public int hashCode() { |
324 | if (_hashCode != 0) |
325 | return _hashCode; |
326 | int code = 0; |
327 | for (int i = 0; i < _elements.length; i++) { |
328 | code += _elements[i]._unit.hashCode() |
329 | * (_elements[i]._pow * 3 - _elements[i]._root * 2); |
330 | } |
331 | _hashCode = code; |
332 | return code; |
333 | } |
334 | |
335 | @Override |
336 | @SuppressWarnings("unchecked") |
337 | public Unit<? super Q> getStandardUnit() { |
338 | if (hasOnlyStandardUnit()) |
339 | return this; |
340 | Unit systemUnit = ONE; |
341 | for (int i = 0; i < _elements.length; i++) { |
342 | Unit unit = _elements[i]._unit.getStandardUnit(); |
343 | unit = unit.pow(_elements[i]._pow); |
344 | unit = unit.root(_elements[i]._root); |
345 | systemUnit = systemUnit.times(unit); |
346 | } |
347 | return systemUnit; |
348 | } |
349 | |
350 | @Override |
351 | public UnitConverter toStandardUnit() { |
352 | if (hasOnlyStandardUnit()) |
353 | return UnitConverter.IDENTITY; |
354 | UnitConverter converter = UnitConverter.IDENTITY; |
355 | for (int i = 0; i < _elements.length; i++) { |
356 | UnitConverter cvtr = _elements[i]._unit.toStandardUnit(); |
357 | if (!cvtr.isLinear()) |
358 | throw new ConversionException(_elements[i]._unit |
359 | + " is non-linear, cannot convert"); |
360 | if (_elements[i]._root != 1) |
361 | throw new ConversionException(_elements[i]._unit |
362 | + " holds a base unit with fractional exponent"); |
363 | int pow = _elements[i]._pow; |
364 | if (pow < 0) { // Negative power. |
365 | pow = -pow; |
366 | cvtr = cvtr.inverse(); |
367 | } |
368 | for (int j = 0; j < pow; j++) { |
369 | converter = converter.concatenate(cvtr); |
370 | } |
371 | } |
372 | return converter; |
373 | } |
374 | |
375 | /** |
376 | * Indicates if this product unit is a standard unit. |
377 | * |
378 | * @return <code>true</code> if all elements are standard units; |
379 | * <code>false</code> otherwise. |
380 | */ |
381 | private boolean hasOnlyStandardUnit() { |
382 | for (int i = 0; i < _elements.length; i++) { |
383 | Unit<?> u = _elements[i]._unit; |
384 | if (!u.isStandardUnit()) |
385 | return false; |
386 | } |
387 | return true; |
388 | } |
389 | |
390 | /** |
391 | * Returns the greatest common divisor (Euclid's algorithm). |
392 | * |
393 | * @param m the first number. |
394 | * @param nn the second number. |
395 | * @return the greatest common divisor. |
396 | */ |
397 | private static int gcd(int m, int n) { |
398 | if (n == 0) { |
399 | return m; |
400 | } else { |
401 | return gcd(n, m % n); |
402 | } |
403 | } |
404 | |
405 | /** |
406 | * Inner product element represents a rational power of a single unit. |
407 | */ |
408 | private final static class Element implements Serializable { |
409 | |
410 | /** |
411 | * Holds the single unit. |
412 | */ |
413 | private final Unit<?> _unit; |
414 | |
415 | /** |
416 | * Holds the power exponent. |
417 | */ |
418 | private final int _pow; |
419 | |
420 | /** |
421 | * Holds the root exponent. |
422 | */ |
423 | private final int _root; |
424 | |
425 | /** |
426 | * Structural constructor. |
427 | * |
428 | * @param unit the unit. |
429 | * @param pow the power exponent. |
430 | * @param root the root exponent. |
431 | */ |
432 | private Element(Unit<?> unit, int pow, int root) { |
433 | _unit = unit; |
434 | _pow = pow; |
435 | _root = root; |
436 | } |
437 | |
438 | /** |
439 | * Returns this element's unit. |
440 | * |
441 | * @return the single unit. |
442 | */ |
443 | public Unit<?> getUnit() { |
444 | return _unit; |
445 | } |
446 | |
447 | /** |
448 | * Returns the power exponent. The power exponent can be negative |
449 | * but is always different from zero. |
450 | * |
451 | * @return the power exponent of the single unit. |
452 | */ |
453 | public int getPow() { |
454 | return _pow; |
455 | } |
456 | |
457 | /** |
458 | * Returns the root exponent. The root exponent is always greater |
459 | * than zero. |
460 | * |
461 | * @return the root exponent of the single unit. |
462 | */ |
463 | public int getRoot() { |
464 | return _root; |
465 | } |
466 | |
467 | private static final long serialVersionUID = 1L; |
468 | } |
469 | |
470 | private static final long serialVersionUID = 1L; |
471 | } |