Java API By Example, From Geeks To Geeks.

# Java > Open Source Codes > org > jscience > physics > quantities > Quantity

 `1 /*2  * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.3  * Copyright (C) 2005 - JScience (http://jscience.org/)4  * All rights reserved.5  * 6  * Permission to use, copy, modify, and distribute this software is7  * freely granted, provided that this notice is preserved.8  */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 /**24  *

This class represents a measurable amount. The nature of the amount25  * is deduced from the quantity unit. The quality of the measurement26  * is given by the measurement error.

27  * 28  *

Errors (including numeric errors) are calculated using numeric intervals.29  * It is possible to resolve systems of linear equations involving physical30  * quantities (e.g. using {@link org.jscience.mathematics.matrices.Matrix}),31  * even if the system is close to singularity; in which case the error 32  * associated with some (or all) components of the solution may be large.33  *

34  * 35  *

The decimal representations of quantities instances are indicative of36  * their precision as only digits guaranteed to be exact are written out.37  * For example, the string "2.000 km/s" represents a 38  * {@link Velocity} of (2.0 ± 0.001) km/s.

39  * 40  *

Finally, operations between quantities may or may not be authorized 41  * based upon the current {@link org.jscience.physics.models.PhysicalModel42  * PhysicalModel} (e.g. adding a {@link Length length} to a {@link Duration43  * duration} is not allowed by the 44  * {@link org.jscience.physics.models.StandardModel StandardModel}, 45  * but is authorized with the {@link46  * org.jscience.physics.models.RelativisticModel RelativisticModel}).

47  * 48  * @author Jean-Marie Dautelle49  * @version 2.0, June 6, 200550  */51 public class Quantity extends Number {52 53     /**54      * Holds the default XML representation for physical quantities.55      * This representation consists of an amount and 56      * an unit attribute.57      * The unit attribute determinates the quantity type. For example:
58       * <Quantity amount="12.3" unit="µA"/>
59      * represents an {@link ElectricCurrent} instance.60      */61     private static final XmlFormat XML = new XmlFormat(62             Quantity.class) {63         public void format(Quantity q, XmlElement xml) {64             xml.setAttribute("amount", q.getAmount());65 // xml.newAttribute("error")66 // .append(q.getAbsoluteError(), 4, false, false);67 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 // double error = xml.getAttribute("error", 0.0);75 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     /**82      * Holds the relative error due to the inexact representation of83      * double values (64 bits IEEE 754 format).84      */85     static final double DOUBLE_RELATIVE_ERROR = MathLib.pow(2, -53);86 87     /**88      * Holds the factor decrementing double values by89      * exactly one LSB.90      */91     static final double DECREMENT = (1.0 - DOUBLE_RELATIVE_ERROR);92 93     /**94      * Holds this quantity unit. 95      */96     private Unit _unit;97 98     /**99      * Holds the minimum amount stated in this quantity base units100      */101     private double _minimum; 102 103     /**104      * Holds the maximum amount stated in this quantity base units.105      */106     private double _maximum; 107 108     //////////////////109 // Construction //110 //////////////////111 112     /**113      * Default constructor.114      */115     protected Quantity() {116     }117 118     /**119      * Returns the quantity corresponding to the specified character sequence.120      * The unit of the specified quantity determinates the class of the quantity121      * being returned. For example:
Quantity.valueOf("1.2 GeV")
122      * returns an {@link Energy} instance.123      *124      * @param csq the character sequence.125      * @return QuantityFormat.current().parse(csq)126      * @throws IllegalArgumentException if the specified character sequence 127      * cannot be parsed.128      * @see QuantityFormat129      */130     public static Q valueOf(CharSequence csq) {131         return (Q) QuantityFormat.current().parse(csq);132     }133 134     /**135      * Returns the quantity for the specified amount.136      * The specified unit determinates the class of the quantity being returned.137      * For example:
Quantity.valueOf(30, NonSI.FOOT)
138      * returns a {@link Length} instance.139      *140      * @param amount the estimated amount (± 1/2 LSB).141      * @param unit the amount's unit.142      * @return the corresponding quantity.143      */144     public static Q valueOf(double amount, Unit unit) {145         Converter cvtr = unit.toBaseUnits();146         double value = cvtr.convert(amount);147         return (Q) newInstance(unit).setRangeApprox(value, value);148     }149 150     /**151      * Returns the quantity of specified amount and measurement error.152      * The specified unit determinates the class of the quantity being returned.153      * For example:
Quantity.valueOf(20, 0.1, SI.KILO(SI.HERTZ))
154      * returns a {@link Frequency} instance.155      *156      * @param amount the estimated amount (± error).157      * @param error the measurement error (absolute).158      * @param unit the amount's unit.159      * @return the corresponding quantity.160      */161     public static Q valueOf(double amount, double error,162             Unit 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     /**170      * Returns the quantity whose amount is in the specified range.171      *172      * @param minimum the lower bound for the quantity amount.173      * @param maximum the upper bound of the quantity amount.174      * @param unit the bounds unit.175      * @return the corresponding quantity.176      */177     public static Q rangeOf(double minimum,178             double maximum, Unit 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     /**186      * Returns this quantity estimated amount stated in this quantity187      * {@link #getUnit unit}.188      *189      * @return this quantity estimated amount.190      */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     /**198      * Returns the unit identifying this quantity type; it is also 199      * the unit in which this quantity is displayed by default.200      *201      * @return the unit for this quantity.202      */203     public Unit getUnit() {204         return _unit;205     }206 207     /**208      * Returns the minimum value for this quantity stated in base units.209      *210      * @return the minimum value.211      */212     public final double getMinimum() {213         return _minimum;214     }215 216     /**217      * Returns the maximum value for this quantity stated in base units.218      *219      * @return the maximum amount value.220      */221     public final double getMaximum() {222         return _maximum;223     }224 225     /**226      * Returns the value by which the {@link #doubleValue estimated value}227      * may differ from the true value (all stated in base units).228      *229      * @return the absolute error stated in base units.230      */231     public final double getAbsoluteError() {232         return MathLib.abs(_maximum - _minimum) / 2.0;233     }234 235     /**236      * Returns the percentage by which the estimated amount may differ237      * from the true amount.238      *239      * @return the relative error.240      */241     public final double getRelativeError() {242         return (_maximum - _minimum) / (_minimum + _maximum);243     }244 245     ////////////////246 // Operations //247 ////////////////248 249     /**250      * Returns the quantity equivalent to this quantity but stated 251      * using the specified unit. This method may return a quantity 252      * of different type than this quantity (the unit determinates 253      * the quantity sub-class). 254      *255      * @param unit the unit of the quantity being returned.256      * @return a quantity equivalent to this unit but stated using 257      * a different unit.258      * @throws ConversionException if the current model does not allows for259      * conversion to the specified unit.260      */261     public final Q to(Unit unit) {262         Quantity q = newInstance(unit);263         if (!needConversionTo(unit)) // Most likely.264 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     /**273      * Returns the opposite of this quantity.274      *275      * @return -this.276      */277     public final Quantity opposite() {278         return Quantity.newInstance(_unit).setRangeExact(-_maximum, -_minimum);279     }280 281     /**282      * Returns the sum of this quantity with the one specified.283      *284      * @param that the quantity to be added.285      * @return this + that.286      * @throws ConversionException if the current model does not allows for287      * these quantities to be added.288      */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     /**297      * Returns the difference of this quantity with the one specified.298      *299      * @param that the quantity to be subtracted.300      * @return this - that.301      * @throws ConversionException if the current model does not allows for302      * these quantities to be subtracted.303      */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     /**312      * Returns this quantity multiplied by the specified factor.313      *314      * @param factor the multiplier.315      * @return this * factor.316      */317     public final Quantity times(double factor) {318         return (factor > 0) ? Quantity.newInstance(_unit).setRangeApprox(319                 this._minimum * factor, this._maximum * factor) : Quantity320                 .newInstance(_unit).setRangeApprox(this._maximum * factor,321                         this._minimum * factor);322     }323 324     /**325      * Returns the product of this quantity with the one specified.326      *327      * @param that the quantity multiplier.328      * @return this * that.329      */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 { // Both around zero.362 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     /**371      * Returns the reciprocal of this quantity.372      * If this quantity is possbily zero, then the resulting quantity373      * is unbounded.374      *375      * @return 1 / this.376      */377     public final Quantity reciprocal() {378         Quantity q = newInstance(_unit.inverse());379         if ((_minimum <= 0) && (_maximum >= 0)) { // Encompass zero.380 return q.setRangeExact(Double.NEGATIVE_INFINITY,381                     Double.POSITIVE_INFINITY);382         }383         return q.setRangeApprox(1.0 / _maximum, 1.0 / _minimum);384     }385 386     /**387      * Returns this quantity divided by the specified divisor.388      *389      * @param divisor the divisor.390      * @return this / divisor.391      */392     public final Quantity divide(double divisor) {393         return (divisor > 0) ? Quantity.newInstance(_unit).setRangeApprox(394                 this._minimum / divisor, this._maximum / divisor) : Quantity395                 .newInstance(_unit).setRangeApprox(this._maximum / divisor,396                         this._minimum / divisor);397     }398 399     /**400      * Returns the square root of this quantity.401      *402      * @return sqrt(this)403      */404     public final Quantity sqrt() {405         return newInstance(_unit.root(2)).setRangeApprox(406                 MathLib.sqrt(_minimum), MathLib.sqrt(_maximum));407     }408 409     /**410      * Returns the given root of this quantity.411      *412      * @param n the root's order (n >= 0).413      * @return the result of taking the given root of this quantity.414      * @throws ArithmeticException if n == 0.415      */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), MathLib420                     .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     /**429      * Returns the magnitude (positive) of this quantity.430      *431      * @return |this|.432      */433     public final Quantity norm() {434         return (_minimum >= -_maximum) ? this : this.opposite();435     }436 437     /**438      * Compares this quantity amount with that quantity amount ignoring 439      * the sign.440      *441      * @return |this| > |that|442      */443     public final boolean isLargerThan(Quantity that) {444         return MathLib.abs(this._minimum + this._maximum) > MathLib445                 .abs(that._minimum + that._maximum);446     }447 448     //////////////////////449 // General Contract //450 //////////////////////451 452     /**453      * Indicates if this quantity is strictly equals to the object specified454      * (same amount and same system unit).455      *456      *

Note: Unlike {@link #approxEquals}, this method does not take into457      * account possible errors (e.g. numeric errors).

458      *459      * @param obj the object to compare with.460      * @return true if this quantity and the specified object461      * represent the exact same quantity; false otherwise.462      */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     /**474      * Returns a well distributed hash code value for this quantity.475      *476      * @return this quantity hash code value.477      * @see #equals478      */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     /**488      * Indicates if this quantity is approximately equals to the specified489      * quantity (regardless of the quantity unit). This method takes into490      * account possible errors (e.g. numeric errors) to make this determination.491      *492      * @param that the quantity to compare with.493      * @return this ≊ that.494      */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     /**503      * Compares this quantity with the specified quantity for order. 504      * Returns a negative integer, zero, or a positive integer as this quantity505      * is less than, equal to, or greater than the specified quantity.506      * This method does not require both units to be stated using the same507      * units.508      *509      * @param that the quantity to be compared.510      * @return a negative integer, zero, or a positive integer as this quantity511      * is less than, equal to, or greater than that quantity.512      * @throws ConversionException if the current model does not allows for513      * these quantities to be compared.514      * @see org.jscience.physics.units.Unit#isCompatible515      */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         // Special cases (e.g. NaN), do not return 0 for consistency with equal.528 long rawBits = Double.doubleToLongBits(diff);529         return (rawBits < 0) ? -1 : 1;530     }531 532     /**533      * Returns the textual representation of this quantity.534      * By default the quantity amount stated in the quantity unit.535      *536      * @return the textual representation of this quantity.537      * @see QuantityFormat538      */539     public Text toText() {540         return QuantityFormat.current().format(this);541     }542 543     /**544      * Returns the estimated value stated in base units represented as a 545      * long.546      *547      * @return the numeric value after conversion to type long.548      */549     public final long longValue() {550         return MathLib.round(doubleValue());551     }552 553     /**554      * Returns the estimated value stated in base units represented as a 555      * double.556      *557      * @return the numeric value after conversion to type double.558      */559     public final double doubleValue() {560         return 0.5 * (_minimum + _maximum);561     }562 563     /**564      * Returns a new quantity instance stated in the specified unit.565      *566      * @param unit the unit identifying the quantity type.567      * @return the corresponding quantity.568      */569     private static Quantity newInstance(Unit unit) {570         Factory< ? extends Quantity> factory = Factory.UNIT_TO_FACTORY571                 .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     /**588      * Indicates if the base units of this quantity are identical to the 589      * base units to this quantity.590      *591      * @param unit the unit the unit to be compared with.592      * @return true if this quantity and quantity stated in593      * the specified unit need conversions; false594      * otherwise.595      */596     private boolean needConversionTo(Unit unit) {597         return (_unit != unit) && (_unit.getBaseUnits() != unit.getBaseUnits());598     }599 600     /**601      * This inner-class represents the factory producing quantity instances.602      * {@link Quantity} instances.603      */604     public static abstract class Factory extends605             RealtimeObject.Factory {606 607         /**608          * Holds the factory producing general purpose quantities.609          */610         private static final Factory GENERAL = new Factory() {611             protected Object create() {612                 return new Quantity();613             }614         };615 616         /**617          * Holds the quantity factories instances (indexed by system unit).618          */619         private static final FastMap> COLLECTION = new FastMap>(620                 256);621 622         /**623          * Holds the unit to quantity factory mapping (cache).624          */625         private static final FastMap> UNIT_TO_FACTORY = new FastMap>(626                 1024);627 628         /**629          * Default constructor.630          */631         protected Factory() {632         }633 634         /**635          * Creates a new factory and associates it to the specified unit.636          * 637          * @param unit the unit to which this factory is used for.638          * @see #useFor(Unit)639          */640         protected Factory(Unit unit) {641             useFor(unit);642         }643 644         /**645          * Maps the specified unit to this factory. Quantities having the 646          * specified unit will be automatically produced by this factory.647          *648          * @param unit the unit mapped to this factory.649          * @return this650          * @throws IllegalArgumentException if the unit is already 651          * associated to another factory.652          */653         public Factory useFor(Unit unit) {654             synchronized (COLLECTION) {655                 if (COLLECTION.containsKey(unit))656                     throw new IllegalArgumentException ("unit: " + unit657                             + " is already mapped");658                 COLLECTION.put(unit, this);659                 // Clears the factory cache (set values to null to keep 660 // access unsynchronized).661 for (FastMap.Entry> e = UNIT_TO_FACTORY662                         .headEntry(), end = UNIT_TO_FACTORY.tailEntry(); (e = e663                         .getNextEntry()) != end;) {664                     e.setValue(null);665                 }666             }667             return this;668         }669 670         /**671          * Returns the factory for the specified unit, this method searches 672          * for the factory directly mapped to the specified unit, then for the 673          * factory mapped to the base units of the specified unit. 674          * If none is found, a general purpose factory is returned.675          *676          * @param unit the unit for which the current factory is searched for. 677          * @return the factory producing quantities for the specified unit.678          */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             // Not in the cache.684 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) { // max >= 0 as well.708 _minimum = min * DECREMENT;709             _maximum = max + max * DOUBLE_RELATIVE_ERROR;710         } else if (max <= 0) { // min <= 0 as well.711 _minimum = min + min * DOUBLE_RELATIVE_ERROR;712             _maximum = max * DECREMENT;713         } else { // min < 0 < max714 _minimum = min + min * DOUBLE_RELATIVE_ERROR;715             _maximum = max + max * DOUBLE_RELATIVE_ERROR;716         }717         return this;718     }719 720     // Forces initialization of predefined quantities.721 static {722         org.jscience.JScience.initialize();723     }724     725     private static final long serialVersionUID = 1L;726 }` Popular Tags