android-calculatorpp/measure/src/main/java/javax/measure/DecimalMeasure.java

179 lines
6.7 KiB
Java

/*
* JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
* Copyright (C) 2007 - JScience (http://jscience.org/)
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software is
* freely granted, provided that this notice is preserved.
*/
package javax.measure;
import java.math.BigDecimal;
import java.math.MathContext;
import javax.measure.converter.AddConverter;
import javax.measure.converter.RationalConverter;
import javax.measure.converter.UnitConverter;
import javax.measure.quantity.Quantity;
import javax.measure.unit.Unit;
/**
* <p> This class represents a measure whose value is an arbitrary-precision
* decimal number.</p>
*
* <p> When converting, applications may supply the
* <code>java.math.Context</code>:[code]
* DecimalMeasure<Velocity> c = DecimalMeasure.valueOf("299792458 m/s");
* DecimalMeasure<Velocity> milesPerHour = c.to(MILES_PER_HOUR, MathContext.DECIMAL128);
* System.out.println(milesPerHour);
*
* > 670616629.3843951324266284896206156 mph
* [/code]
*
* @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
* @version 4.3, October 3, 2007
*/
public class DecimalMeasure<Q extends Quantity> extends Measure<BigDecimal, Q> {
/**
* Holds the BigDecimal value.
*/
private final BigDecimal _value;
/**
* Holds the unit.
*/
private final Unit<Q> _unit;
/**
* Creates a decimal measure for the specified number stated in the
* specified unit.
*/
public DecimalMeasure(BigDecimal value, Unit<Q> unit) {
_value = value;
_unit = unit;
}
/**
* Returns the decimal measure for the specified number stated in the
* specified unit.
*
* @param decimal the measurement value.
* @param unit the measurement unit.
*/
public static <Q extends Quantity> DecimalMeasure<Q> valueOf(
BigDecimal decimal, Unit<Q> unit) {
return new DecimalMeasure<Q>(decimal, unit);
}
/**
* Returns the decimal measure for the specified textual representation.
* This method first reads the <code>BigDecimal</code> value, then
* the unit if any (value and unit should be separated by white spaces).
*
* @param csq the decimal measure representation (including unit if any).
* @throws NumberFormatException if the specified character sequence is
* not a valid representation of decimal measure.
*/
@SuppressWarnings("unchecked")
public static <Q extends Quantity> DecimalMeasure<Q> valueOf(CharSequence csq) {
String str = csq.toString();
int numberLength = str.length();
int unitStartIndex = -1;
for (int i=0; i < str.length(); i++) {
if (Character.isWhitespace(str.charAt(i))) {
for (int j=i+1; j < str.length(); j++) {
if (!Character.isWhitespace(str.charAt(j))) {
unitStartIndex = j;
break;
}
}
numberLength = i;
break;
}
}
BigDecimal decimal = new BigDecimal(str.substring(0, numberLength));
Unit unit = Unit.ONE;
if (unitStartIndex > 0) {
unit = Unit.valueOf(str.substring(unitStartIndex));
}
return new DecimalMeasure<Q>(decimal, unit);
}
@Override
public Unit<Q> getUnit() {
return _unit;
}
@Override
public BigDecimal getValue() {
return _value;
}
/**
* Returns the decimal measure equivalent to this measure but stated in the
* specified unit. This method will raise an ArithmeticException if the
* resulting measure does not have a terminating decimal expansion.
*
* @param unit the new measurement unit.
* @return the measure stated in the specified unit.
* @throws ArithmeticException if the converted measure value does not have
* a terminating decimal expansion
* @see #to(Unit, MathContext)
*/
@Override
public DecimalMeasure<Q> to(Unit<Q> unit) {
return to(unit, null);
}
/**
* Returns the decimal measure equivalent to this measure but stated in the
* specified unit, the conversion is performed using the specified math
* context.
*
* @param unit the new measurement unit.
* @param mathContext the mathContext used to convert
* <code>BigDecimal</code> values or <code>null</code> if none.
* @return the measure stated in the specified unit.
* @throws ArithmeticException if the result is inexact but the
* rounding mode is <code>MathContext.UNNECESSARY</code> or
* <code>mathContext.precision == 0</tt> and the quotient has a
* non-terminating decimal expansion.
*/
public DecimalMeasure<Q> to(Unit<Q> unit, MathContext mathContext) {
if ((unit == _unit) || (unit.equals(_unit)))
return this;
UnitConverter cvtr = _unit.getConverterTo(unit);
if (cvtr instanceof RationalConverter) {
RationalConverter factor = (RationalConverter) cvtr;
BigDecimal dividend = BigDecimal.valueOf(factor.getDividend());
BigDecimal divisor = BigDecimal.valueOf(factor.getDivisor());
BigDecimal result = mathContext == null ?
_value.multiply(dividend).divide(divisor) :
_value.multiply(dividend, mathContext).divide(divisor, mathContext);
return new DecimalMeasure<Q>(result, unit);
} else if (cvtr.isLinear()) {
BigDecimal factor = BigDecimal.valueOf(cvtr.convert(1.0));
BigDecimal result = mathContext == null ?
_value.multiply(factor) : _value.multiply(factor, mathContext);
return new DecimalMeasure<Q>(result, unit);
} else if (cvtr instanceof AddConverter) {
BigDecimal offset = BigDecimal.valueOf(((AddConverter)cvtr).getOffset());
BigDecimal result = mathContext == null ?
_value.add(offset) : _value.add(offset, mathContext);
return new DecimalMeasure<Q>(result, unit);
} else { // Non-linear and not an offset, convert the double value.
BigDecimal result = BigDecimal.valueOf(cvtr.convert(_value.doubleValue()));
return new DecimalMeasure<Q>(result, unit);
}
}
public double doubleValue(Unit<Q> unit) {
if ((unit == _unit) || (unit.equals(_unit)))
return _value.doubleValue();
return _unit.getConverterTo(unit).convert(_value.doubleValue());
}
private static final long serialVersionUID = 1L;
}