From af0bf6ab124a77e9633d9bfd3d95f5c3facc44f3 Mon Sep 17 00:00:00 2001 From: Younies Mahmoud Date: Fri, 24 Jan 2025 23:56:43 +0000 Subject: [PATCH] ICU-22781 Add support for converting units with constant denominators (C++) See #3347 --- icu4c/source/i18n/units_converter.cpp | 8 ++++++++ icu4c/source/i18n/units_converter.h | 1 + icu4c/source/test/intltest/units_test.cpp | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/icu4c/source/i18n/units_converter.cpp b/icu4c/source/i18n/units_converter.cpp index 3ccb0065bfca..1ab60bd4c060 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 01fa557062fe..6f4b55f81d9b 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 147d19c55e6a..0c342ea43c53 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) {