1 9 package org.jscience.physics.quantities; 10 11 import javolution.util.FastMap; 12 import javolution.lang.MathLib; 13 import javolution.lang.Text; 14 import javolution.xml.XmlElement; 15 import javolution.xml.XmlFormat; 16 import javolution.realtime.RealtimeObject; 17 18 import org.jscience.mathematics.numbers.Number; 19 import org.jscience.physics.units.ConversionException; 20 import org.jscience.physics.units.Converter; 21 import org.jscience.physics.units.Unit; 22 23 51 public class Quantity extends Number <Quantity> { 52 53 61 private static final XmlFormat<Quantity> XML = new XmlFormat<Quantity>( 62 Quantity.class) { 63 public void format(Quantity q, XmlElement xml) { 64 xml.setAttribute("amount", q.getAmount()); 65 if (q._unit != Unit.ONE) { 68 xml.setAttribute("unit", q._unit.toText()); 69 } 70 } 71 72 public Quantity parse(XmlElement xml) { 73 double amount = xml.getAttribute("amount", 0.0); 74 CharSequence unitName = xml.getAttribute("unit"); 76 Unit unit = unitName != null ? Unit.valueOf(unitName) : Unit.ONE; 77 return Quantity.valueOf(amount, unit); 78 } 79 }; 80 81 85 static final double DOUBLE_RELATIVE_ERROR = MathLib.pow(2, -53); 86 87 91 static final double DECREMENT = (1.0 - DOUBLE_RELATIVE_ERROR); 92 93 96 private Unit _unit; 97 98 101 private double _minimum; 102 103 106 private double _maximum; 107 108 112 115 protected Quantity() { 116 } 117 118 130 public static <Q extends Quantity> Q valueOf(CharSequence csq) { 131 return (Q) QuantityFormat.current().parse(csq); 132 } 133 134 144 public static <Q extends Quantity> Q valueOf(double amount, Unit<Q> unit) { 145 Converter cvtr = unit.toBaseUnits(); 146 double value = cvtr.convert(amount); 147 return (Q) newInstance(unit).setRangeApprox(value, value); 148 } 149 150 161 public static <Q extends Quantity> Q valueOf(double amount, double error, 162 Unit<Q> unit) { 163 Converter cvtr = unit.toBaseUnits(); 164 double min = cvtr.convert(amount - error); 165 double max = cvtr.convert(amount + error); 166 return (Q) newInstance(unit).setRangeApprox(min, max); 167 } 168 169 177 public static <Q extends Quantity> Q rangeOf(double minimum, 178 double maximum, Unit<Q> unit) { 179 Converter cvtr = unit.toBaseUnits(); 180 double min = cvtr.convert(minimum); 181 double max = cvtr.convert(maximum); 182 return (Q) newInstance(unit).setRangeApprox(min, max); 183 } 184 185 191 public double getAmount() { 192 double baseUnitValue = (_minimum + _maximum) * 0.5; 193 Converter cvtr = _unit.toBaseUnits().inverse(); 194 return cvtr.convert(baseUnitValue); 195 } 196 197 203 public Unit getUnit() { 204 return _unit; 205 } 206 207 212 public final double getMinimum() { 213 return _minimum; 214 } 215 216 221 public final double getMaximum() { 222 return _maximum; 223 } 224 225 231 public final double getAbsoluteError() { 232 return MathLib.abs(_maximum - _minimum) / 2.0; 233 } 234 235 241 public final double getRelativeError() { 242 return (_maximum - _minimum) / (_minimum + _maximum); 243 } 244 245 249 261 public final <Q extends Quantity> Q to(Unit<Q> unit) { 262 Quantity q = newInstance(unit); 263 if (!needConversionTo(unit)) return (Q) q.setRangeExact(_minimum, _maximum); 265 Converter cvtr = _unit.getBaseUnits().getConverterTo( 266 unit.getBaseUnits()); 267 double min = cvtr.convert(_minimum); 268 double max = cvtr.convert(_maximum); 269 return (Q) q.setRangeApprox(min, max); 270 } 271 272 277 public final Quantity opposite() { 278 return Quantity.newInstance(_unit).setRangeExact(-_maximum, -_minimum); 279 } 280 281 289 public final Quantity plus(Quantity that) throws ConversionException { 290 if (needConversionTo(that._unit)) 291 return this.plus(that.to(_unit)); 292 return Quantity.newInstance(_unit).setRangeApprox( 293 this._minimum + that._minimum, this._maximum + that._maximum); 294 } 295 296 304 public final Quantity minus(Quantity that) throws ConversionException { 305 if (needConversionTo(that._unit)) 306 return this.minus(that.to(_unit)); 307 return Quantity.newInstance(_unit).setRangeApprox( 308 this._minimum - that._maximum, this._maximum - that._minimum); 309 } 310 311 317 public final Quantity times(double factor) { 318 return (factor > 0) ? Quantity.newInstance(_unit).setRangeApprox( 319 this._minimum * factor, this._maximum * factor) : Quantity 320 .newInstance(_unit).setRangeApprox(this._maximum * factor, 321 this._minimum * factor); 322 } 323 324 330 public final Quantity times(Quantity that) { 331 double min, max; 332 if (_minimum >= 0) { 333 if (that._minimum >= 0) { 334 min = _minimum * that._minimum; 335 max = _maximum * that._maximum; 336 } else if (that._maximum < 0){ 337 min = _maximum * that._minimum; 338 max = _minimum * that._maximum; 339 } else { 340 min = _maximum * that._minimum; 341 max = _maximum * that._maximum; 342 } 343 } else if (_maximum < 0) { 344 if (that._minimum >= 0) { 345 min = _minimum * that._maximum; 346 max = _maximum * that._minimum; 347 } else if (that._maximum < 0){ 348 min = _maximum * that._maximum; 349 max = _minimum * that._minimum; 350 } else { 351 min = _minimum * that._maximum; 352 max = _minimum * that._minimum; 353 } 354 } else { 355 if (that._minimum >= 0) { 356 min = _minimum * that._maximum; 357 max = _maximum * that._maximum; 358 } else if (that._maximum < 0){ 359 min = _maximum * that._minimum; 360 max = _minimum * that._minimum; 361 } else { min = MathLib.min(_minimum * that._maximum, _maximum * that._minimum); 363 max = MathLib.max(_minimum * that._minimum, _maximum * that._maximum); 364 } 365 } 366 return newInstance(this._unit.times(that._unit)).setRangeApprox(min, 367 max); 368 } 369 370 377 public final Quantity reciprocal() { 378 Quantity q = newInstance(_unit.inverse()); 379 if ((_minimum <= 0) && (_maximum >= 0)) { return q.setRangeExact(Double.NEGATIVE_INFINITY, 381 Double.POSITIVE_INFINITY); 382 } 383 return q.setRangeApprox(1.0 / _maximum, 1.0 / _minimum); 384 } 385 386 392 public final Quantity divide(double divisor) { 393 return (divisor > 0) ? Quantity.newInstance(_unit).setRangeApprox( 394 this._minimum / divisor, this._maximum / divisor) : Quantity 395 .newInstance(_unit).setRangeApprox(this._maximum / divisor, 396 this._minimum / divisor); 397 } 398 399 404 public final Quantity sqrt() { 405 return newInstance(_unit.root(2)).setRangeApprox( 406 MathLib.sqrt(_minimum), MathLib.sqrt(_maximum)); 407 } 408 409 416 public final Quantity root(int n) { 417 if (n > 0) { 418 Quantity q = newInstance(_unit.root(n)); 419 return q.setRangeApprox(MathLib.pow(_minimum, 1.0 / n), MathLib 420 .pow(_maximum, 1.0 / n)); 421 } else if (n < 0) { 422 return root(-n).reciprocal(); 423 } else { 424 throw new ArithmeticException ("Root's order of zero"); 425 } 426 } 427 428 433 public final Quantity norm() { 434 return (_minimum >= -_maximum) ? this : this.opposite(); 435 } 436 437 443 public final boolean isLargerThan(Quantity that) { 444 return MathLib.abs(this._minimum + this._maximum) > MathLib 445 .abs(that._minimum + that._maximum); 446 } 447 448 452 463 public boolean equals(Object obj) { 464 if (!(obj instanceof Quantity)) 465 return false; 466 Quantity that = (Quantity) obj; 467 if (this._unit != that._unit) 468 return false; 469 return (this._minimum == that._minimum) 470 && (this._maximum == that._maximum); 471 } 472 473 479 public int hashCode() { 480 int h = Float.floatToIntBits((float) _maximum); 481 h += ~(h << 9); 482 h ^= (h >>> 14); 483 h += (h << 4); 484 return h ^ (h >>> 10); 485 } 486 487 495 public boolean approxEquals(Quantity that) { 496 if (!this._unit.isCompatible(that._unit)) 497 return false; 498 Quantity diff = this.minus(that); 499 return (diff._minimum <= 0) && (diff._maximum >= 0); 500 } 501 502 516 public int compareTo(Quantity that) { 517 if (!this._unit.isCompatible(that._unit)) 518 throw new ConversionException("Cannot compare quantity in " 519 + this._unit + " with quantity in " + that._unit); 520 double diff = this.minus(that).doubleValue(); 521 if (diff < 0) 522 return -1; 523 if (diff > 0) 524 return 1; 525 if (this.equals(that)) 526 return 0; 527 long rawBits = Double.doubleToLongBits(diff); 529 return (rawBits < 0) ? -1 : 1; 530 } 531 532 539 public Text toText() { 540 return QuantityFormat.current().format(this); 541 } 542 543 549 public final long longValue() { 550 return MathLib.round(doubleValue()); 551 } 552 553 559 public final double doubleValue() { 560 return 0.5 * (_minimum + _maximum); 561 } 562 563 569 private static Quantity newInstance(Unit unit) { 570 Factory< ? extends Quantity> factory = Factory.UNIT_TO_FACTORY 571 .get(unit); 572 if (factory != null) { 573 Quantity q = factory.object(); 574 q._unit = unit; 575 return q; 576 } 577 return newInstanceCacheMiss(unit); 578 } 579 580 private static Quantity newInstanceCacheMiss(Unit unit) { 581 Factory< ? extends Quantity> factory = Factory.getInstance(unit); 582 Quantity q = factory.object(); 583 q._unit = unit; 584 return q; 585 } 586 587 596 private boolean needConversionTo(Unit unit) { 597 return (_unit != unit) && (_unit.getBaseUnits() != unit.getBaseUnits()); 598 } 599 600 604 public static abstract class Factory<Q extends Quantity> extends 605 RealtimeObject.Factory<Q> { 606 607 610 private static final Factory GENERAL = new Factory() { 611 protected Object create() { 612 return new Quantity(); 613 } 614 }; 615 616 619 private static final FastMap<Unit, Factory< ? extends Quantity>> COLLECTION = new FastMap<Unit, Factory< ? extends Quantity>>( 620 256); 621 622 625 private static final FastMap<Unit, Factory< ? extends Quantity>> UNIT_TO_FACTORY = new FastMap<Unit, Factory< ? extends Quantity>>( 626 1024); 627 628 631 protected Factory() { 632 } 633 634 640 protected Factory(Unit<Q> unit) { 641 useFor(unit); 642 } 643 644 653 public Factory<Q> useFor(Unit unit) { 654 synchronized (COLLECTION) { 655 if (COLLECTION.containsKey(unit)) 656 throw new IllegalArgumentException ("unit: " + unit 657 + " is already mapped"); 658 COLLECTION.put(unit, this); 659 for (FastMap.Entry<Unit, Factory< ? extends Quantity>> e = UNIT_TO_FACTORY 662 .headEntry(), end = UNIT_TO_FACTORY.tailEntry(); (e = e 663 .getNextEntry()) != end;) { 664 e.setValue(null); 665 } 666 } 667 return this; 668 } 669 670 679 private static Factory< ? extends Quantity> getInstance(Unit unit) { 680 Factory< ? extends Quantity> factory = UNIT_TO_FACTORY.get(unit); 681 if (factory != null) 682 return factory; 683 while (true) { 685 factory = COLLECTION.get(unit); 686 if (factory != null) break; 687 if (unit.getParentUnit() == unit) { 688 factory = GENERAL; 689 break; 690 } 691 unit = unit.getParentUnit(); 692 } 693 synchronized (UNIT_TO_FACTORY) { 694 UNIT_TO_FACTORY.put(unit, factory); 695 } 696 return factory; 697 } 698 } 699 700 private Quantity setRangeExact(double min, double max) { 701 _minimum = min; 702 _maximum = max; 703 return this; 704 } 705 706 private Quantity setRangeApprox(double min, double max) { 707 if (min >= 0) { _minimum = min * DECREMENT; 709 _maximum = max + max * DOUBLE_RELATIVE_ERROR; 710 } else if (max <= 0) { _minimum = min + min * DOUBLE_RELATIVE_ERROR; 712 _maximum = max * DECREMENT; 713 } else { _minimum = min + min * DOUBLE_RELATIVE_ERROR; 715 _maximum = max + max * DOUBLE_RELATIVE_ERROR; 716 } 717 return this; 718 } 719 720 static { 722 org.jscience.JScience.initialize(); 723 } 724 725 private static final long serialVersionUID = 1L; 726 } | Popular Tags |