001/** 002 * Parameter -- An amount represented by a number and a unit of measure. 003 * 004 * Copyright (C) 2008-2015 by Joseph A. Huwaldt. All rights reserved. 005 * 006 * This library is free software; you can redistribute it and/or modify it under the terms 007 * of the GNU Lesser General Public License as published by the Free Software Foundation; 008 * either version 2 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, but WITHOUT ANY 011 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 012 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 013 * 014 * You should have received a copy of the GNU Lesser General Public License along with 015 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - 016 * Suite 330, Boston, MA 02111-1307, USA. Or visit: http://www.gnu.org/licenses/lgpl.html 017 */ 018package jahuwaldt.js.param; 019 020import jahuwaldt.tools.math.MathTools; 021import java.text.MessageFormat; 022import java.util.ResourceBundle; 023import javax.measure.Measurable; 024import javax.measure.converter.ConversionException; 025import javax.measure.converter.UnitConverter; 026import javax.measure.quantity.*; 027import javax.measure.unit.NonSI; 028import javax.measure.unit.SI; 029import javax.measure.unit.Unit; 030import javax.realtime.MemoryArea; 031import javolution.context.ImmortalContext; 032import javolution.context.ObjectFactory; 033import javolution.lang.MathLib; 034import javolution.lang.Realtime; 035import javolution.lang.ValueType; 036import javolution.text.Text; 037import javolution.util.FastComparator; 038import javolution.util.FastMap; 039import javolution.xml.XMLFormat; 040import javolution.xml.XMLSerializable; 041import javolution.xml.stream.XMLStreamException; 042import org.jscience.mathematics.structure.Field; 043 044/** 045 * This class represents an amount (a value with associated units) for which operations 046 * such as addition, subtraction, multiplication and division can be performed (it 047 * implements the Field interface). 048 * <p> 049 * The nature of an amount can be deduced from its parameterization (compile time) or its 050 * unit (run time).. 051 * </p> 052 * <p> 053 * Operations between different amounts may or may not be authorized based upon the 054 * current PhysicalModel. For example, adding <code>Parameter<Length></code> and 055 * <code>Parameter<Duration></code> is not allowed by the StandardModel, but is 056 * authorized with the RelativisticModel. 057 * </p> 058 * 059 * <p> Modified by: Joseph A. Huwaldt</p> 060 * 061 * @author Joseph A. Huwaldt Date: November 15, 2008 062 * @version March 10, 2017 063 * 064 * @param <Q> The Quantity (unit type, such as Length or Volume) of this parameter. 065 * 066 */ 067public final class Parameter<Q extends Quantity> implements 068 Measurable<Q>, Field<Parameter<Q>>, ValueType, Realtime, XMLSerializable { 069 070 /** 071 * Serial ID for this class. 072 */ 073 private static final long serialVersionUID = -7209871188244228767L; 074 075 /** 076 * The machine epsilon or unit roundoff for <code>double</code> in the Java 077 * environment. Machine epsilon gives an upper bound on the relative error due to 078 * rounding in floating point arithmetic. 079 */ 080 public static final double EPS = MathTools.EPS; 081 082 /** 083 * Ten times the machine epsilon or unit roundoff for <code>double</code> in the Java 084 * environment. This is 10*EPS. 085 * 086 * @see #EPS 087 */ 088 public static final double EPS10 = 10 * EPS; 089 090 /** 091 * The square-root of EPS. 092 * 093 * @see #EPS 094 */ 095 public static final double SQRT_EPS = MathLib.sqrt(EPS); 096 097 /** 098 * The resource bundle for this package. 099 */ 100 static final ResourceBundle RESOURCES 101 = ResourceBundle.getBundle("jahuwaldt.js.param.ParameterResources", java.util.Locale.getDefault()); 102 103 ////////////////////// 104 // Factory Creation // 105 ////////////////////// 106 @SuppressWarnings("unchecked") 107 private static <Q extends Quantity> Parameter<Q> newInstance(Unit<?> unit) { 108 Parameter<Q> measure = FACTORY.object(); 109 measure._unit = (Unit<Q>)unit; 110 return measure; 111 } 112 113 @SuppressWarnings("unchecked") 114 private static <Q extends Quantity> Parameter<Q> copyOf(Parameter<Q> original) { 115 Parameter<Q> measure = FACTORY.object(); 116 measure._value = original._value; 117 measure._unit = original._unit; 118 return measure; 119 } 120 121 @SuppressWarnings({"rawtypes"}) 122 private static final ObjectFactory<Parameter> FACTORY = new ObjectFactory<Parameter>() { 123 124 @Override 125 protected Parameter create() { 126 return new Parameter(); 127 } 128 }; 129 130 private Parameter() { 131 } 132 133 /** 134 * Holds a dimensionless measure of zero. 135 */ 136 public static final Parameter<Dimensionless> ZERO; 137 138 /** 139 * Holds a dimensionless measure of one. 140 */ 141 public static final Parameter<Dimensionless> ONE; 142 143 /** 144 * An angular measure of zero. 145 */ 146 public static final Parameter<Angle> ZERO_ANGLE; 147 148 /** 149 * An angular measure of <code>pi</code> or 180 degrees. 150 */ 151 public static final Parameter<Angle> PI_ANGLE; 152 153 /** 154 * An angular measure of <code>pi/2</code> or 90 degrees. 155 */ 156 public static final Parameter<Angle> HALFPI_ANGLE; 157 158 /** 159 * An angular measure of <code>2*pi</code> or 360 degrees. 160 */ 161 public static final Parameter<Angle> TWOPI_ANGLE; 162 163 /** 164 * An length measure of zero. 165 */ 166 public static final Parameter<Length> ZERO_LENGTH; 167 168 /** 169 * An area measure of zero. 170 */ 171 public static final Parameter<Area> ZERO_AREA; 172 173 /** 174 * A volume measure of zero. 175 */ 176 public static final Parameter<Volume> ZERO_VOLUME; 177 178 /** 179 * An velocity measure of zero. 180 */ 181 public static final Parameter<Velocity> ZERO_VELOCITY; 182 183 /** 184 * An acceleration measure of zero. 185 */ 186 public static final Parameter<Acceleration> ZERO_ACCELERATION; 187 188 /** 189 * A duration measure of zero. 190 */ 191 public static final Parameter<Duration> ZERO_DURATION; 192 193 /** 194 * A force measure of zero. 195 */ 196 public static final Parameter<Force> ZERO_FORCE; 197 198 /////////////////// 199 // Lookup tables // 200 /////////////////// 201 private static final FastMap<Unit<?>, FastMap<Unit<?>, Unit<?>>> MULT_LOOKUP; 202 private static final FastMap<Unit<?>, Unit<?>> INV_LOOKUP; 203 private static final FastMap<Unit<?>, FastMap<Unit<?>, UnitConverter>> CVTR_LOOKUP; 204 205 static { 206 // Forces constants to ImmortalMemory. 207 ImmortalContext.enter(); 208 try { 209 ZERO = Parameter.newInstance(Unit.ONE); 210 ZERO._value = 0; 211 212 ONE = Parameter.newInstance(Unit.ONE); 213 ONE._value = 1.0; 214 215 ZERO_ANGLE = Parameter.newInstance(Angle.UNIT); 216 ZERO_ANGLE._value = 0; 217 218 PI_ANGLE = Parameter.newInstance(NonSI.DEGREE_ANGLE); 219 PI_ANGLE._value = 180.0; 220 221 HALFPI_ANGLE = Parameter.newInstance(NonSI.DEGREE_ANGLE); 222 HALFPI_ANGLE._value = 90.0; 223 224 TWOPI_ANGLE = Parameter.newInstance(NonSI.DEGREE_ANGLE); 225 TWOPI_ANGLE._value = 360.0; 226 227 ZERO_LENGTH = Parameter.newInstance(Length.UNIT); 228 ZERO_LENGTH._value = 0; 229 230 ZERO_AREA = Parameter.newInstance(Area.UNIT); 231 ZERO_AREA._value = 0; 232 233 ZERO_VOLUME = Parameter.newInstance(Volume.UNIT); 234 ZERO_VOLUME._value = 0; 235 236 ZERO_VELOCITY = Parameter.newInstance(Velocity.UNIT); 237 ZERO_VELOCITY._value = 0; 238 239 ZERO_ACCELERATION = Parameter.newInstance(Acceleration.UNIT); 240 ZERO_ACCELERATION._value = 0; 241 242 ZERO_DURATION = Parameter.newInstance(Duration.UNIT); 243 ZERO_DURATION._value = 0; 244 245 ZERO_FORCE = Parameter.newInstance(Force.UNIT); 246 ZERO_FORCE._value = 0; 247 248 MULT_LOOKUP = new FastMap<Unit<?>, FastMap<Unit<?>, Unit<?>>>("UNITS_MULT_2_LOOKUP").setKeyComparator(FastComparator.DIRECT); 249 INV_LOOKUP = new FastMap<Unit<?>, Unit<?>>("UNITS_INV_2_LOOKUP").setKeyComparator(FastComparator.DIRECT); 250 CVTR_LOOKUP = new FastMap<Unit<?>, FastMap<Unit<?>, UnitConverter>>("UNITS_CVTR_2_LOOKUP").setKeyComparator(FastComparator.DIRECT); 251 252 } finally { 253 ImmortalContext.exit(); 254 } 255 } 256 257 /** 258 * Holds the value stated in this measure's unit. 259 */ 260 private double _value; 261 262 /** 263 * Holds this measure's unit. 264 */ 265 private Unit<Q> _unit; 266 267 /** 268 * Returns the measure corresponding to a value (<code>double</code>) stated in the 269 * specified unit. 270 * 271 * @param <Q> The Quantity (unit type) of this parameter. 272 * @param value the value stated in the specified unit. 273 * @param unit the unit in which the value is stated. 274 * @return the corresponding measure object. 275 */ 276 public static <Q extends Quantity> Parameter<Q> valueOf(double value, Unit<Q> unit) { 277 if (unit == null) 278 throw new NullPointerException( 279 MessageFormat.format(RESOURCES.getString("paramNullErr"), "unit")); 280 Parameter<Q> m = Parameter.newInstance(unit); 281 m._value = value; 282 return m; 283 } 284 285 /** 286 * Returns the measure represented by the specified character sequence. 287 * 288 * @param csq the character sequence. 289 * @return <code>ParameterFormat.newInstance().parse(csq)</code> 290 */ 291 public static Parameter<?> valueOf(CharSequence csq) { 292 return ParameterFormat.newInstance().parse(csq); 293 } 294 295 /** 296 * Returns the unit in which the {@link #getValue() 297 * value} is stated. 298 * 299 * @return the measure unit. 300 */ 301 public Unit<Q> getUnit() { 302 return _unit; 303 } 304 305 /** 306 * Returns the value for this measure stated in this measure's {@link #getUnit unit}. 307 * 308 * @return the value of the measure. 309 */ 310 public double getValue() { 311 return _value; 312 } 313 314 /** 315 * Returns the measure equivalent to this measure but stated in the specified unit. 316 * 317 * @param <R> The Quantity (unit type) to convert this parameter to. 318 * @param unit the unit of the measure to be returned. 319 * @return a measure equivalent to this measure but stated in the specified unit. 320 * @throws ConversionException if the current model does not allows for conversion to 321 * the specified unit. 322 */ 323 public <R extends Quantity> Parameter<R> to(Unit<R> unit) throws ConversionException { 324 if ((_unit == unit) || this._unit.equals(unit)) 325 return (Parameter<R>)this; 326 UnitConverter cvtr = Parameter.converterOf(_unit, unit); 327 if (cvtr == UnitConverter.IDENTITY) { // No conversion necessary. 328 Parameter<R> result = (Parameter<R>)Parameter.copyOf(this); 329 result._unit = unit; 330 return result; 331 } 332 Parameter<R> result = Parameter.newInstance(unit); 333 double value = cvtr.convert(_value); 334 result._value = value; 335 return result; 336 } 337 338 /** 339 * Casts this Parameter to a parameterized unit of specified nature or throw a 340 * <code>ClassCastException</code> if the dimension of the specified quantity and this 341 * parameter's unit dimension do not match. 342 * 343 * @param <T> The Quantity (unit type) to cast this parameter as. 344 * @param type the quantity class identifying the nature of the unit. 345 * @return this Parameter parameterized with the specified type. 346 * @throws ClassCastException if the dimension of this parameter's unit is different 347 * from the specified quantity dimension. 348 * @throws UnsupportedOperationException if the specified quantity class does not have 349 * a public static field named "UNIT" holding the standard unit for the quantity. 350 */ 351 public final <T extends Quantity> Parameter<T> asType(Class<T> type) throws ClassCastException { 352 @SuppressWarnings("unused") 353 Unit<T> u = _unit.asType(type); // If no exception is thrown, the cast is valid. 354 return (Parameter<T>)this; 355 } 356 357 /** 358 * Returns the opposite of this measure. 359 * 360 * @return <code>-this</code>. 361 */ 362 @Override 363 public Parameter<Q> opposite() { 364 Parameter<Q> m = Parameter.newInstance(_unit); 365 m._value = -_value; 366 return m; 367 } 368 369 /** 370 * Returns the sum of this measure with the one specified. 371 * 372 * @param that the measure to be added. 373 * @return <code>this + that</code>. 374 * @throws ConversionException if the current model does not allows for these 375 * quantities to be added. 376 */ 377 @Override 378 public Parameter<Q> plus(Parameter<Q> that) throws ConversionException { 379 Parameter<Q> m = Parameter.newInstance(_unit); 380 double value = this._value + that.getValue(_unit); 381 m._value = value; 382 return m; 383 } 384 385 /** 386 * Returns the difference of this measure with the one specified. 387 * 388 * @param that the measure to be subtracted. 389 * @return <code>this - that</code>. 390 * @throws ConversionException if the current model does not allows for these 391 * quantities to be subtracted. 392 */ 393 public Parameter<Q> minus(Parameter<Q> that) throws ConversionException { 394 Parameter<Q> m = Parameter.newInstance(_unit); 395 double value = this._value - that.getValue(_unit); 396 m._value = value; 397 return m; 398 } 399 400 /** 401 * Returns this measure scaled by the specified approximate factor (dimensionless). 402 * 403 * @param factor the scaling factor. 404 * @return <code>this · factor</code>. 405 */ 406 public Parameter<Q> times(double factor) { 407 Parameter<Q> m = Parameter.newInstance(_unit); 408 double value = _value * factor; 409 m._value = value; 410 return m; 411 } 412 413 /** 414 * Returns the product of this measure with the one specified. 415 * 416 * @param that the measure multiplier. 417 * @return <code>this · that</code>. 418 */ 419 @Override 420 public Parameter times(Parameter that) { 421 Unit unit = Parameter.productOf(this._unit, that._unit); 422 Parameter m = Parameter.newInstance(unit); 423 double value = _value * that._value; 424 m._value = value; 425 return m; 426 } 427 428 /** 429 * Returns the multiplicative inverse of this measure. If this measure is possibly 430 * zero, then the result is unbounded (]-infinity, +infinity[). 431 * 432 * @return <code>1 / this</code>. 433 */ 434 @Override 435 public Parameter<Q> inverse() { 436 Parameter<Q> m = newInstance(Parameter.inverseOf(_unit)); 437 if (this._value == 1.0) { 438 m._value = 1; 439 return m; 440 } 441 double value = 1.0 / _value; 442 m._value = value; 443 return m; 444 } 445 446 /** 447 * Returns this measure divided by the specified approximate divisor (dimensionless). 448 * 449 * @param divisor the approximated divisor. 450 * @return <code>this / divisor</code>. 451 */ 452 public Parameter<Q> divide(double divisor) { 453 Parameter<Q> m = Parameter.newInstance(_unit); 454 double value = _value / divisor; 455 m._value = value; 456 return m; 457 } 458 459 /** 460 * Returns this measure divided by the one specified. 461 * 462 * @param that the measure divisor. 463 * @return <code>this / that</code>. 464 */ 465 @SuppressWarnings("unchecked") 466 public Parameter<? extends Quantity> divide(Parameter<?> that) { 467 return this.times(that.inverse()); 468 } 469 470 /** 471 * Returns the absolute value of this measure. 472 * 473 * @return <code>|this|</code>. 474 */ 475 public Parameter<Q> abs() { 476 return (_value >= 0) ? this : this.opposite(); 477 } 478 479 /** 480 * Returns the square root of this measure. 481 * 482 * @return <code>sqrt(this)</code> 483 * 484 */ 485 public Parameter<? extends Quantity> sqrt() { 486 Parameter<Q> m = Parameter.newInstance(_unit.root(2)); 487 double value = MathLib.sqrt(_value); 488 m._value = value; 489 return m; 490 } 491 492 /** 493 * Returns the given root of this measure. 494 * 495 * @param n the root's order (n != 0). 496 * @return the result of taking the given root of this quantity. 497 * @throws ArithmeticException if <code>n == 0</code>. 498 */ 499 public Parameter<? extends Quantity> root(int n) { 500 if (n == 0) 501 throw new ArithmeticException(RESOURCES.getString("badRootOrder")); 502 if (n < 0) 503 return this.root(-n).inverse(); 504 if (n == 2) 505 return this.sqrt(); 506 Parameter<Q> m = Parameter.newInstance(_unit.root(n)); 507 double value = MathLib.pow(_value, 1.0 / n); 508 m._value = value; 509 return m; 510 } 511 512 /** 513 * Returns this measure raised at the specified exponent. 514 * 515 * @param exp the exponent. 516 * @return <code>this<sup>exp</sup></code> 517 */ 518 public Parameter<? extends Quantity> pow(int exp) { 519 if (exp < 0) 520 return this.pow(-exp).inverse(); 521 if (exp == 0) 522 return ONE; 523 Parameter<?> pow2 = this; 524 Parameter<?> result = null; 525 while (exp >= 1) { // Iteration. 526 if ((exp & 1) == 1) { 527 result = (result == null) ? pow2 : result.times(pow2); 528 } 529 pow2 = pow2.times(pow2); 530 exp >>>= 1; 531 } 532 return result; 533 } 534 535 /** 536 * Compares this measure with the specified measurable object. 537 * 538 * @param that the measure to compare with. 539 * @return a negative integer, zero, or a positive integer as this measure is less 540 * than, equal to, or greater than that measurable. 541 * @throws ConversionException if the current model does not allows for these measure 542 * to be compared. 543 */ 544 @Override 545 public int compareTo(Measurable<Q> that) { 546 double thatValue = that.doubleValue(_unit); 547 return Double.compare(_value, thatValue); 548 } 549 550 /** 551 * Compares this parameter against the specified object for strict equality (same 552 * value and same units). 553 * 554 * @param that the object to compare with. 555 * @return <code>true</code> if this measure is identical to that measure; 556 * <code>false</code> otherwise. 557 */ 558 @Override 559 public boolean equals(Object that) { 560 if (this == that) 561 return true; 562 if ((that == null) || (that.getClass() != this.getClass())) 563 return false; 564 565 Parameter<?> m = (Parameter<?>)that; 566 if (!_unit.equals(m._unit)) 567 return false; 568 return _value == m._value; 569 } 570 571 /** 572 * Returns the hash code for this parameter. 573 * 574 * @return the hash code value. 575 */ 576 @Override 577 public int hashCode() { 578 int hash = 7; 579 580 int var_code = (null == _unit ? 0 : _unit.hashCode()); 581 hash = hash * 31 + var_code; 582 583 long bits = Double.doubleToLongBits(_value); 584 var_code = (int)(bits ^ (bits >>> 32)); 585 hash = hash * 31 + var_code; 586 587 return hash; 588 } 589 590 /** 591 * Indicates if this measure is ordered before that measure (independently of the 592 * measure unit). 593 * 594 * @param that The measure being compared with this one. 595 * @return this < that 596 */ 597 public boolean isLessThan(Parameter<Q> that) { 598 return this.compareTo(that) < 0; 599 } 600 601 /** 602 * Indicates if this measure is ordered after that measure (independently of the 603 * measure unit). 604 * 605 * @param that The measure being compared with this one. 606 * @return this > that 607 */ 608 public boolean isGreaterThan(Parameter<Q> that) { 609 return this.compareTo(that) > 0; 610 } 611 612 /** 613 * Compares this measure with that measure ignoring the sign. 614 * 615 * @param that The measure being compared with this one. 616 * @return <code>|this| > |that|</code> 617 */ 618 public boolean isLargerThan(Parameter<Q> that) { 619 return this.abs().isGreaterThan(that.abs()); 620 } 621 622 /** 623 * Compares this measure with that measure for approximate equality. Approximate 624 * equality means that the two parameters, stated in this parameter's units, differ by 625 * an amount less than the machine epsilon. 626 * 627 * @param that The measure being compared with this one. 628 * @return <code>this ~= that</code> 629 */ 630 public boolean isApproxEqual(Parameter<Q> that) { 631 // First check for exact object equality. 632 if (this == that) 633 return true; 634 if (that == null) 635 return false; 636 637 // Now check for approximate equality. 638 double thisVal = this.getValue(); 639 double thatVal = that.getValue(this._unit); 640 return MathTools.isApproxEqual(thisVal, thatVal); 641 } 642 643 /** 644 * Compares this measure with that measure for approximate equality. Approximate 645 * equality means that the two parameters differ by an amount less than the supplied 646 * tolerance. 647 * 648 * @param that The measure being compared with this one. 649 * @param tol The tolerance used to determine floating point equality. If 650 * <code>null</code> is passed, then a tolerance of machine epsilon is 651 * assumed. 652 * @return <code>this ~= that</code> 653 */ 654 public boolean isApproxEqual(Parameter<Q> that, Parameter<Q> tol) { 655 // First check for exact equality. 656 if (this == that) 657 return true; 658 if (that == null) 659 return false; 660 661 // Now check for approximate equality. 662 double thisVal = this.getValue(); 663 double thatVal = that.getValue(this._unit); 664 665 if (tol != null) { 666 double tolVal = tol.getValue(this._unit); 667 return (MathLib.abs(thisVal - thatVal) <= tolVal); 668 } 669 return MathTools.isApproxEqual(thisVal, thatVal); 670 } 671 672 /** 673 * Compares this measure with zero for approximate equality. Approximately zero means 674 * that this parameter differs from zero by an amount less than machine epsilon. 675 * 676 * @return <code>this ~= 0</code> 677 */ 678 public boolean isApproxZero() { 679 // Check for approximate equality. 680 return (MathLib.abs(this.getValue()) <= EPS); 681 } 682 683 /** 684 * Returns the minimum of this parameter and the specified one. 685 * 686 * @param that The measure being compared with this one. 687 * @return The minimum of this parameter and the specified one. 688 */ 689 public Parameter<Q> min(Parameter<Q> that) { 690 if (this.isGreaterThan(that)) 691 return that; 692 return this; 693 } 694 695 /** 696 * Returns the maximum of this parameter and the specified one. 697 * 698 * @param that The measure being compared with this one. 699 * @return The maximum of this parameter and the specified one. 700 */ 701 public Parameter<Q> max(Parameter<Q> that) { 702 if (this.isLessThan(that)) 703 return that; 704 return this; 705 } 706 707 /** 708 * Return a new parameter with the value of this parameter rounded to the nearest ones 709 * place. 710 * 711 * @return A new parameter with the value of this parameter rounded. 712 */ 713 public Parameter<Q> round() { 714 return valueOf(MathLib.round(getValue()), getUnit()); 715 } 716 717 /** 718 * Return a new parameter with the value of this parameter rounded to the specified 719 * decimal place. 720 * 721 * @param place Number of decimal places to round the value to. A place of 1 rounds to 722 * 10's place, 2 to 100's place, -2 to 1/100th place, et cetera. 723 * @return A new parameter with the value of this parameter rounded. 724 */ 725 public Parameter<Q> roundToPlace(int place) { 726 return valueOf(MathTools.roundToPlace(getValue(), place), getUnit()); 727 } 728 729 /** 730 * Returns <code>true</code> if this <code>Parameter</code> value is a Not-a-Number 731 * (NaN), <code>false</code> otherwise. 732 * 733 * @return <code>true</code> if the value represented by this object is NaN; 734 * <code>false</code> otherwise. 735 */ 736 public boolean isNaN() { 737 return Double.isNaN(_value); 738 } 739 740 /** 741 * Returns <code>true</code> if this <code>Parameter</code> value is infinitely large 742 * in magnitude, <code>false</code> otherwise. 743 * 744 * @return <code>true</code> if the value represented by this object is positive 745 * infinity or negative infinity; <code>false</code> otherwise. 746 */ 747 public boolean isInfinite() { 748 return Double.isInfinite(_value); 749 } 750 751 /** 752 * Returns the text representation of this parameter. 753 * 754 * @return <code>ParameterFormat.newInstance().format(this)</code> 755 */ 756 @Override 757 public Text toText() { 758 return ParameterFormat.newInstance().format(this); 759 } 760 761 /** 762 * Returns the text representation of this parameter as a 763 * <code>java.lang.String</code>. 764 * 765 * @return <code>toText().toString()</code> 766 */ 767 @Override 768 public final String toString() { 769 return toText().toString(); 770 } 771 772 /** 773 * Returns the value of this measurable stated in the specified unit as a 774 * <code>double</code>. This is an alternate to getValue(unit). 775 * 776 * @param unit the unit in which this measurable value is stated. 777 * @return the numeric value after conversion to type <code>double</code>. 778 * @see #getValue(javax.measure.unit.Unit) 779 * @see #getValue() 780 */ 781 @Override 782 public double doubleValue(Unit<Q> unit) { 783 return getValue(unit); 784 } 785 786 /** 787 * Returns the value of this measurable stated in the specified unit as a 788 * <code>double</code>. 789 * 790 * @param unit the unit in which this measurable value is stated. 791 * @return the numeric value after conversion to type <code>double</code>. 792 * @see #getValue() 793 */ 794 public double getValue(Unit<Q> unit) { 795 if (_unit.equals(unit)) 796 return _value; 797 UnitConverter cvtr = Parameter.converterOf(_unit, unit); 798 if (cvtr == UnitConverter.IDENTITY) { // No conversion necessary. 799 return _value; 800 } 801 return cvtr.convert(_value); 802 } 803 804 /** 805 * Returns the estimated integer value of this measurable stated in the specified unit 806 * as a <code>long</code>. 807 * <p> 808 * Note: This method differs from the <code>Number.longValue()</code> in the sense 809 * that the closest integer value is returned and an ArithmeticException is raised 810 * instead of a bit truncation in case of overflow (safety critical). 811 * </p> 812 * 813 * @param unit the unit in which the measurable value is stated. 814 * @return the numeric value after conversion to type <code>long</code>. 815 * @throws ArithmeticException if this quantity cannot be represented as a 816 * <code>long</code> number in the specified unit. 817 */ 818 @Override 819 public final long longValue(Unit<Q> unit) { 820 if (!_unit.equals(unit)) 821 return this.to(unit).longValue(unit); 822 double doubleValue = this.getValue(); 823 if ((doubleValue >= Long.MIN_VALUE) && (doubleValue <= Long.MAX_VALUE)) 824 return Math.round(doubleValue); 825 throw new ArithmeticException( 826 MessageFormat.format(RESOURCES.getString("canNotBeLong"), doubleValue, _unit)); 827 } 828 829 /** 830 * Returns a copy of this Parameter allocated by the calling thread (possibly on the stack). 831 * 832 * @return an identical and independent copy of this Parameter. 833 */ 834 @Override 835 public Parameter<Q> copy() { 836 return copyOf(this); 837 } 838 839 //////////////////////// 840 // Public Static Methods 841 //////////////////////// 842 /** 843 * Returns the trigonometric cosine of the specified angle. 844 * 845 * @param angle The angle to calculate the cosine of. 846 * @return The cosine of the specified angle. 847 */ 848 public static Parameter<Dimensionless> cos(Parameter<Angle> angle) { 849 double ca = MathLib.cos(angle.getValue(SI.RADIAN)); 850 return Parameter.valueOf(ca, Dimensionless.UNIT); 851 } 852 853 /** 854 * Returns the trigonometric sine of the specified angle. 855 * 856 * @param angle The angle to calculate the sine of. 857 * @return The sine of the specified angle. 858 */ 859 public static Parameter<Dimensionless> sin(Parameter<Angle> angle) { 860 double ca = MathLib.sin(angle.getValue(SI.RADIAN)); 861 return Parameter.valueOf(ca, Dimensionless.UNIT); 862 } 863 864 /** 865 * Returns the trigonometric tangent of the specified angle. 866 * 867 * @param angle The angle to calculate the tangent of. 868 * @return The tangent of the specified angle. 869 */ 870 public static Parameter<Dimensionless> tan(Parameter<Angle> angle) { 871 double ca = MathLib.tan(angle.getValue(SI.RADIAN)); 872 return Parameter.valueOf(ca, Dimensionless.UNIT); 873 } 874 875 /** 876 * Returns the arc sine of the specified value, in the range of 877 * <code>-HALFPI_ANGLE</code> through <code>HALFPI_ANGLE</code>. 878 * 879 * @param x The value to calculate the inverse-sine of. 880 * @return The angle represented by the inverse-sine of the specified value. 881 */ 882 public static Parameter<Angle> asin(Parameter<Dimensionless> x) { 883 double a = MathLib.asin(x.getValue()); 884 return Parameter.valueOf(a, SI.RADIAN); 885 } 886 887 /** 888 * Returns the arc cosine of the specified value, in the range of 889 * <code>ZERO_ANGLE</code> through <code>PI_ANGLE</code>. 890 * 891 * @param x The value to calculate the inverse-cosine of. 892 * @return The angle represented by the inverse-cosine of the specified value. 893 */ 894 public static Parameter<Angle> acos(Parameter<Dimensionless> x) { 895 double a = MathLib.acos(x.getValue()); 896 return Parameter.valueOf(a, SI.RADIAN); 897 } 898 899 /** 900 * Returns the arc tangent of the specified value, in the range of 901 * <code>-HALFPI_ANGLE</code> through <code>HALFPI_ANGLE</code>. 902 * 903 * @param x The value to calculate the inverse-tangent of. 904 * @return The angle represented by the inverse-tangent of the specified value. 905 */ 906 public static Parameter<Angle> atan(Parameter<Dimensionless> x) { 907 double a = MathLib.atan(x.getValue()); 908 return Parameter.valueOf(a, SI.RADIAN); 909 } 910 911 /** 912 * Returns the angle theta such that (x == cos(theta)) && (y == sin(theta)). The two 913 * parameters must be the same type of unit, but otherwise they may be in different 914 * units of the same type (e.g.: y in "km" and x in "ft"). 915 * 916 * @param <R> The Quantity (unit type) of the input parameters. 917 * @param y The the ordinate coordinate. 918 * @param x The the abscissa coordinate. 919 * @return The angle represented by the inverse-tangent of the specified values. 920 */ 921 public static <R extends Quantity> Parameter<Angle> atan2(Parameter<R> y, Parameter<R> x) { 922 double a = MathLib.atan2(y.getValue(), x.getValue(y.getUnit())); 923 return Parameter.valueOf(a, SI.RADIAN); 924 } 925 926 /** 927 * Returns the product of the two input units. 928 * 929 * @param left The left unit to multiply by the right unit. 930 * @param right The right unit to multiply by the left unit. 931 * @return The product of the two input units. 932 */ 933 public static Unit<?> productOf(Unit<?> left, Unit<?> right) { 934 FastMap<Unit<?>, Unit<?>> leftTable = MULT_LOOKUP.get(left); 935 if (leftTable == null) 936 return calculateProductOf(left, right); 937 Unit<?> result = leftTable.get(right); 938 if (result == null) 939 return calculateProductOf(left, right); 940 return result; 941 } 942 943 private static synchronized Unit<?> calculateProductOf(final Unit<?> left, final Unit<?> right) { 944 MemoryArea memoryArea = MemoryArea.getMemoryArea(MULT_LOOKUP); 945 memoryArea.executeInArea(new Runnable() { 946 @Override 947 public void run() { 948 FastMap<Unit<?>, Unit<?>> leftTable = MULT_LOOKUP.get(left); 949 if (leftTable == null) { 950 leftTable = new FastMap<Unit<?>, Unit<?>>().setKeyComparator( 951 FastComparator.DIRECT); 952 MULT_LOOKUP.put(left, leftTable); 953 } 954 Unit<?> result = leftTable.get(right); 955 if (result == null) { 956 result = left.times(right); 957 leftTable.put(right, result); 958 } 959 } 960 }); 961 return MULT_LOOKUP.get(left).get(right); 962 } 963 964 private static Unit<?> inverseOf(Unit<?> unit) { 965 Unit<?> inverse = INV_LOOKUP.get(unit); 966 if (inverse == null) 967 return calculateInverseOf(unit); 968 return inverse; 969 } 970 971 private static synchronized Unit<?> calculateInverseOf(final Unit<?> unit) { 972 MemoryArea memoryArea = MemoryArea.getMemoryArea(INV_LOOKUP); 973 memoryArea.executeInArea(new Runnable() { 974 @Override 975 public void run() { 976 Unit<?> inverse = INV_LOOKUP.get(unit); 977 if (inverse == null) { 978 inverse = unit.inverse(); 979 INV_LOOKUP.put(unit, inverse); 980 } 981 } 982 }); 983 return INV_LOOKUP.get(unit); 984 } 985 986 /** 987 * Returns a unit converter that will convert between the specified units. 988 * 989 * @param left The unit to convert from. 990 * @param right The unit to convert to. 991 * @return The converter between the specified units. 992 */ 993 public static UnitConverter converterOf(Unit<?> left, Unit<?> right) throws ConversionException { 994 FastMap<Unit<?>, UnitConverter> leftTable = CVTR_LOOKUP.get(left); 995 if (leftTable == null) 996 return calculateConverterOf(left, right); 997 UnitConverter result = leftTable.get(right); 998 if (result == null) 999 return calculateConverterOf(left, right); 1000 return result; 1001 } 1002 1003 private static synchronized UnitConverter calculateConverterOf(final Unit<?> left, 1004 final Unit<?> right) throws ConversionException { 1005 MemoryArea memoryArea = MemoryArea.getMemoryArea(CVTR_LOOKUP); 1006 memoryArea.executeInArea(new Runnable() { 1007 @Override 1008 public void run() { 1009 FastMap<Unit<?>, UnitConverter> leftTable = CVTR_LOOKUP.get(left); 1010 if (leftTable == null) { 1011 leftTable = new FastMap<Unit<?>, UnitConverter>().setKeyComparator(FastComparator.DIRECT); 1012 synchronized (CVTR_LOOKUP) { 1013 CVTR_LOOKUP.put(left, leftTable); 1014 } 1015 } 1016 UnitConverter result = leftTable.get(right); 1017 if (result == null) { 1018 result = left.getConverterTo(right); 1019 synchronized (leftTable) { 1020 leftTable.put(right, result); 1021 } 1022 } 1023 } 1024 }); 1025 return CVTR_LOOKUP.get(left).get(right); 1026 } 1027 1028 /** 1029 * Holds the default XML representation for the Parameter class. This representation 1030 * consists of a <code>value</code>, and an <code>unit</code>. The unit attribute 1031 * determines the Parameter type. For example: 1032 * <pre><Parameter value="12" unit="µA"/></pre> represents an electric current 1033 * measurement. 1034 */ 1035 protected static final XMLFormat<Parameter> XML = new XMLFormat<Parameter>(Parameter.class) { 1036 1037 @Override 1038 public Parameter newInstance(Class<Parameter> cls, InputElement xml) throws XMLStreamException { 1039 Unit unit = Unit.valueOf(xml.getAttribute("unit")); 1040 Parameter<?> m = Parameter.newInstance(unit); 1041 double value = xml.getAttribute("value", 0.0); 1042 m._value = value; 1043 return m; 1044 } 1045 1046 @Override 1047 public void read(javolution.xml.XMLFormat.InputElement arg0, Parameter arg1) throws XMLStreamException { 1048 // Nothing to do. 1049 } 1050 1051 @Override 1052 public void write(Parameter m, OutputElement xml) throws XMLStreamException { 1053 xml.setAttribute("value", m._value); 1054 xml.setAttribute("unit", m._unit.toString()); 1055 } 1056 }; 1057 1058 /** 1059 * Testing code for this class. 1060 * 1061 * @param args Command line arguments (not used). 1062 */ 1063 @SuppressWarnings("unchecked") 1064 public static void main(String args[]) { 1065 // insert code here... 1066 System.out.println("Testing Parameter: test = result [correct result]"); 1067 1068 Parameter<Length> p1 = Parameter.valueOf(2, NonSI.FOOT); 1069 System.out.println("p1 = " + p1); 1070 System.out.println(" converted to m = " + p1.to(SI.METER) + " [0.6096 m]"); 1071 System.out.println(" opposite = " + p1.opposite() + " [-2.0 ft]"); 1072 System.out.println(" p1.inverse() = " + p1.inverse() + " [0.5 1/ft]"); 1073 System.out.println(" p1.abs() = " + p1.abs() + " [2.0 ft]"); 1074 System.out.println(" p1.opposite().abs() = " + p1.opposite().abs() + " [2.0 ft]"); 1075 System.out.println(" p1.sqrt() = " + p1.sqrt() + " [1.4142135623731 ft^1:2]"); 1076 System.out.println(" p1.root(3) = " + p1.root(3) + " [1.25992104989487 ft^1:3]"); 1077 System.out.println(" p1.pow(5) = " + p1.pow(5) + " [32.0 ft^5]"); 1078 1079 Parameter<Length> p2 = Parameter.valueOf(1, SI.METER); 1080 System.out.println("p2 = " + p2); 1081 System.out.println(" p1 + p2 = " + p1.plus(p2) + " [5.28083989501312 ft]"); 1082 System.out.println(" p1 - p2 = " + p1.minus(p2) + " [-1.28083989501312 ft]"); 1083 System.out.println(" p1*2 = " + p1.times(2) + " [4.0 ft]"); 1084 System.out.println(" p1*ZERO = " + p1.times(ZERO) + " [0.0 ft]"); 1085 System.out.println(" p1 * p2 = " + p1.times(p2)); 1086 System.out.println(" converted to ft² = " + p1.times(p2).to(NonSI.SQUARE_FOOT) + " [6.56167979002625 ft²]"); 1087 System.out.println(" p1 / 2 = " + p1.divide(2) + " [1.0 ft]"); 1088 System.out.println(" p1 / p2 = " + p1.divide(p2)); 1089 System.out.println(" converted to dimensionless = " + p1.divide(p2).to(Dimensionless.UNIT) + " [0.6096]"); 1090 System.out.println(" p1.compareTo(p2) = " + p1.compareTo(p2) + " [-1]"); 1091 System.out.println(" p2.compareTo(p1) = " + p2.compareTo(p1) + " [1]"); 1092 System.out.println(" p1.compareTo(p1) = " + p1.compareTo(p1) + " [0]"); 1093 System.out.println(" p1.equals(p1) = " + p1.equals(p1) + " [true]"); 1094 System.out.println(" p1.equals(p2) = " + p1.equals(p2) + " [false]"); 1095 System.out.println(" p1.equals(p1.to(SI.METER)) = " + p1.equals(p1.to(SI.METER)) + " [false]"); 1096 System.out.println(" p1.isLessThan(p2) = " + p1.isLessThan(p2) + " [true]"); 1097 System.out.println(" p1.isGreaterThan(p2) = " + p1.isGreaterThan(p2) + " [false]"); 1098 System.out.println(" p1.isLargerThan(p2) = " + p1.isLargerThan(p2) + " [false]"); 1099 1100 Parameter<Length> p3 = Parameter.valueOf(-1, SI.METER); 1101 System.out.println("p3 = " + p3); 1102 System.out.println(" p3.isGreaterThan(p1) = " + p3.isGreaterThan(p1) + " [false]"); 1103 System.out.println(" p3.isLargerThan(p1) = " + p3.isLargerThan(p1) + " [true]"); 1104 1105 Parameter<?> a1 = Parameter.valueOf("2.5 ft^2"); 1106 System.out.println("Parameter.valueOf(\"2.5 ft^2\") = " + a1); 1107 1108 // Write out XML data. 1109 try { 1110 System.out.println(); 1111 1112 // Creates some useful aliases for class names. 1113 javolution.xml.XMLBinding binding = new javolution.xml.XMLBinding(); 1114 //binding.setAlias(org.jscience.mathematics.number.Float64.class, "Float64"); 1115 1116 javolution.xml.XMLObjectWriter writer = javolution.xml.XMLObjectWriter.newInstance(System.out); 1117 writer.setIndentation(" "); 1118 writer.setBinding(binding); 1119 writer.write(a1, "Parameter", Parameter.class); 1120 writer.flush(); 1121 1122 System.out.println(); 1123 } catch (Exception e) { 1124 e.printStackTrace(); 1125 } 1126 1127 } 1128}