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 */ 009package javax.measure.unit; 010 011import java.io.Serializable; 012 013import javax.measure.converter.ConversionException; 014import javax.measure.converter.UnitConverter; 015import 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 */ 033public final class ProductUnit<Q extends Quantity> extends DerivedUnit<Q> { 034 035 /** 036 * Holds the units composing this product unit. 037 */ 038 private final Element[] _elements; 039 040 /** 041 * Holds the hashcode (optimization). 042 */ 043 private int _hashCode; 044 045 /** 046 * Default constructor (used solely to create <code>ONE</code> instance). 047 */ 048 ProductUnit() { 049 _elements = new Element[0]; 050 } 051 052 /** 053 * Copy constructor (allows for parameterization of product units). 054 * 055 * @param productUnit the product unit source. 056 * @throws ClassCastException if the specified unit is not 057 * a product unit. 058 */ 059 public ProductUnit(Unit<?> productUnit) { 060 _elements = ((ProductUnit<?>)productUnit)._elements; 061 } 062 063 /** 064 * Product unit constructor. 065 * 066 * @param elements the product elements. 067 */ 068 private ProductUnit(Element[] elements) { 069 _elements = elements; 070 } 071 072 /** 073 * Returns the unit defined from the product of the specifed elements. 074 * 075 * @param leftElems left multiplicand elements. 076 * @param rightElems right multiplicand elements. 077 * @return the corresponding unit. 078 */ 079 @SuppressWarnings("unchecked") 080 private static Unit<? extends Quantity> getInstance(Element[] leftElems, 081 Element[] rightElems) { 082 083 // Merges left elements with right elements. 084 Element[] result = new Element[leftElems.length + rightElems.length]; 085 int resultIndex = 0; 086 for (int i = 0; i < leftElems.length; i++) { 087 Unit unit = leftElems[i]._unit; 088 int p1 = leftElems[i]._pow; 089 int r1 = leftElems[i]._root; 090 int p2 = 0; 091 int r2 = 1; 092 for (int j = 0; j < rightElems.length; j++) { 093 if (unit.equals(rightElems[j]._unit)) { 094 p2 = rightElems[j]._pow; 095 r2 = rightElems[j]._root; 096 break; // No duplicate. 097 } 098 } 099 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}