0001: /*
0002: * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
0003: * Copyright (C) 2006 - JScience (http://jscience.org/)
0004: * All rights reserved.
0005: *
0006: * Permission to use, copy, modify, and distribute this software is
0007: * freely granted, provided that this notice is preserved.
0008: */
0009: package org.jscience.physics.amount;
0010:
0011: import java.io.Serializable;
0012:
0013: import javolution.context.ObjectFactory;
0014: import javolution.lang.Immutable;
0015: import javolution.lang.MathLib;
0016: import javolution.text.Text;
0017: import javolution.util.FastComparator;
0018: import javolution.util.FastMap;
0019: import javolution.xml.XMLFormat;
0020: import javolution.xml.stream.XMLStreamException;
0021:
0022: import org.jscience.mathematics.structure.Field;
0023:
0024: import javax.measure.converter.ConversionException;
0025: import javax.measure.converter.RationalConverter;
0026: import javax.measure.converter.UnitConverter;
0027: import javax.measure.quantity.Dimensionless;
0028: import javax.measure.quantity.Quantity;
0029: import javax.measure.unit.Unit;
0030: import javax.measure.Measurable;
0031: import javax.realtime.MemoryArea;
0032:
0033: /**
0034: * <p> This class represents a determinate or estimated amount for which
0035: * operations such as addition, subtraction, multiplication and division
0036: * can be performed (it implements the {@link Field} interface).</p>
0037: *
0038: * <p> The nature of an amount can be deduced from its parameterization
0039: * (compile time) or its {@link #getUnit() unit} (run time).
0040: * Its precision is given by its {@link #getAbsoluteError() error}.</p>
0041: *
0042: * <p> Amounts can be {@link #isExact() exact}, in which case they can be
0043: * expressed as an exact <code>long</code> integer in the amount unit.
0044: * The framework tries to keep amount exact as much as possible.
0045: * For example:[code]
0046: * Amount<Length> m = Amount.valueOf(33, FOOT).divide(11).times(2);
0047: * System.out.println(m);
0048: * System.out.println(m.isExact() ? "exact" : "inexact");
0049: * System.out.println(m.getExactValue());
0050: * > 6 ft
0051: * > exact
0052: * > 6[/code]
0053: * </p>
0054: *
0055: * <p> Errors (including numeric errors) are calculated using numeric intervals.
0056: * It is possible to resolve systems of linear equations involving
0057: * {@link org.jscience.mathematics.vector.Matrix matrices}, even if the
0058: * system is close to singularity; in which case the error associated with
0059: * some (or all) components of the solution may be large.</p>
0060: *
0061: * <p> By default, non-exact amounts are shown using the plus/minus
0062: * character ('±') (see {@link AmountFormat}). For example,
0063: * <code>"(2.0 ± 0.001) km/s"</code> represents a velocity of
0064: * 2 km/s with an absolute error of ± 1 m/s. Exact amount use an
0065: * integer notation (no decimal point, e.g. <code>"2000 m"</code>).</p>
0066: *
0067: * <p> Operations between different amounts may or may not be authorized
0068: * based upon the current {@link org.jscience.physics.model.PhysicalModel
0069: * PhysicalModel}. For example, adding <code>Amount<Length> and
0070: * <code>Amount<Duration> is not allowed by the
0071: * {@link org.jscience.physics.model.StandardModel StandardModel},
0072: * but is authorized with the {@link
0073: * org.jscience.physics.model.RelativisticModel RelativisticModel}.</p>
0074: *
0075: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
0076: * @version 4.0, June 4, 2007
0077: * @see <a href="http://en.wikipedia.org/wiki/Measuring">
0078: * Wikipedia: Measuring</a>
0079: */
0080: public final class Amount<Q extends Quantity> implements Measurable<Q>,
0081: Field<Amount<?>>, Serializable, Immutable {
0082:
0083: ////////////////////////////////////////////////////////////////////////////////
0084: // Note: In the future, Amount might be abstract (with more measure types) //
0085: // We don't provide public constructors, factory methods should be used.//
0086: ////////////////////////////////////////////////////////////////////////////////
0087:
0088: /**
0089: * Holds a dimensionless measure of zero (exact).
0090: */
0091: public static final Amount<Dimensionless> ZERO = new Amount<Dimensionless>();
0092: static {
0093: ZERO._unit = Unit.ONE;
0094: ZERO._isExact = true;
0095: ZERO._exactValue = 0L;
0096: ZERO._minimum = 0;
0097: ZERO._maximum = 0;
0098: }
0099:
0100: /**
0101: * Holds a dimensionless measure of one (exact).
0102: */
0103: public static final Amount<Dimensionless> ONE = new Amount<Dimensionless>();
0104: static {
0105: ONE._unit = Unit.ONE;
0106: ONE._isExact = true;
0107: ONE._exactValue = 1L;
0108: ONE._minimum = 1.0;
0109: ONE._maximum = 1.0;
0110: }
0111:
0112: /**
0113: * Holds the default XML representation for measures.
0114: * This representation consists of a <code>value</code>,
0115: * an <code>unit</code> and an optional <code>error</code> attribute
0116: * when the measure is not exact.
0117: * The unit attribute determinates the measurement type. For example:<pre>
0118: * <Amount value="12" unit="µA"/></pre>
0119: * represents an electric current measurement.
0120: */
0121: @SuppressWarnings("unchecked")
0122: protected static final XMLFormat<Amount> XML = new XMLFormat<Amount>(
0123: Amount.class) {
0124:
0125: @Override
0126: public Amount newInstance(Class<Amount> cls, InputElement xml)
0127: throws XMLStreamException {
0128: Unit unit = Unit.valueOf(xml.getAttribute("unit"));
0129: Amount<?> m = Amount.newInstance(unit);
0130: if (xml.getAttribute("error") == null) // Exact.
0131: return m.setExact(xml.getAttribute("value", 0L));
0132: m._isExact = false;
0133: double estimatedValue = xml.getAttribute("value", 0.0);
0134: double error = xml.getAttribute("error", 0.0);
0135: m._minimum = estimatedValue - error;
0136: m._maximum = estimatedValue + error;
0137: return m;
0138: }
0139:
0140: @Override
0141: public void read(javolution.xml.XMLFormat.InputElement arg0,
0142: Amount arg1) throws XMLStreamException {
0143: // Nothing to do.
0144: }
0145:
0146: @Override
0147: public void write(Amount m, OutputElement xml)
0148: throws XMLStreamException {
0149: if (m._isExact) {
0150: xml.setAttribute("value", m._exactValue);
0151: } else {
0152: xml.setAttribute("value", m.getEstimatedValue());
0153: xml.setAttribute("error", m.getAbsoluteError());
0154: }
0155: xml.setAttribute("unit", m._unit.toString());
0156: }
0157: };
0158:
0159: /**
0160: * Returns the exact measure corresponding to the value stated in the
0161: * specified unit.
0162: *
0163: * @param value the exact value stated in the specified unit.
0164: * @param unit the unit in which the value is stated.
0165: * @return the corresponding measure object.
0166: */
0167: public static <Q extends Quantity> Amount<Q> valueOf(long value,
0168: Unit<Q> unit) {
0169: Amount<Q> m = Amount.newInstance(unit);
0170: return m.setExact(value);
0171: }
0172:
0173: /**
0174: * Returns the measure corresponding to an approximate value
0175: * (<code>double</code>) stated in the specified unit;
0176: * the precision of the measure is assumed to be the
0177: * <code>double</code> precision (64 bits IEEE 754 format).
0178: *
0179: * @param value the estimated value (± LSB) stated in the specified unit.
0180: * @param unit the unit in which the value is stated.
0181: * @return the corresponding measure object.
0182: */
0183: public static <Q extends Quantity> Amount<Q> valueOf(double value,
0184: Unit<Q> unit) {
0185: Amount<Q> m = Amount.newInstance(unit);
0186: m._isExact = false;
0187: double valInc = value * INCREMENT;
0188: double valDec = value * DECREMENT;
0189: m._minimum = (value < 0) ? valInc : valDec;
0190: m._maximum = (value < 0) ? valDec : valInc;
0191: return m;
0192: }
0193:
0194: /**
0195: * Returns the measure corresponding to the specified approximate value
0196: * and measurement error, both stated in the specified unit.
0197: *
0198: * @param value the estimated amount (± error) stated in the specified unit.
0199: * @param error the measurement error (absolute).
0200: * @param unit the unit in which the amount and the error are stated.
0201: * @return the corresponding measure object.
0202: * @throws IllegalArgumentException if <code>error < 0.0</code>
0203: */
0204: public static <Q extends Quantity> Amount<Q> valueOf(double value,
0205: double error, Unit<Q> unit) {
0206: if (error < 0)
0207: throw new IllegalArgumentException("error: " + error
0208: + " is negative");
0209: Amount<Q> m = Amount.newInstance(unit);
0210: double min = value - error;
0211: double max = value + error;
0212: m._isExact = false;
0213: m._minimum = (min < 0) ? min * INCREMENT : min * DECREMENT;
0214: m._maximum = (max < 0) ? max * DECREMENT : max * INCREMENT;
0215: return m;
0216: }
0217:
0218: /**
0219: * Returns the measure corresponding to the specified interval stated
0220: * in the specified unit.
0221: *
0222: * @param minimum the lower bound for the measure value.
0223: * @param maximum the upper bound for the measure value.
0224: * @param unit the unit for both the minimum and maximum values.
0225: * @return the corresponding measure object.
0226: * @throws IllegalArgumentException if <code>minimum > maximum</code>
0227: */
0228: public static <Q extends Quantity> Amount<Q> rangeOf(
0229: double minimum, double maximum, Unit<Q> unit) {
0230: if (minimum > maximum)
0231: throw new IllegalArgumentException("minimum: " + minimum
0232: + " greater than maximum: " + maximum);
0233: Amount<Q> m = Amount.newInstance(unit);
0234: m._isExact = false;
0235: m._minimum = (minimum < 0) ? minimum * INCREMENT : minimum
0236: * DECREMENT;
0237: m._maximum = (maximum < 0) ? maximum * DECREMENT : maximum
0238: * INCREMENT;
0239: return m;
0240: }
0241:
0242: /**
0243: * Returns the measure represented by the specified character sequence.
0244: *
0245: * @param csq the character sequence.
0246: * @return <code>AmountFormat.getInstance().parse(csq)</code>
0247: */
0248: public static Amount<?> valueOf(CharSequence csq) {
0249: return AmountFormat.getInstance().parse(csq);
0250: }
0251:
0252: /**
0253: * Indicates if this measure is exact.
0254: */
0255: private boolean _isExact;
0256:
0257: /**
0258: * Holds the exact value (when exact) stated in this measure unit.
0259: */
0260: private long _exactValue;
0261:
0262: /**
0263: * Holds the minimum value stated in this measure unit.
0264: * For inexact measures: _minimum < _maximum
0265: */
0266: private double _minimum;
0267:
0268: /**
0269: * Holds the maximum value stated in this measure unit.
0270: * For inexact measures: _maximum > _minimum
0271: */
0272: private double _maximum;
0273:
0274: /**
0275: * Holds this measure unit.
0276: */
0277: private Unit<Q> _unit;
0278:
0279: /**
0280: * Indicates if this measure amount is exact. An exact amount is
0281: * guarantee exact only when stated in this measure unit
0282: * (e.g. <code>this.longValue()</code>); stating the amount
0283: * in any other unit may introduce conversion errors.
0284: *
0285: * @return <code>true</code> if this measure is exact;
0286: * <code>false</code> otherwise.
0287: */
0288: public boolean isExact() {
0289: return _isExact;
0290: }
0291:
0292: /**
0293: * Returns the unit in which the {@link #getEstimatedValue()
0294: * estimated value} and {@link #getAbsoluteError() absolute error}
0295: * are stated.
0296: *
0297: * @return the measure unit.
0298: */
0299: public Unit<Q> getUnit() {
0300: return _unit;
0301: }
0302:
0303: /**
0304: * Returns the exact value for this measure stated in this measure
0305: * {@link #getUnit unit}.
0306: *
0307: * @return the exact measure value (<code>long</code>) stated
0308: * in this measure's {@link #getUnit unit}
0309: * @throws AmountException if this measure is not {@link #isExact()}
0310: */
0311: public long getExactValue() throws AmountException {
0312: if (!_isExact)
0313: throw new AmountException(
0314: "Inexact measures don't have exact values");
0315: return _exactValue;
0316: }
0317:
0318: /**
0319: * Returns the estimated value for this measure stated in this measure
0320: * {@link #getUnit unit}.
0321: *
0322: * @return the median value of the measure interval.
0323: */
0324: public double getEstimatedValue() {
0325: return (_isExact) ? _exactValue : (_minimum + _maximum) * 0.5;
0326: }
0327:
0328: /**
0329: * Returns the lower bound interval value for this measure stated in
0330: * this measure unit.
0331: *
0332: * @return the minimum value.
0333: */
0334: public double getMinimumValue() {
0335: return _minimum;
0336: }
0337:
0338: /**
0339: * Returns the upper bound interval value for this measure stated in
0340: * this measure unit.
0341: *
0342: * @return the maximum value.
0343: */
0344: public double getMaximumValue() {
0345: return _maximum;
0346: }
0347:
0348: /**
0349: * Returns the value by which the{@link #getEstimatedValue() estimated
0350: * value} may differ from the true value (all stated in base units).
0351: *
0352: * @return the absolute error stated in base units.
0353: */
0354: public double getAbsoluteError() {
0355: return MathLib.abs(_maximum - _minimum) * 0.5;
0356: }
0357:
0358: /**
0359: * Returns the percentage by which the estimated amount may differ
0360: * from the true amount.
0361: *
0362: * @return the relative error.
0363: */
0364: public double getRelativeError() {
0365: return _isExact ? 0 : (_maximum - _minimum)
0366: / (_minimum + _maximum);
0367: }
0368:
0369: /**
0370: * Returns the measure equivalent to this measure but stated in the
0371: * specified unit. The returned measure may not be exact even if this
0372: * measure is exact due to conversion errors.
0373: *
0374: * @param unit the unit of the measure to be returned.
0375: * @return a measure equivalent to this measure but stated in the
0376: * specified unit.
0377: * @throws ConversionException if the current model does not allows for
0378: * conversion to the specified unit.
0379: */
0380: @SuppressWarnings("unchecked")
0381: public <R extends Quantity> Amount<R> to(Unit<R> unit) {
0382: if ((_unit == unit) || this ._unit.equals(unit))
0383: return (Amount<R>) this ;
0384: UnitConverter cvtr = Amount.converterOf(_unit, unit);
0385: if (cvtr == UnitConverter.IDENTITY) { // No conversion necessary.
0386: Amount result = Amount.copyOf(this );
0387: result._unit = unit;
0388: return result;
0389: }
0390: if (cvtr instanceof RationalConverter) { // Exact conversion.
0391: RationalConverter rc = (RationalConverter) cvtr;
0392: Amount result = this .times(rc.getDividend()).divide(
0393: rc.getDivisor());
0394: result._unit = unit;
0395: return result;
0396: }
0397: Amount<R> result = Amount.newInstance(unit);
0398: double min = cvtr.convert(_minimum);
0399: double max = cvtr.convert(_maximum);
0400: result._isExact = false;
0401: result._minimum = (min < 0) ? min * INCREMENT : min * DECREMENT;
0402: result._maximum = (max < 0) ? max * DECREMENT : max * INCREMENT;
0403: return result;
0404: }
0405:
0406: /**
0407: * Returns the opposite of this measure.
0408: *
0409: * @return <code>-this</code>.
0410: */
0411: public Amount<Q> opposite() {
0412: Amount<Q> m = Amount.newInstance(_unit);
0413: if ((_isExact) && (_exactValue != Long.MAX_VALUE))
0414: return m.setExact(-_exactValue);
0415: m._isExact = false;
0416: m._minimum = -_maximum;
0417: m._maximum = -_minimum;
0418: return m;
0419: }
0420:
0421: /**
0422: * Returns the sum of this measure with the one specified.
0423: *
0424: * @param that the measure to be added.
0425: * @return <code>this + that</code>.
0426: * @throws ConversionException if the current model does not allows for
0427: * these quantities to be added.
0428: */
0429: @SuppressWarnings("unchecked")
0430: public Amount<Q> plus(Amount that) throws ConversionException {
0431: final Amount thatToUnit = that.to(_unit);
0432: Amount<Q> m = Amount.newInstance(_unit);
0433: if (this ._isExact && thatToUnit._isExact) {
0434: long sumLong = this ._exactValue + thatToUnit._exactValue;
0435: double sumDouble = ((double) this ._exactValue)
0436: + ((double) thatToUnit._exactValue);
0437: if (sumLong == sumDouble)
0438: return m.setExact(sumLong);
0439: }
0440: double min = this ._minimum + thatToUnit._minimum;
0441: double max = this ._maximum + thatToUnit._maximum;
0442: m._isExact = false;
0443: m._minimum = (min < 0) ? min * INCREMENT : min * DECREMENT;
0444: m._maximum = (max < 0) ? max * DECREMENT : max * INCREMENT;
0445: return m;
0446: }
0447:
0448: /**
0449: * Returns the difference of this measure with the one specified.
0450: *
0451: * @param that the measure to be subtracted.
0452: * @return <code>this - that</code>.
0453: * @throws ConversionException if the current model does not allows for
0454: * these quantities to be subtracted.
0455: */
0456: @SuppressWarnings("unchecked")
0457: public Amount<Q> minus(Amount that) throws ConversionException {
0458: final Amount thatToUnit = that.to(_unit);
0459: Amount<Q> m = Amount.newInstance(_unit);
0460: if (this ._isExact && thatToUnit._isExact) {
0461: long diffLong = this ._exactValue - thatToUnit._exactValue;
0462: double diffDouble = ((double) this ._exactValue)
0463: - ((double) thatToUnit._exactValue);
0464: if (diffLong == diffDouble)
0465: return m.setExact(diffLong);
0466: }
0467: double min = this ._minimum - thatToUnit._maximum;
0468: double max = this ._maximum - thatToUnit._minimum;
0469: m._isExact = false;
0470: m._minimum = (min < 0) ? min * INCREMENT : min * DECREMENT;
0471: m._maximum = (max < 0) ? max * DECREMENT : max * INCREMENT;
0472: return m;
0473: }
0474:
0475: /**
0476: * Returns this measure scaled by the specified exact factor
0477: * (dimensionless).
0478: *
0479: * @param factor the scaling factor.
0480: * @return <code>this · factor</code>.
0481: */
0482: public Amount<Q> times(long factor) {
0483: Amount<Q> m = Amount.newInstance(_unit);
0484: if (this ._isExact) {
0485: long productLong = _exactValue * factor;
0486: double productDouble = ((double) _exactValue) * factor;
0487: if (productLong == productDouble)
0488: return m.setExact(productLong);
0489: }
0490: m._isExact = false;
0491: m._minimum = (factor > 0) ? _minimum * factor : _maximum
0492: * factor;
0493: m._maximum = (factor > 0) ? _maximum * factor : _minimum
0494: * factor;
0495: return m;
0496: }
0497:
0498: /**
0499: * Returns this measure scaled by the specified approximate factor
0500: * (dimensionless).
0501: *
0502: * @param factor the scaling factor.
0503: * @return <code>this · factor</code>.
0504: */
0505: public Amount<Q> times(double factor) {
0506: Amount<Q> m = Amount.newInstance(_unit);
0507: double min = (factor > 0) ? _minimum * factor : _maximum
0508: * factor;
0509: double max = (factor > 0) ? _maximum * factor : _minimum
0510: * factor;
0511: m._isExact = false;
0512: m._minimum = (min < 0) ? min * INCREMENT : min * DECREMENT;
0513: m._maximum = (max < 0) ? max * DECREMENT : max * INCREMENT;
0514: return m;
0515: }
0516:
0517: /**
0518: * Returns the product of this measure with the one specified.
0519: *
0520: * @param that the measure multiplier.
0521: * @return <code>this · that</code>.
0522: */
0523: @SuppressWarnings("unchecked")
0524: public Amount<? extends Quantity> times(Amount that) {
0525: Unit<?> unit = Amount.productOf(this ._unit, that._unit);
0526: if (that._isExact) {
0527: Amount m = this .times(that._exactValue);
0528: m._unit = unit;
0529: return m;
0530: }
0531: Amount<Q> m = Amount.newInstance(unit);
0532: double min, max;
0533: if (_minimum >= 0) {
0534: if (that._minimum >= 0) {
0535: min = _minimum * that._minimum;
0536: max = _maximum * that._maximum;
0537: } else if (that._maximum < 0) {
0538: min = _maximum * that._minimum;
0539: max = _minimum * that._maximum;
0540: } else {
0541: min = _maximum * that._minimum;
0542: max = _maximum * that._maximum;
0543: }
0544: } else if (_maximum < 0) {
0545: if (that._minimum >= 0) {
0546: min = _minimum * that._maximum;
0547: max = _maximum * that._minimum;
0548: } else if (that._maximum < 0) {
0549: min = _maximum * that._maximum;
0550: max = _minimum * that._minimum;
0551: } else {
0552: min = _minimum * that._maximum;
0553: max = _minimum * that._minimum;
0554: }
0555: } else {
0556: if (that._minimum >= 0) {
0557: min = _minimum * that._maximum;
0558: max = _maximum * that._maximum;
0559: } else if (that._maximum < 0) {
0560: min = _maximum * that._minimum;
0561: max = _minimum * that._minimum;
0562: } else { // Both around zero.
0563: min = MathLib.min(_minimum * that._maximum, _maximum
0564: * that._minimum);
0565: max = MathLib.max(_minimum * that._minimum, _maximum
0566: * that._maximum);
0567: }
0568: }
0569: m._isExact = false;
0570: m._minimum = (min < 0) ? min * INCREMENT : min * DECREMENT;
0571: m._maximum = (max < 0) ? max * DECREMENT : max * INCREMENT;
0572: return m;
0573: }
0574:
0575: /**
0576: * Returns the multiplicative inverse of this measure.
0577: * If this measure is possibly zero, then the result is unbounded
0578: * (]-infinity, +infinity[).
0579: *
0580: * @return <code>1 / this</code>.
0581: */
0582: public Amount<? extends Quantity> inverse() {
0583: Amount<? extends Quantity> m = newInstance(Amount
0584: .inverseOf(_unit));
0585: if ((_isExact) && (_exactValue == 1L)) { // Only one exact inverse: one
0586: m.setExact(1L);
0587: return m;
0588: }
0589: m._isExact = false;
0590: if ((_minimum <= 0) && (_maximum >= 0)) { // Encompass zero.
0591: m._minimum = Double.NEGATIVE_INFINITY;
0592: m._maximum = Double.POSITIVE_INFINITY;
0593: return m;
0594: }
0595: double min = 1.0 / _maximum;
0596: double max = 1.0 / _minimum;
0597: m._minimum = (min < 0) ? min * INCREMENT : min * DECREMENT;
0598: m._maximum = (max < 0) ? max * DECREMENT : max * INCREMENT;
0599: return m;
0600: }
0601:
0602: /**
0603: * Returns this measure divided by the specified exact divisor
0604: * (dimensionless).
0605: *
0606: * @param divisor the exact divisor.
0607: * @return <code>this / divisor</code>.
0608: * @throws ArithmeticException if this measure is exact and the
0609: * specified divisor is zero.
0610: */
0611: public Amount<Q> divide(long divisor) {
0612: Amount<Q> m = Amount.newInstance(_unit);
0613: if (this ._isExact) {
0614: long quotientLong = _exactValue / divisor;
0615: double quotientDouble = ((double) _exactValue) / divisor;
0616: if (quotientLong == quotientDouble)
0617: return m.setExact(quotientLong);
0618: }
0619: double min = (divisor > 0) ? _minimum / divisor : _maximum
0620: / divisor;
0621: double max = (divisor > 0) ? _maximum / divisor : _minimum
0622: / divisor;
0623: m._isExact = false;
0624: m._minimum = (min < 0) ? min * INCREMENT : min * DECREMENT;
0625: m._maximum = (max < 0) ? max * DECREMENT : max * INCREMENT;
0626: return m;
0627: }
0628:
0629: /**
0630: * Returns this measure divided by the specified approximate divisor
0631: * (dimensionless).
0632: *
0633: * @param divisor the approximated divisor.
0634: * @return <code>this / divisor</code>.
0635: */
0636: public Amount<Q> divide(double divisor) {
0637: Amount<Q> m = Amount.newInstance(_unit);
0638: double min = (divisor > 0) ? _minimum / divisor : _maximum
0639: / divisor;
0640: double max = (divisor > 0) ? _maximum / divisor : _minimum
0641: / divisor;
0642: m._isExact = false;
0643: m._minimum = (min < 0) ? min * INCREMENT : min * DECREMENT;
0644: m._maximum = (max < 0) ? max * DECREMENT : max * INCREMENT;
0645: return m;
0646: }
0647:
0648: /**
0649: * Returns this measure divided by the one specified.
0650: *
0651: * @param that the measure divisor.
0652: * @return <code>this / that</code>.
0653: */
0654: @SuppressWarnings("unchecked")
0655: public Amount<? extends Quantity> divide(Amount that) {
0656: if (that._isExact) {
0657: Amount m = this .divide(that._exactValue);
0658: m._unit = Amount.productOf(this ._unit, Amount
0659: .inverseOf(that._unit));
0660: return m;
0661: }
0662: return this .times(that.inverse());
0663: }
0664:
0665: /**
0666: * Returns the absolute value of this measure.
0667: *
0668: * @return <code>|this|</code>.
0669: */
0670: public Amount<Q> abs() {
0671: return (_isExact) ? ((_exactValue < 0) ? this .opposite() : this )
0672: : (_minimum >= -_maximum) ? this : this .opposite();
0673: }
0674:
0675: /**
0676: * Returns the square root of this measure.
0677: *
0678: * @return <code>sqrt(this)</code>
0679: *
0680: */
0681: public Amount<? extends Quantity> sqrt() {
0682: Amount<Q> m = Amount.newInstance(_unit.root(2));
0683: if (this ._isExact) {
0684: double sqrtDouble = MathLib.sqrt(_exactValue);
0685: long sqrtLong = (long) sqrtDouble;
0686: if (sqrtLong * sqrtLong == _exactValue)
0687: return m.setExact(sqrtLong);
0688: }
0689: double min = MathLib.sqrt(_minimum);
0690: double max = MathLib.sqrt(_maximum);
0691: m._isExact = false;
0692: m._minimum = (min < 0) ? min * INCREMENT : min * DECREMENT;
0693: m._maximum = (max < 0) ? max * DECREMENT : max * INCREMENT;
0694: return m;
0695: }
0696:
0697: /**
0698: * Returns the given root of this measure.
0699: *
0700: * @param n the root's order (n != 0).
0701: * @return the result of taking the given root of this quantity.
0702: * @throws ArithmeticException if <code>n == 0</code>.
0703: */
0704: public Amount<? extends Quantity> root(int n) {
0705: if (n == 0)
0706: throw new ArithmeticException("Root's order of zero");
0707: if (n < 0)
0708: return this .root(-n).inverse();
0709: if (n == 2)
0710: return this .sqrt();
0711: Amount<Q> m = Amount.newInstance(_unit.root(n));
0712: if (this ._isExact) {
0713: double rootDouble = MathLib.pow(_exactValue, 1.0 / n);
0714: long rootLong = (long) rootDouble;
0715: long this Long = rootLong;
0716: for (int i = 1; i < n; i++) {
0717: this Long *= rootLong;
0718: }
0719: if (this Long == _exactValue)
0720: return m.setExact(rootLong);
0721: }
0722: double min = MathLib.pow(_minimum, 1.0 / n);
0723: double max = MathLib.pow(_maximum, 1.0 / n);
0724: m._isExact = false;
0725: m._minimum = (min < 0) ? min * INCREMENT : min * DECREMENT;
0726: m._maximum = (max < 0) ? max * DECREMENT : max * INCREMENT;
0727: return m;
0728: }
0729:
0730: /**
0731: * Returns this measure raised at the specified exponent.
0732: *
0733: * @param exp the exponent.
0734: * @return <code>this<sup>exp</sup></code>
0735: */
0736: public Amount<? extends Quantity> pow(int exp) {
0737: if (exp < 0)
0738: return this .pow(-exp).inverse();
0739: if (exp == 0)
0740: return ONE;
0741: Amount<?> pow2 = this ;
0742: Amount<?> result = null;
0743: while (exp >= 1) { // Iteration.
0744: if ((exp & 1) == 1) {
0745: result = (result == null) ? pow2 : result.times(pow2);
0746: }
0747: pow2 = pow2.times(pow2);
0748: exp >>>= 1;
0749: }
0750: return result;
0751: }
0752:
0753: /**
0754: * Compares this measure with the specified measurable object.
0755: *
0756: * @param that the measure to compare with.
0757: * @return a negative integer, zero, or a positive integer as this measure
0758: * is less than, equal to, or greater than that measurable.
0759: * @throws ConversionException if the current model does not allows for
0760: * these measure to be compared.
0761: */
0762: @SuppressWarnings("unchecked")
0763: public int compareTo(Measurable<Q> that) {
0764: double thatValue = that.doubleValue(_unit);
0765: return Double.compare(this .getEstimatedValue(), thatValue);
0766: }
0767:
0768: /**
0769: * Compares this measure against the specified object for strict
0770: * equality (same value interval and same units).
0771: *
0772: * @param that the object to compare with.
0773: * @return <code>true</code> if this measure is identical to that
0774: * measure; <code>false</code> otherwise.
0775: */
0776: public boolean equals(Object that) {
0777: if (this == that)
0778: return true;
0779: if (!(that instanceof Amount<?>))
0780: return false;
0781: Amount<?> m = (Amount<?>) that;
0782: if (!_unit.equals(m._unit))
0783: return false;
0784: if (_isExact != m._isExact)
0785: return false;
0786: if (_isExact && (this ._exactValue == m._exactValue))
0787: return true;
0788: if (_minimum != m._minimum)
0789: return false;
0790: if (_maximum != m._maximum)
0791: return false;
0792: return true;
0793: }
0794:
0795: /**
0796: * Returns the hash code for this measure.
0797: *
0798: * @return the hash code value.
0799: */
0800: public int hashCode() {
0801: int h = Float.floatToIntBits((float) _minimum);
0802: h += ~(h << 9);
0803: h ^= (h >>> 14);
0804: h += (h << 4);
0805: return h ^ (h >>> 10);
0806: }
0807:
0808: /**
0809: * Indicates if this measure approximates that measure.
0810: * Measures are considered approximately equals if their value intervals
0811: * overlaps. It should be noted that less accurate measurements are
0812: * more likely to be approximately equals. It is therefore recommended
0813: * to ensure that the measurement error is not too large before testing
0814: * for approximate equality.
0815: *
0816: * @return <code>this ≅ that</code>
0817: */
0818: @SuppressWarnings("unchecked")
0819: public boolean approximates(Amount that) {
0820: Amount thatToUnit = that.to(_unit);
0821: return (this ._maximum >= thatToUnit._minimum)
0822: && (thatToUnit._maximum >= this ._minimum);
0823: }
0824:
0825: /**
0826: * Indicates if this measure is ordered before that measure
0827: * (independently of the measure unit).
0828: *
0829: * @return <code>this.compareTo(that) < 0</code>.
0830: */
0831: public boolean isLessThan(Amount<Q> that) {
0832: return this .compareTo(that) < 0;
0833: }
0834:
0835: /**
0836: * Indicates if this measure is ordered after that measure
0837: * (independently of the measure unit).
0838: *
0839: * @return <code>this.compareTo(that) > 0</code>.
0840: */
0841: public boolean isGreaterThan(Amount<Q> that) {
0842: return this .compareTo(that) > 0;
0843: }
0844:
0845: /**
0846: * Compares this measure with that measure ignoring the sign.
0847: *
0848: * @return <code>|this| > |that|</code>
0849: */
0850: public boolean isLargerThan(Amount<Q> that) {
0851: return this .abs().isGreaterThan(that.abs());
0852: }
0853:
0854: /**
0855: * Returns the text representation of this measure.
0856: *
0857: * @return <code>AmountFormat.getInstance().format(this)</code>
0858: */
0859: public Text toText() {
0860: return AmountFormat.getInstance().format(this );
0861: }
0862:
0863: /**
0864: * Returns the text representation of this amount as a
0865: * <code>java.lang.String</code>.
0866: *
0867: * @return <code>toText().toString()</code>
0868: */
0869: public final String toString() {
0870: return toText().toString();
0871: }
0872:
0873: // Implements Quantity.
0874: public double doubleValue(Unit<Q> unit) {
0875: return ((_unit == unit) || _unit.equals(unit)) ? this
0876: .getEstimatedValue() : this .to(unit)
0877: .getEstimatedValue();
0878: }
0879:
0880: // Implements Quantity.
0881: public final long longValue(Unit<Q> unit) {
0882: if (!_unit.equals(unit))
0883: return this .to(unit).longValue(unit);
0884: if (_isExact)
0885: return _exactValue;
0886: double doubleValue = this .getEstimatedValue();
0887: if ((doubleValue >= Long.MIN_VALUE)
0888: && (doubleValue <= Long.MAX_VALUE))
0889: return Math.round(doubleValue);
0890: throw new ArithmeticException(doubleValue + " " + _unit
0891: + " cannot be represented as long");
0892: }
0893:
0894: ///////////////////
0895: // Lookup tables //
0896: ///////////////////
0897:
0898: static final FastMap<Unit<?>, FastMap<Unit<?>, Unit<?>>> MULT_LOOKUP = new FastMap<Unit<?>, FastMap<Unit<?>, Unit<?>>>(
0899: "UNITS_MULT_LOOKUP")
0900: .setKeyComparator(FastComparator.DIRECT);
0901:
0902: static final FastMap<Unit<?>, Unit<?>> INV_LOOKUP = new FastMap<Unit<?>, Unit<?>>(
0903: "UNITS_INV_LOOKUP").setKeyComparator(FastComparator.DIRECT);
0904:
0905: static final FastMap<Unit<?>, FastMap<Unit<?>, UnitConverter>> CVTR_LOOKUP = new FastMap<Unit<?>, FastMap<Unit<?>, UnitConverter>>(
0906: "UNITS_CVTR_LOOKUP")
0907: .setKeyComparator(FastComparator.DIRECT);
0908:
0909: private static Unit<?> productOf(Unit<?> left, Unit<?> right) {
0910: FastMap<Unit<?>, Unit<?>> leftTable = MULT_LOOKUP.get(left);
0911: if (leftTable == null)
0912: return calculateProductOf(left, right);
0913: Unit<?> result = leftTable.get(right);
0914: if (result == null)
0915: return calculateProductOf(left, right);
0916: return result;
0917: }
0918:
0919: private static synchronized Unit<?> calculateProductOf(
0920: final Unit<?> left, final Unit<?> right) {
0921: MemoryArea memoryArea = MemoryArea.getMemoryArea(MULT_LOOKUP);
0922: memoryArea.executeInArea(new Runnable() {
0923: public void run() {
0924: FastMap<Unit<?>, Unit<?>> leftTable = MULT_LOOKUP
0925: .get(left);
0926: if (leftTable == null) {
0927: leftTable = new FastMap<Unit<?>, Unit<?>>()
0928: .setKeyComparator(FastComparator.DIRECT);
0929: MULT_LOOKUP.put(left, leftTable);
0930: }
0931: Unit<?> result = leftTable.get(right);
0932: if (result == null) {
0933: result = left.times(right);
0934: leftTable.put(right, result);
0935: }
0936: }
0937: });
0938: return MULT_LOOKUP.get(left).get(right);
0939: }
0940:
0941: private static Unit<?> inverseOf(Unit<?> unit) {
0942: Unit<?> inverse = INV_LOOKUP.get(unit);
0943: if (inverse == null)
0944: return calculateInverseOf(unit);
0945: return inverse;
0946: }
0947:
0948: private static synchronized Unit<?> calculateInverseOf(
0949: final Unit<?> unit) {
0950: MemoryArea memoryArea = MemoryArea.getMemoryArea(INV_LOOKUP);
0951: memoryArea.executeInArea(new Runnable() {
0952: public void run() {
0953: Unit<?> inverse = INV_LOOKUP.get(unit);
0954: if (inverse == null) {
0955: inverse = unit.inverse();
0956: INV_LOOKUP.put(unit, inverse);
0957: }
0958: }
0959: });
0960: return INV_LOOKUP.get(unit);
0961: }
0962:
0963: private static UnitConverter converterOf(Unit<?> left, Unit<?> right) {
0964: FastMap<Unit<?>, UnitConverter> leftTable = CVTR_LOOKUP
0965: .get(left);
0966: if (leftTable == null)
0967: return calculateConverterOf(left, right);
0968: UnitConverter result = leftTable.get(right);
0969: if (result == null)
0970: return calculateConverterOf(left, right);
0971: return result;
0972: }
0973:
0974: private static synchronized UnitConverter calculateConverterOf(
0975: final Unit<?> left, final Unit<?> right) {
0976: MemoryArea memoryArea = MemoryArea.getMemoryArea(CVTR_LOOKUP);
0977: memoryArea.executeInArea(new Runnable() {
0978: public void run() {
0979: FastMap<Unit<?>, UnitConverter> leftTable = CVTR_LOOKUP
0980: .get(left);
0981: if (leftTable == null) {
0982: leftTable = new FastMap<Unit<?>, UnitConverter>()
0983: .setKeyComparator(FastComparator.DIRECT);
0984: synchronized (CVTR_LOOKUP) {
0985: CVTR_LOOKUP.put(left, leftTable);
0986: }
0987: }
0988: UnitConverter result = leftTable.get(right);
0989: if (result == null) {
0990: result = left.getConverterTo(right);
0991: synchronized (leftTable) {
0992: leftTable.put(right, result);
0993: }
0994: }
0995: }
0996: });
0997: return CVTR_LOOKUP.get(left).get(right);
0998: }
0999:
1000: public Amount<Q> copy() {
1001: Amount<Q> estimate = Amount.newInstance(_unit);
1002: estimate._isExact = _isExact;
1003: estimate._exactValue = _exactValue;
1004: estimate._minimum = _minimum;
1005: estimate._maximum = _maximum;
1006: return estimate;
1007: }
1008:
1009: //////////////////////
1010: // Factory Creation //
1011: //////////////////////
1012:
1013: @SuppressWarnings("unchecked")
1014: private static <Q extends Quantity> Amount<Q> newInstance(
1015: Unit<?> unit) {
1016: Amount<Q> measure = FACTORY.object();
1017: measure._unit = (Unit<Q>) unit;
1018: return measure;
1019: }
1020:
1021: @SuppressWarnings("unchecked")
1022: private static <Q extends Quantity> Amount<Q> copyOf(Amount original) {
1023: Amount<Q> measure = FACTORY.object();
1024: measure._exactValue = original._exactValue;
1025: measure._isExact = original._isExact;
1026: measure._maximum = original._maximum;
1027: measure._minimum = original._minimum;
1028: measure._unit = original._unit;
1029: return measure;
1030: }
1031:
1032: @SuppressWarnings("unchecked")
1033: private static final ObjectFactory<Amount> FACTORY = new ObjectFactory<Amount>() {
1034:
1035: @Override
1036: protected Amount create() {
1037: return new Amount();
1038: }
1039: };
1040:
1041: private Amount() {
1042: }
1043:
1044: private Amount<Q> setExact(long exactValue) {
1045: _isExact = true;
1046: _exactValue = exactValue;
1047: double doubleValue = exactValue;
1048: if (doubleValue == exactValue) {
1049: _minimum = doubleValue;
1050: _maximum = doubleValue;
1051: } else {
1052: double valInc = exactValue * INCREMENT;
1053: double valDec = exactValue * DECREMENT;
1054: _minimum = (_exactValue < 0) ? valInc : valDec;
1055: _maximum = (_exactValue < 0) ? valDec : valInc;
1056: }
1057: return this ;
1058: }
1059:
1060: static final double DOUBLE_RELATIVE_ERROR = MathLib.pow(2, -53);
1061:
1062: static final double DECREMENT = (1.0 - DOUBLE_RELATIVE_ERROR);
1063:
1064: static final double INCREMENT = (1.0 + DOUBLE_RELATIVE_ERROR);
1065:
1066: private static final long serialVersionUID = 1L;
1067:
1068: }
|