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&lt;Length&gt;</code> and
055 * <code>Parameter&lt;Duration&gt;</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>&lt;Parameter value="12" unit="µA"/&gt;</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}