ICU-22781 Add support for converting units with constant denominators (C++)
See #3347
diff --git a/icu4c/source/i18n/units_converter.cpp b/icu4c/source/i18n/units_converter.cpp
index 3ccb006..1ab60bd 100644
--- a/icu4c/source/i18n/units_converter.cpp
+++ b/icu4c/source/i18n/units_converter.cpp
@@ -49,6 +49,8 @@ void U_I18N_API Factor::divideBy(const Factor &rhs) {
offset = std::max(rhs.offset, offset);
}
+void U_I18N_API Factor::divideBy(const uint64_t constant) { factorDen *= constant; }
+
void U_I18N_API Factor::power(int32_t power) {
// multiply all the constant by the power.
for (int i = 0; i < CONSTANTS_COUNT; i++) {
@@ -239,6 +241,12 @@ Factor loadCompoundFactor(const MeasureUnitImpl &source, const ConversionRates &
result.multiplyBy(singleFactor);
}
+ // If the source has a constant denominator, then we need to divide the
+ // factor by the constant denominator.
+ if (source.constantDenominator != 0) {
+ result.divideBy(source.constantDenominator);
+ }
+
return result;
}
diff --git a/icu4c/source/i18n/units_converter.h b/icu4c/source/i18n/units_converter.h
index 01fa557..6f4b55f 100644
--- a/icu4c/source/i18n/units_converter.h
+++ b/icu4c/source/i18n/units_converter.h
@@ -82,6 +82,7 @@ struct U_I18N_API Factor {
void multiplyBy(const Factor &rhs);
void divideBy(const Factor &rhs);
+ void divideBy(const uint64_t constant);
// Apply the power to the factor.
void power(int32_t power);
diff --git a/icu4c/source/test/intltest/units_test.cpp b/icu4c/source/test/intltest/units_test.cpp
index 147d19c..0c342ea 100644
--- a/icu4c/source/test/intltest/units_test.cpp
+++ b/icu4c/source/test/intltest/units_test.cpp
@@ -361,6 +361,24 @@ void UnitsTest::testConverter() {
{"dot-per-inch", "pixel-per-inch", 1.0, 1.0},
{"dot", "pixel", 1.0, 1.0},
+ // Test with constants
+ {"meter-per-10", "foot", 1.0, 0.328084},
+ {"meter", "foot-per-10", 1.0, 32.8084},
+ {"meter", "foot-per-100", 1.0, 328.084},
+ {"portion", "portion-per-1000", 1.0, 1000},
+ {"portion", "portion-per-10000", 1.0, 10000},
+ {"portion", "portion-per-100000", 1.0, 100000},
+ {"portion", "portion-per-1000000", 1.0, 1000000},
+ {"portion-per-10", "portion", 1.0, 0.1},
+ {"portion-per-100", "portion", 1.0, 0.01},
+ {"portion-per-1000", "portion", 1.0, 0.001},
+ {"portion-per-10000", "portion", 1.0, 0.0001},
+ {"portion-per-100000", "portion", 1.0, 0.00001},
+ {"portion-per-1000000", "portion", 1.0, 0.000001},
+ {"mile-per-hour", "meter-per-second", 1.0, 0.44704},
+ {"mile-per-100-hour", "meter-per-100-second", 1.0, 0.44704},
+ {"mile-per-hour", "meter-per-100-second", 1.0, 44.704},
+ {"mile-per-100-hour", "meter-per-second", 1.0, 0.0044704},
};
for (const auto &testCase : testCases) {