mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-07 22:44:49 +00:00
parent
8e69552228
commit
412ac386f4
9 changed files with 96 additions and 96 deletions
|
@ -32,7 +32,7 @@ ComplexUnitsConverter::ComplexUnitsConverter(const MeasureUnitImpl &targetUnit,
|
|||
// Just borrowing a pointer to the instance
|
||||
MeasureUnitImpl *biggestUnit = units_[0]->unitImpl.getAlias();
|
||||
for (int32_t i = 1; i < units_.length(); i++) {
|
||||
if (UnitConverter::compareTwoUnits(*units_[i]->unitImpl, *biggestUnit, ratesInfo, status) > 0 &&
|
||||
if (UnitsConverter::compareTwoUnits(*units_[i]->unitImpl, *biggestUnit, ratesInfo, status) > 0 &&
|
||||
U_SUCCESS(status)) {
|
||||
biggestUnit = units_[i]->unitImpl.getAlias();
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ void ComplexUnitsConverter::init(const MeasureUnitImpl &inputUnit,
|
|||
const auto *rightPointer = static_cast<const MeasureUnitImplWithIndex *const *>(right);
|
||||
|
||||
// Multiply by -1 to sort in descending order
|
||||
return (-1) * UnitConverter::compareTwoUnits(*((**leftPointer).unitImpl) /* left unit*/, //
|
||||
return (-1) * UnitsConverter::compareTwoUnits(*((**leftPointer).unitImpl) /* left unit*/, //
|
||||
*((**rightPointer).unitImpl) /* right unit */, //
|
||||
*static_cast<const ConversionRates *>(context), //
|
||||
status);
|
||||
|
@ -100,10 +100,10 @@ void ComplexUnitsConverter::init(const MeasureUnitImpl &inputUnit,
|
|||
// 3. then, the final result will be (6 feet and 6.74016 inches)
|
||||
for (int i = 0, n = units_.length(); i < n; i++) {
|
||||
if (i == 0) { // first element
|
||||
unitConverters_.emplaceBackAndCheckErrorCode(status, inputUnit, *(units_[i]->unitImpl),
|
||||
unitsConverters_.emplaceBackAndCheckErrorCode(status, inputUnit, *(units_[i]->unitImpl),
|
||||
ratesInfo, status);
|
||||
} else {
|
||||
unitConverters_.emplaceBackAndCheckErrorCode(status, *(units_[i - 1]->unitImpl),
|
||||
unitsConverters_.emplaceBackAndCheckErrorCode(status, *(units_[i - 1]->unitImpl),
|
||||
*(units_[i]->unitImpl), ratesInfo, status);
|
||||
}
|
||||
|
||||
|
@ -114,10 +114,10 @@ void ComplexUnitsConverter::init(const MeasureUnitImpl &inputUnit,
|
|||
}
|
||||
|
||||
UBool ComplexUnitsConverter::greaterThanOrEqual(double quantity, double limit) const {
|
||||
U_ASSERT(unitConverters_.length() > 0);
|
||||
U_ASSERT(unitsConverters_.length() > 0);
|
||||
|
||||
// First converter converts to the biggest quantity.
|
||||
double newQuantity = unitConverters_[0]->convert(quantity);
|
||||
double newQuantity = unitsConverters_[0]->convert(quantity);
|
||||
return newQuantity >= limit;
|
||||
}
|
||||
|
||||
|
@ -137,14 +137,14 @@ MaybeStackVector<Measure> ComplexUnitsConverter::convert(double quantity,
|
|||
// - the following N-2 converters convert to bigger units for which we want integers,
|
||||
// - the Nth converter (index N-1) converts to the smallest unit, for which
|
||||
// we keep a double.
|
||||
MaybeStackArray<int64_t, 5> intValues(unitConverters_.length() - 1, status);
|
||||
MaybeStackArray<int64_t, 5> intValues(unitsConverters_.length() - 1, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return result;
|
||||
}
|
||||
uprv_memset(intValues.getAlias(), 0, (unitConverters_.length() - 1) * sizeof(int64_t));
|
||||
uprv_memset(intValues.getAlias(), 0, (unitsConverters_.length() - 1) * sizeof(int64_t));
|
||||
|
||||
for (int i = 0, n = unitConverters_.length(); i < n; ++i) {
|
||||
quantity = (*unitConverters_[i]).convert(quantity);
|
||||
for (int i = 0, n = unitsConverters_.length(); i < n; ++i) {
|
||||
quantity = (*unitsConverters_[i]).convert(quantity);
|
||||
if (i < n - 1) {
|
||||
// If quantity is at the limits of double's precision from an
|
||||
// integer value, we take that integer value.
|
||||
|
@ -168,13 +168,13 @@ MaybeStackVector<Measure> ComplexUnitsConverter::convert(double quantity,
|
|||
|
||||
// Initialize empty result. We use a MaybeStackArray directly so we can
|
||||
// assign pointers - for this privilege we have to take care of cleanup.
|
||||
MaybeStackArray<Measure *, 4> tmpResult(unitConverters_.length(), status);
|
||||
MaybeStackArray<Measure *, 4> tmpResult(unitsConverters_.length(), status);
|
||||
if (U_FAILURE(status)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Package values into temporary Measure instances in tmpResult:
|
||||
for (int i = 0, n = unitConverters_.length(); i < n; ++i) {
|
||||
for (int i = 0, n = unitsConverters_.length(); i < n; ++i) {
|
||||
if (i < n - 1) {
|
||||
Formattable formattableQuantity(intValues[i] * sign);
|
||||
// Measure takes ownership of the MeasureUnit*
|
||||
|
@ -190,7 +190,7 @@ MaybeStackVector<Measure> ComplexUnitsConverter::convert(double quantity,
|
|||
|
||||
|
||||
// Transfer values into result and return:
|
||||
for(int32_t i = 0, n = unitConverters_.length(); i < n; ++i) {
|
||||
for(int32_t i = 0, n = unitsConverters_.length(); i < n; ++i) {
|
||||
U_ASSERT(tmpResult[i] != nullptr);
|
||||
result.emplaceBackAndCheckErrorCode(status, *tmpResult[i]);
|
||||
delete tmpResult[i];
|
||||
|
@ -215,27 +215,27 @@ void ComplexUnitsConverter::applyRounder(MaybeStackArray<int64_t, 5> &intValues,
|
|||
}
|
||||
quantity = decimalQuantity.toDouble();
|
||||
|
||||
int32_t lastIndex = unitConverters_.length() - 1;
|
||||
int32_t lastIndex = unitsConverters_.length() - 1;
|
||||
if (lastIndex == 0) {
|
||||
// Only one element, no need to bubble up the carry
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if there's a carry, and bubble it back up the resulting intValues.
|
||||
int64_t carry = floor(unitConverters_[lastIndex]->convertInverse(quantity) * (1 + DBL_EPSILON));
|
||||
int64_t carry = floor(unitsConverters_[lastIndex]->convertInverse(quantity) * (1 + DBL_EPSILON));
|
||||
if (carry <= 0) {
|
||||
return;
|
||||
}
|
||||
quantity -= unitConverters_[lastIndex]->convert(carry);
|
||||
quantity -= unitsConverters_[lastIndex]->convert(carry);
|
||||
intValues[lastIndex - 1] += carry;
|
||||
|
||||
// We don't use the first converter: that one is for the input unit
|
||||
for (int32_t j = lastIndex - 1; j > 0; j--) {
|
||||
carry = floor(unitConverters_[j]->convertInverse(intValues[j]) * (1 + DBL_EPSILON));
|
||||
carry = floor(unitsConverters_[j]->convertInverse(intValues[j]) * (1 + DBL_EPSILON));
|
||||
if (carry <= 0) {
|
||||
return;
|
||||
}
|
||||
intValues[j] -= round(unitConverters_[j]->convert(carry));
|
||||
intValues[j] -= round(unitsConverters_[j]->convert(carry));
|
||||
intValues[j - 1] += carry;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,9 +24,9 @@ U_NAMESPACE_BEGIN
|
|||
// Note: These need to be outside of the units namespace, or Clang will generate
|
||||
// a compile error.
|
||||
#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
|
||||
template class U_I18N_API MaybeStackArray<units::UnitConverter*, 8>;
|
||||
template class U_I18N_API MemoryPool<units::UnitConverter, 8>;
|
||||
template class U_I18N_API MaybeStackVector<units::UnitConverter, 8>;
|
||||
template class U_I18N_API MaybeStackArray<units::UnitsConverter*, 8>;
|
||||
template class U_I18N_API MemoryPool<units::UnitsConverter, 8>;
|
||||
template class U_I18N_API MaybeStackVector<units::UnitsConverter, 8>;
|
||||
template class U_I18N_API MaybeStackArray<MeasureUnitImpl*, 8>;
|
||||
template class U_I18N_API MemoryPool<MeasureUnitImpl, 8>;
|
||||
template class U_I18N_API MaybeStackVector<MeasureUnitImpl, 8>;
|
||||
|
@ -42,9 +42,9 @@ namespace units {
|
|||
* For example, from `meter` to `foot+inch`.
|
||||
*
|
||||
* DESIGN:
|
||||
* This class uses `UnitConverter` in order to perform the single converter (i.e. converters from a
|
||||
* This class uses `UnitsConverter` in order to perform the single converter (i.e. converters from a
|
||||
* single unit to another single unit). Therefore, `ComplexUnitsConverter` class contains multiple
|
||||
* instances of the `UnitConverter` to perform the conversion.
|
||||
* instances of the `UnitsConverter` to perform the conversion.
|
||||
*/
|
||||
class U_I18N_API ComplexUnitsConverter : public UMemory {
|
||||
public:
|
||||
|
@ -94,14 +94,14 @@ class U_I18N_API ComplexUnitsConverter : public UMemory {
|
|||
convert(double quantity, icu::number::impl::RoundingImpl *rounder, UErrorCode &status) const;
|
||||
|
||||
private:
|
||||
MaybeStackVector<UnitConverter> unitConverters_;
|
||||
MaybeStackVector<UnitsConverter> unitsConverters_;
|
||||
|
||||
// Individual units of mixed units, sorted big to small, with indices
|
||||
// indicating the requested output mixed unit order.
|
||||
MaybeStackVector<MeasureUnitImplWithIndex> units_;
|
||||
|
||||
// Sorts units_, which must be populated before calling this, and populates
|
||||
// unitConverters_.
|
||||
// unitsConverters_.
|
||||
void init(const MeasureUnitImpl &inputUnit, const ConversionRates &ratesInfo, UErrorCode &status);
|
||||
|
||||
// Applies the rounder to the quantity (last element) and bubble up any carried value to all the
|
||||
|
|
|
@ -272,7 +272,7 @@ UBool checkSimpleUnit(const MeasureUnitImpl &unit, UErrorCode &status) {
|
|||
/**
|
||||
* Extract conversion rate from `source` to `target`
|
||||
*/
|
||||
// In ICU4J, this function is partially inlined in the UnitConverter constructor.
|
||||
// In ICU4J, this function is partially inlined in the UnitsConverter constructor.
|
||||
void loadConversionRate(ConversionRate &conversionRate, const MeasureUnitImpl &source,
|
||||
const MeasureUnitImpl &target, Convertibility unitsState,
|
||||
const ConversionRates &ratesInfo, UErrorCode &status) {
|
||||
|
@ -489,7 +489,7 @@ Convertibility U_I18N_API extractConvertibility(const MeasureUnitImpl &source,
|
|||
return UNCONVERTIBLE;
|
||||
}
|
||||
|
||||
UnitConverter::UnitConverter(const MeasureUnitImpl &source, const MeasureUnitImpl &target,
|
||||
UnitsConverter::UnitsConverter(const MeasureUnitImpl &source, const MeasureUnitImpl &target,
|
||||
const ConversionRates &ratesInfo, UErrorCode &status)
|
||||
: conversionRate_(source.copy(status), target.copy(status)) {
|
||||
if (source.complexity == UMeasureUnitComplexity::UMEASURE_UNIT_MIXED ||
|
||||
|
@ -509,7 +509,7 @@ UnitConverter::UnitConverter(const MeasureUnitImpl &source, const MeasureUnitImp
|
|||
ratesInfo, status);
|
||||
}
|
||||
|
||||
int32_t UnitConverter::compareTwoUnits(const MeasureUnitImpl &firstUnit,
|
||||
int32_t UnitsConverter::compareTwoUnits(const MeasureUnitImpl &firstUnit,
|
||||
const MeasureUnitImpl &secondUnit,
|
||||
const ConversionRates &ratesInfo, UErrorCode &status) {
|
||||
if (U_FAILURE(status)) {
|
||||
|
@ -555,7 +555,7 @@ int32_t UnitConverter::compareTwoUnits(const MeasureUnitImpl &firstUnit,
|
|||
return 0;
|
||||
}
|
||||
|
||||
double UnitConverter::convert(double inputValue) const {
|
||||
double UnitsConverter::convert(double inputValue) const {
|
||||
double result =
|
||||
inputValue + conversionRate_.sourceOffset; // Reset the input to the target zero index.
|
||||
// Convert the quantity to from the source scale to the target scale.
|
||||
|
@ -576,7 +576,7 @@ double UnitConverter::convert(double inputValue) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
double UnitConverter::convertInverse(double inputValue) const {
|
||||
double UnitsConverter::convertInverse(double inputValue) const {
|
||||
double result = inputValue;
|
||||
if (conversionRate_.reciprocal) {
|
||||
if (result == 0) {
|
||||
|
|
|
@ -137,7 +137,7 @@ Convertibility U_I18N_API extractConvertibility(const MeasureUnitImpl &source,
|
|||
* Only works with SINGLE and COMPOUND units. If one of the units is a
|
||||
* MIXED unit, an error will occur. For more information, see UMeasureUnitComplexity.
|
||||
*/
|
||||
class U_I18N_API UnitConverter : public UMemory {
|
||||
class U_I18N_API UnitsConverter : public UMemory {
|
||||
public:
|
||||
/**
|
||||
* Constructor of `UnitConverter`.
|
||||
|
@ -150,7 +150,7 @@ class U_I18N_API UnitConverter : public UMemory {
|
|||
* @param ratesInfo Contains all the needed conversion rates.
|
||||
* @param status
|
||||
*/
|
||||
UnitConverter(const MeasureUnitImpl &source, const MeasureUnitImpl &target,
|
||||
UnitsConverter(const MeasureUnitImpl &source, const MeasureUnitImpl &target,
|
||||
const ConversionRates &ratesInfo, UErrorCode &status);
|
||||
|
||||
/**
|
||||
|
|
|
@ -47,7 +47,7 @@ class UnitsTest : public IntlTest {
|
|||
void testExtractConvertibility();
|
||||
void testConverterWithCLDRTests();
|
||||
void testComplexUnitsConverter();
|
||||
void testComplexUnitConverterSorting();
|
||||
void testComplexUnitsConverterSorting();
|
||||
void testUnitPreferencesWithCLDRTests();
|
||||
void testConverter();
|
||||
};
|
||||
|
@ -63,7 +63,7 @@ void UnitsTest::runIndexedTest(int32_t index, UBool exec, const char *&name, cha
|
|||
TESTCASE_AUTO(testExtractConvertibility);
|
||||
TESTCASE_AUTO(testConverterWithCLDRTests);
|
||||
TESTCASE_AUTO(testComplexUnitsConverter);
|
||||
TESTCASE_AUTO(testComplexUnitConverterSorting);
|
||||
TESTCASE_AUTO(testComplexUnitsConverterSorting);
|
||||
TESTCASE_AUTO(testUnitPreferencesWithCLDRTests);
|
||||
TESTCASE_AUTO(testConverter);
|
||||
TESTCASE_AUTO_END;
|
||||
|
@ -250,8 +250,8 @@ void UnitsTest::testConverter() {
|
|||
if (status.errIfFailureAndReset("conversionRates(status)")) {
|
||||
continue;
|
||||
}
|
||||
UnitConverter converter(source, target, conversionRates, status);
|
||||
if (status.errIfFailureAndReset("UnitConverter(<%s>, <%s>, ...)", testCase.source,
|
||||
UnitsConverter converter(source, target, conversionRates, status);
|
||||
if (status.errIfFailureAndReset("UnitsConverter(<%s>, <%s>, ...)", testCase.source,
|
||||
testCase.target)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -368,8 +368,8 @@ void unitsTestDataLineFn(void *context, char *fields[][2], int32_t fieldCount, U
|
|||
unitsTest->assertNotEquals(msg.data(), UNCONVERTIBLE, convertibility);
|
||||
|
||||
// Conversion:
|
||||
UnitConverter converter(sourceUnit, targetUnit, *ctx->conversionRates, status);
|
||||
if (status.errIfFailureAndReset("UnitConverter(<%s>, <%s>, ...)", sourceIdent.data(),
|
||||
UnitsConverter converter(sourceUnit, targetUnit, *ctx->conversionRates, status);
|
||||
if (status.errIfFailureAndReset("UnitsConverter(<%s>, <%s>, ...)", sourceIdent.data(),
|
||||
targetIdent.data())) {
|
||||
return;
|
||||
}
|
||||
|
@ -555,8 +555,8 @@ void UnitsTest::testComplexUnitsConverter() {
|
|||
// TODO(icu-units#63): test negative numbers!
|
||||
}
|
||||
|
||||
void UnitsTest::testComplexUnitConverterSorting() {
|
||||
IcuTestErrorCode status(*this, "UnitsTest::testComplexUnitConverterSorting");
|
||||
void UnitsTest::testComplexUnitsConverterSorting() {
|
||||
IcuTestErrorCode status(*this, "UnitsTest::testComplexUnitsConverterSorting");
|
||||
ConversionRates conversionRates(status);
|
||||
|
||||
status.assertSuccess();
|
||||
|
|
|
@ -17,14 +17,14 @@ import com.ibm.icu.util.Measure;
|
|||
/**
|
||||
* Converts from single or compound unit to single, compound or mixed units. For example, from `meter` to `foot+inch`.
|
||||
* <p>
|
||||
* DESIGN: This class uses `UnitConverter` in order to perform the single converter (i.e. converters from a single unit
|
||||
* to another single unit). Therefore, `ComplexUnitsConverter` class contains multiple instances of the `UnitConverter`
|
||||
* to perform the conversion.
|
||||
* DESIGN: This class uses <code>UnitsConverter</code> in order to perform the single converter (i.e. converters from
|
||||
* a single unit to another single unit). Therefore, <code>ComplexUnitsConverter</code> class contains multiple
|
||||
* instances of the <code>UnitsConverter</code> to perform the conversion.
|
||||
*/
|
||||
public class ComplexUnitsConverter {
|
||||
public static final BigDecimal EPSILON = BigDecimal.valueOf(Math.ulp(1.0));
|
||||
public static final BigDecimal EPSILON_MULTIPLIER = BigDecimal.valueOf(1).add(EPSILON);
|
||||
private ArrayList<UnitConverter> unitConverters_;
|
||||
private ArrayList<UnitsConverter> unitsConverters_;
|
||||
/**
|
||||
* Individual units of mixed units, sorted big to small, with indices
|
||||
* indicating the requested output mixed unit order.
|
||||
|
@ -80,7 +80,7 @@ public class ComplexUnitsConverter {
|
|||
|
||||
/**
|
||||
* Sorts units_, which must be populated before calling this, and populates
|
||||
* unitConverters_.
|
||||
* unitsConverters_.
|
||||
*/
|
||||
private void init(ConversionRates conversionRates) {
|
||||
// Sort the units in a descending order.
|
||||
|
@ -101,13 +101,13 @@ public class ComplexUnitsConverter {
|
|||
// 2. convert the residual of 6.56168 feet (0.56168) to inches, which will be (6.74016
|
||||
// inches)
|
||||
// 3. then, the final result will be (6 feet and 6.74016 inches)
|
||||
unitConverters_ = new ArrayList<>();
|
||||
unitsConverters_ = new ArrayList<>();
|
||||
for (int i = 0, n = units_.size(); i < n; i++) {
|
||||
if (i == 0) { // first element
|
||||
unitConverters_.add(new UnitConverter(this.inputUnit_, units_.get(i).unitImpl, conversionRates));
|
||||
unitsConverters_.add(new UnitsConverter(this.inputUnit_, units_.get(i).unitImpl, conversionRates));
|
||||
} else {
|
||||
unitConverters_
|
||||
.add(new UnitConverter(units_.get(i - 1).unitImpl, units_.get(i).unitImpl, conversionRates));
|
||||
unitsConverters_
|
||||
.add(new UnitsConverter(units_.get(i - 1).unitImpl, units_.get(i).unitImpl, conversionRates));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ public class ComplexUnitsConverter {
|
|||
assert !units_.isEmpty();
|
||||
|
||||
// NOTE: First converter converts to the biggest quantity.
|
||||
return unitConverters_.get(0).convert(quantity).multiply(EPSILON_MULTIPLIER).compareTo(limit) >= 0;
|
||||
return unitsConverters_.get(0).convert(quantity).multiply(EPSILON_MULTIPLIER).compareTo(limit) >= 0;
|
||||
}
|
||||
|
||||
public static class ComplexConverterResult {
|
||||
|
@ -157,9 +157,9 @@ public class ComplexUnitsConverter {
|
|||
// - N-1 converters convert to bigger units for which we want integers,
|
||||
// - the Nth converter (index N-1) converts to the smallest unit, which
|
||||
// isn't (necessarily) an integer.
|
||||
List<BigInteger> intValues = new ArrayList<>(unitConverters_.size() - 1);
|
||||
for (int i = 0, n = unitConverters_.size(); i < n; ++i) {
|
||||
quantity = (unitConverters_.get(i)).convert(quantity);
|
||||
List<BigInteger> intValues = new ArrayList<>(unitsConverters_.size() - 1);
|
||||
for (int i = 0, n = unitsConverters_.size(); i < n; ++i) {
|
||||
quantity = (unitsConverters_.get(i)).convert(quantity);
|
||||
|
||||
if (i < n - 1) {
|
||||
// The double type has 15 decimal digits of precision. For choosing
|
||||
|
@ -185,14 +185,14 @@ public class ComplexUnitsConverter {
|
|||
quantity = applyRounder(intValues, quantity, rounder);
|
||||
|
||||
// Initialize empty measures.
|
||||
List<Measure> measures = new ArrayList<>(unitConverters_.size());
|
||||
for (int i = 0; i < unitConverters_.size(); i++) {
|
||||
List<Measure> measures = new ArrayList<>(unitsConverters_.size());
|
||||
for (int i = 0; i < unitsConverters_.size(); i++) {
|
||||
measures.add(null);
|
||||
}
|
||||
|
||||
// Package values into Measure instances in measures:
|
||||
int indexOfQuantity = -1;
|
||||
for (int i = 0, n = unitConverters_.size(); i < n; ++i) {
|
||||
for (int i = 0, n = unitsConverters_.size(); i < n; ++i) {
|
||||
if (i < n - 1) {
|
||||
Measure measure = new Measure(intValues.get(i).multiply(sign), units_.get(i).unitImpl.build());
|
||||
measures.set(units_.get(i).index, measure);
|
||||
|
@ -228,25 +228,25 @@ public class ComplexUnitsConverter {
|
|||
}
|
||||
|
||||
// Check if there's a carry, and bubble it back up the resulting intValues.
|
||||
int lastIndex = unitConverters_.size() - 1;
|
||||
BigDecimal carry = unitConverters_.get(lastIndex).convertInverse(quantity).multiply(EPSILON_MULTIPLIER)
|
||||
int lastIndex = unitsConverters_.size() - 1;
|
||||
BigDecimal carry = unitsConverters_.get(lastIndex).convertInverse(quantity).multiply(EPSILON_MULTIPLIER)
|
||||
.setScale(0, RoundingMode.FLOOR);
|
||||
if (carry.compareTo(BigDecimal.ZERO) <= 0) { // carry is not greater than zero
|
||||
return quantity;
|
||||
}
|
||||
quantity = quantity.subtract(unitConverters_.get(lastIndex).convert(carry));
|
||||
quantity = quantity.subtract(unitsConverters_.get(lastIndex).convert(carry));
|
||||
intValues.set(lastIndex - 1, intValues.get(lastIndex - 1).add(carry.toBigInteger()));
|
||||
|
||||
// We don't use the first converter: that one is for the input unit
|
||||
for (int j = lastIndex - 1; j > 0; j--) {
|
||||
carry = unitConverters_.get(j)
|
||||
carry = unitsConverters_.get(j)
|
||||
.convertInverse(BigDecimal.valueOf(intValues.get(j).longValue()))
|
||||
.multiply(EPSILON_MULTIPLIER)
|
||||
.setScale(0, RoundingMode.FLOOR);
|
||||
if (carry.compareTo(BigDecimal.ZERO) <= 0) { // carry is not greater than zero
|
||||
break;
|
||||
}
|
||||
intValues.set(j, intValues.get(j).subtract(unitConverters_.get(j).convert(carry).toBigInteger()));
|
||||
intValues.set(j, intValues.get(j).subtract(unitsConverters_.get(j).convert(carry).toBigInteger()));
|
||||
intValues.set(j - 1, intValues.get(j - 1).add(carry.toBigInteger()));
|
||||
}
|
||||
|
||||
|
@ -255,6 +255,6 @@ public class ComplexUnitsConverter {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ComplexUnitsConverter [unitConverters_=" + unitConverters_ + ", units_=" + units_ + "]";
|
||||
return "ComplexUnitsConverter [unitsConverters_=" + unitsConverters_ + ", units_=" + units_ + "]";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,10 +38,10 @@ public class ConversionRates {
|
|||
* @return
|
||||
*/
|
||||
// In ICU4C, this is called loadCompoundFactor().
|
||||
private UnitConverter.Factor getFactorToBase(SingleUnitImpl singleUnit) {
|
||||
private UnitsConverter.Factor getFactorToBase(SingleUnitImpl singleUnit) {
|
||||
int power = singleUnit.getDimensionality();
|
||||
MeasureUnit.MeasurePrefix unitPrefix = singleUnit.getPrefix();
|
||||
UnitConverter.Factor result = UnitConverter.Factor.processFactor(mapToConversionRate.get(singleUnit.getSimpleUnitID()).getConversionRate());
|
||||
UnitsConverter.Factor result = UnitsConverter.Factor.processFactor(mapToConversionRate.get(singleUnit.getSimpleUnitID()).getConversionRate());
|
||||
|
||||
// Prefix before power, because:
|
||||
// - square-kilometer to square-meter: (1000)^2
|
||||
|
@ -49,8 +49,8 @@ public class ConversionRates {
|
|||
return result.applyPrefix(unitPrefix).power(power);
|
||||
}
|
||||
|
||||
public UnitConverter.Factor getFactorToBase(MeasureUnitImpl measureUnit) {
|
||||
UnitConverter.Factor result = new UnitConverter.Factor();
|
||||
public UnitsConverter.Factor getFactorToBase(MeasureUnitImpl measureUnit) {
|
||||
UnitsConverter.Factor result = new UnitsConverter.Factor();
|
||||
for (SingleUnitImpl singleUnit :
|
||||
measureUnit.getSingleUnits()) {
|
||||
result = result.multiply(getFactorToBase(singleUnit));
|
||||
|
@ -60,9 +60,9 @@ public class ConversionRates {
|
|||
}
|
||||
|
||||
// In ICU4C, this functionality is found in loadConversionRate().
|
||||
protected BigDecimal getOffset(MeasureUnitImpl source, MeasureUnitImpl target, UnitConverter.Factor
|
||||
sourceToBase, UnitConverter.Factor targetToBase, UnitConverter.Convertibility convertibility) {
|
||||
if (convertibility != UnitConverter.Convertibility.CONVERTIBLE) return BigDecimal.valueOf(0);
|
||||
protected BigDecimal getOffset(MeasureUnitImpl source, MeasureUnitImpl target, UnitsConverter.Factor
|
||||
sourceToBase, UnitsConverter.Factor targetToBase, UnitsConverter.Convertibility convertibility) {
|
||||
if (convertibility != UnitsConverter.Convertibility.CONVERTIBLE) return BigDecimal.valueOf(0);
|
||||
if (!(checkSimpleUnit(source) && checkSimpleUnit(target))) return BigDecimal.valueOf(0);
|
||||
|
||||
String sourceSimpleIdentifier = source.getSingleUnits().get(0).getSimpleUnitID();
|
||||
|
|
|
@ -11,12 +11,12 @@ import java.util.regex.Pattern;
|
|||
|
||||
import com.ibm.icu.util.MeasureUnit;
|
||||
|
||||
public class UnitConverter {
|
||||
public class UnitsConverter {
|
||||
private BigDecimal conversionRate;
|
||||
private BigDecimal offset;
|
||||
|
||||
/**
|
||||
* Constructor of `UnitConverter`.
|
||||
* Constructor of <code>UnitsConverter</code>.
|
||||
* NOTE:
|
||||
* - source and target must be under the same category
|
||||
* - e.g. meter to mile --> both of them are length units.
|
||||
|
@ -25,7 +25,7 @@ public class UnitConverter {
|
|||
* @param target represents the target unit.
|
||||
* @param conversionRates contains all the needed conversion rates.
|
||||
*/
|
||||
public UnitConverter(MeasureUnitImpl source, MeasureUnitImpl target, ConversionRates conversionRates) {
|
||||
public UnitsConverter(MeasureUnitImpl source, MeasureUnitImpl target, ConversionRates conversionRates) {
|
||||
Convertibility convertibility = extractConvertibility(source, target, conversionRates);
|
||||
assert (convertibility == Convertibility.CONVERTIBLE || convertibility == Convertibility.RECIPROCAL);
|
||||
|
||||
|
@ -347,6 +347,6 @@ public class UnitConverter {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UnitConverter [conversionRate=" + conversionRate + ", offset=" + offset + "]";
|
||||
return "UnitsConverter [conversionRate=" + conversionRate + ", offset=" + offset + "]";
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ import com.ibm.icu.impl.Pair;
|
|||
import com.ibm.icu.impl.units.ComplexUnitsConverter;
|
||||
import com.ibm.icu.impl.units.ConversionRates;
|
||||
import com.ibm.icu.impl.units.MeasureUnitImpl;
|
||||
import com.ibm.icu.impl.units.UnitConverter;
|
||||
import com.ibm.icu.impl.units.UnitsConverter;
|
||||
import com.ibm.icu.impl.units.UnitsRouter;
|
||||
import com.ibm.icu.util.Measure;
|
||||
import com.ibm.icu.util.MeasureUnit;
|
||||
|
@ -235,9 +235,9 @@ public class UnitsTest {
|
|||
class TestData {
|
||||
MeasureUnitImpl source;
|
||||
MeasureUnitImpl target;
|
||||
UnitConverter.Convertibility expected;
|
||||
UnitsConverter.Convertibility expected;
|
||||
|
||||
TestData(String source, String target, UnitConverter.Convertibility convertibility) {
|
||||
TestData(String source, String target, UnitsConverter.Convertibility convertibility) {
|
||||
this.source = MeasureUnitImpl.UnitsParser.parseForIdentifier(source);
|
||||
this.target = MeasureUnitImpl.UnitsParser.parseForIdentifier(target);
|
||||
this.expected = convertibility;
|
||||
|
@ -245,29 +245,29 @@ public class UnitsTest {
|
|||
}
|
||||
|
||||
TestData[] tests = {
|
||||
new TestData("meter", "foot", UnitConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("kilometer", "foot", UnitConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("hectare", "square-foot", UnitConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("kilometer-per-second", "second-per-meter", UnitConverter.Convertibility.RECIPROCAL),
|
||||
new TestData("square-meter", "square-foot", UnitConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("kilometer-per-second", "foot-per-second", UnitConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("square-hectare", "pow4-foot", UnitConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("square-kilometer-per-second", "second-per-square-meter", UnitConverter.Convertibility.RECIPROCAL),
|
||||
new TestData("cubic-kilometer-per-second-meter", "second-per-square-meter", UnitConverter.Convertibility.RECIPROCAL),
|
||||
new TestData("square-meter-per-square-hour", "hectare-per-square-second", UnitConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("hertz", "revolution-per-second", UnitConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("millimeter", "meter", UnitConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("yard", "meter", UnitConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("ounce-troy", "kilogram", UnitConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("percent", "portion", UnitConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("ofhg", "kilogram-per-square-meter-square-second", UnitConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("second-per-meter", "meter-per-second", UnitConverter.Convertibility.RECIPROCAL),
|
||||
new TestData("meter", "foot", UnitsConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("kilometer", "foot", UnitsConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("hectare", "square-foot", UnitsConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("kilometer-per-second", "second-per-meter", UnitsConverter.Convertibility.RECIPROCAL),
|
||||
new TestData("square-meter", "square-foot", UnitsConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("kilometer-per-second", "foot-per-second", UnitsConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("square-hectare", "pow4-foot", UnitsConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("square-kilometer-per-second", "second-per-square-meter", UnitsConverter.Convertibility.RECIPROCAL),
|
||||
new TestData("cubic-kilometer-per-second-meter", "second-per-square-meter", UnitsConverter.Convertibility.RECIPROCAL),
|
||||
new TestData("square-meter-per-square-hour", "hectare-per-square-second", UnitsConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("hertz", "revolution-per-second", UnitsConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("millimeter", "meter", UnitsConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("yard", "meter", UnitsConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("ounce-troy", "kilogram", UnitsConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("percent", "portion", UnitsConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("ofhg", "kilogram-per-square-meter-square-second", UnitsConverter.Convertibility.CONVERTIBLE),
|
||||
new TestData("second-per-meter", "meter-per-second", UnitsConverter.Convertibility.RECIPROCAL),
|
||||
};
|
||||
ConversionRates conversionRates = new ConversionRates();
|
||||
|
||||
for (TestData test :
|
||||
tests) {
|
||||
assertEquals(test.expected, UnitConverter.extractConvertibility(test.source, test.target, conversionRates));
|
||||
assertEquals(test.expected, UnitsConverter.extractConvertibility(test.source, test.target, conversionRates));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -340,7 +340,7 @@ public class UnitsTest {
|
|||
|
||||
ConversionRates conversionRates = new ConversionRates();
|
||||
for (TestData test : tests) {
|
||||
UnitConverter converter = new UnitConverter(test.source, test.target, conversionRates);
|
||||
UnitsConverter converter = new UnitsConverter(test.source, test.target, conversionRates);
|
||||
double maxDelta = 1e-6 * Math.abs(test.expected.doubleValue());
|
||||
if (test.expected.doubleValue() == 0) {
|
||||
maxDelta = 1e-12;
|
||||
|
@ -394,7 +394,7 @@ public class UnitsTest {
|
|||
|
||||
for (TestCase testCase :
|
||||
tests) {
|
||||
UnitConverter converter = new UnitConverter(testCase.source, testCase.target, conversionRates);
|
||||
UnitsConverter converter = new UnitsConverter(testCase.source, testCase.target, conversionRates);
|
||||
BigDecimal got = converter.convert(testCase.input);
|
||||
if (compareTwoBigDecimal(testCase.expected, got, BigDecimal.valueOf(0.000001))) {
|
||||
continue;
|
||||
|
|
Loading…
Add table
Reference in a new issue