ICU-20568 Support smart units / unit contexts / preferences

Explore Usage-related error codes, address icu-units/icu#36.
PR: https://github.com/icu-units/icu/pull/56
Commit: d5d7fdccfef887bb1af180bba3e2a0286dc32135

Implement Precision handling in UsagePrefsHandler::processQuantity
PR: https://github.com/icu-units/icu/pull/61
Commit: 16547f32986600a46e4adf20a6870c1708dd1c75

Support Mixed Units in NumberFormatter when using usage()
PR: https://github.com/icu-units/icu/pull/52
Commit: cc5a12202133855e15ffba889acffc10aad2d46b

For MixedUnits, use the correct ListFormatter styles.
PR: https://github.com/icu-units/icu/pull/66
Commit: 77bb747002d36626386f18e45c68c44b276cf575

Read the CLDR testData test files from the new location.
PR: https://github.com/icu-units/icu/pull/68
Commit: 6eb992e2b3c0bbe4870b554a5aa855b3636566d4

Fix double-precision maths in unit conversions
PR: https://github.com/icu-units/icu/pull/71
Commit: 78e88fbddef0f6817654d58c9c5dfeb6606324b9

Support .unit(MIXED_UNIT) without .usage(...).
PR: https://github.com/icu-units/icu/pull/72
Commit: 56ac7959375b8c9363ff022185165e52490c6c00

More commits:
- Reorder numbertest_api.cpp tests for consistent order.
- NumberFormatterApiTest: fold unitPipeline() into unitCompoundMeasure()
- Add some 'template class' instantiations for MSVC.
- Make trimField handle all whitespace, improve test messages
- Drop templated 'appendAll': it requires copy constructor
- Add protected MaybeStackArray::copyFrom()
- Add TODO(icu-units#67) and commented-out test case: use kUndefinedField for now
- Provide correct output order for units like "inch-and-foot"
- MSVC: export MaybeStackVector<MeasureUnit>
- Code review feedback: dependencies.txt and doc comments
- Consistent naming for code files: units_*
diff --git a/icu4c/source/common/cmemory.h b/icu4c/source/common/cmemory.h
index 81728b9..210bc76 100644
--- a/icu4c/source/common/cmemory.h
+++ b/icu4c/source/common/cmemory.h
@@ -387,6 +387,20 @@
      *         caller becomes responsible for deleting the array
      */
     inline T *orphanOrClone(int32_t length, int32_t &resultCapacity);
+
+protected:
+    // Resizes the array to the size of src, then copies the contents of src.
+    void copyFrom(const MaybeStackArray &src, UErrorCode &status) {
+        if (U_FAILURE(status)) {
+            return;
+        }
+        if (this->resize(src.capacity, 0) == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+        uprv_memcpy(this->ptr, src.ptr, (size_t)capacity * sizeof(T));
+    }
+
 private:
     T *ptr;
     int32_t capacity;
diff --git a/icu4c/source/i18n/formatted_string_builder.h b/icu4c/source/i18n/formatted_string_builder.h
index 4a886b9..92bcf07 100644
--- a/icu4c/source/i18n/formatted_string_builder.h
+++ b/icu4c/source/i18n/formatted_string_builder.h
@@ -55,7 +55,6 @@
     // Convention: bottom 4 bits for field, top 4 bits for field category.
     // Field category 0 implies the number category so that the number field
     // literals can be directly passed as a Field type.
-    // See the helper functions in "StringBuilderFieldUtils" below.
     // Exported as U_I18N_API so it can be used by other exports on Windows.
     struct U_I18N_API Field {
         uint8_t bits;
diff --git a/icu4c/source/i18n/i18n.vcxproj b/icu4c/source/i18n/i18n.vcxproj
index cf5ea8c..de36301 100644
--- a/icu4c/source/i18n/i18n.vcxproj
+++ b/icu4c/source/i18n/i18n.vcxproj
@@ -202,6 +202,7 @@
     <ClCompile Include="number_multiplier.cpp" />
     <ClCompile Include="number_currencysymbols.cpp" />
     <ClCompile Include="number_skeletons.cpp" />
+    <ClCompile Include="number_symbolswrapper.cpp" />
     <ClCompile Include="number_capi.cpp" />
     <ClCompile Include="string_segment.cpp" />
     <ClCompile Include="numparse_parsednumber.cpp" />
@@ -251,10 +252,10 @@
     <ClCompile Include="ufieldpositer.cpp" />
     <ClCompile Include="ulocdata.cpp" />
     <ClCompile Include="umsg.cpp" />
-    <ClCompile Include="unitconverter.cpp" />
-    <ClCompile Include="complexunitsconverter.cpp" />
-    <ClCompile Include="unitsrouter.cpp" />
-    <ClCompile Include="unitsdata.cpp" />
+    <ClCompile Include="units_complexconverter.cpp" />
+    <ClCompile Include="units_converter.cpp" />
+    <ClCompile Include="units_data.cpp" />
+    <ClCompile Include="units_router.cpp" />
     <ClCompile Include="unum.cpp" />
     <ClCompile Include="unumsys.cpp" />
     <ClCompile Include="upluralrules.cpp" />
@@ -470,13 +471,14 @@
     <ClInclude Include="number_scientific.h" />
     <ClInclude Include="formatted_string_builder.h" />
     <ClInclude Include="number_types.h" />
-    <ClCompile Include="number_usageprefs.h" />
+    <ClInclude Include="number_usageprefs.h" />
     <ClInclude Include="number_utypes.h" />
     <ClInclude Include="number_utils.h" />
     <ClInclude Include="number_mapper.h" />
     <ClInclude Include="number_multiplier.h" />
     <ClInclude Include="number_currencysymbols.h" />
     <ClInclude Include="number_skeletons.h" />
+    <ClInclude Include="number_symbolswrapper.h" />
     <ClInclude Include="string_segment.h" />
     <ClInclude Include="numparse_impl.h" />
     <ClInclude Include="numparse_symbols.h" />
@@ -490,10 +492,10 @@
     <ClInclude Include="numparse_utils.h" />
     <ClInclude Include="numrange_impl.h" />
     <ClInclude Include="formattedval_impl.h" />
-    <ClInclude Include="unitconverter.h" />
-    <ClInclude Include="complexunitsconverter.h" />
-    <ClInclude Include="unitsrouter.h" />
-    <ClInclude Include="unitsdata.h" />
+    <ClInclude Include="units_complexconverter.h" />
+    <ClInclude Include="units_converter.h" />
+    <ClInclude Include="units_data.h" />
+    <ClInclude Include="units_router.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="i18n.rc" />
diff --git a/icu4c/source/i18n/i18n.vcxproj.filters b/icu4c/source/i18n/i18n.vcxproj.filters
index 1dc9b5c..a012465 100644
--- a/icu4c/source/i18n/i18n.vcxproj.filters
+++ b/icu4c/source/i18n/i18n.vcxproj.filters
@@ -588,6 +588,9 @@
     <ClCompile Include="formatted_string_builder.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
+    <ClCompile Include="number_usageprefs.cpp">
+      <Filter>formatting</Filter>
+    </ClCompile>
     <ClCompile Include="number_utils.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
@@ -603,6 +606,9 @@
     <ClCompile Include="number_skeletons.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
+    <ClCompile Include="number_symbolswrapper.cpp">
+      <Filter>formatting</Filter>
+    </ClCompile>
     <ClCompile Include="number_capi.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
@@ -651,16 +657,16 @@
     <ClCompile Include="erarules.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
-    <ClCompile Include="unitconverter.cpp">
+    <ClCompile Include="units_complexconverter.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
-    <ClCompile Include="complexunitsconverter.cpp">
+    <ClCompile Include="units_converter.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
-    <ClCompile Include="unitsrouter.cpp">
+    <ClCompile Include="units_data.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
-    <ClCompile Include="unitsdata.cpp">
+    <ClCompile Include="units_router.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
   </ItemGroup>
@@ -914,6 +920,9 @@
     <ClInclude Include="number_utypes.h">
       <Filter>formatting</Filter>
     </ClInclude>
+    <ClInclude Include="number_usageprefs.h">
+      <Filter>formatting</Filter>
+    </ClInclude>
     <ClInclude Include="number_utils.h">
       <Filter>formatting</Filter>
     </ClInclude>
@@ -929,6 +938,9 @@
     <ClInclude Include="number_skeletons.h">
       <Filter>formatting</Filter>
     </ClInclude>
+    <ClInclude Include="number_symbolswrapper.h">
+      <Filter>formatting</Filter>
+    </ClInclude>
     <ClInclude Include="string_segment.h">
       <Filter>formatting</Filter>
     </ClInclude>
@@ -1007,16 +1019,16 @@
     <ClInclude Include="umsg_imp.h">
       <Filter>formatting</Filter>
     </ClInclude>
-    <ClInclude Include="unitconveter.h">
+    <ClInclude Include="units_complexconverter.h">
       <Filter>formatting</Filter>
     </ClInclude>
-    <ClInclude Include="complexunitsconverter.h">
+    <ClInclude Include="units_converter.h">
       <Filter>formatting</Filter>
     </ClInclude>
-    <ClInclude Include="unitsrouter.h">
+    <ClInclude Include="units_data.h">
       <Filter>formatting</Filter>
     </ClInclude>
-    <ClInclude Include="unitsdata.h">
+    <ClInclude Include="units_router.h">
       <Filter>formatting</Filter>
     </ClInclude>
     <ClInclude Include="vzone.h">
diff --git a/icu4c/source/i18n/i18n_uwp.vcxproj b/icu4c/source/i18n/i18n_uwp.vcxproj
index 2742efe..be7f4da 100644
--- a/icu4c/source/i18n/i18n_uwp.vcxproj
+++ b/icu4c/source/i18n/i18n_uwp.vcxproj
@@ -483,10 +483,10 @@
     <ClCompile Include="ufieldpositer.cpp" />
     <ClCompile Include="ulocdata.cpp" />
     <ClCompile Include="umsg.cpp" />
-    <ClCompile Include="unitconverter.cpp" />
-    <ClCompile Include="complexunitsconverter.cpp" />
-    <ClCompile Include="unitsrouter.cpp" />
-    <ClCompile Include="unitsdata.cpp" />
+    <ClCompile Include="units_complexconverter.cpp" />
+    <ClCompile Include="units_converter.cpp" />
+    <ClCompile Include="units_data.cpp" />
+    <ClCompile Include="units_router.cpp" />
     <ClCompile Include="unum.cpp" />
     <ClCompile Include="unumsys.cpp" />
     <ClCompile Include="upluralrules.cpp" />
@@ -723,10 +723,10 @@
     <ClInclude Include="numparse_utils.h" />
     <ClInclude Include="numrange_impl.h" />
     <ClInclude Include="formattedval_impl.h" />
-    <ClInclude Include="unitconverter.h" />
-    <ClInclude Include="complexunitsconverter.h" />
-    <ClInclude Include="unitsrouter.h" />
-    <ClInclude Include="unitsdata.h" />
+    <ClInclude Include="units_complexconverter.h" />
+    <ClInclude Include="units_converter.h" />
+    <ClInclude Include="units_data.h" />
+    <ClInclude Include="units_router.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="i18n.rc" />
diff --git a/icu4c/source/i18n/number_fluent.cpp b/icu4c/source/i18n/number_fluent.cpp
index 579f306..8569a36 100644
--- a/icu4c/source/i18n/number_fluent.cpp
+++ b/icu4c/source/i18n/number_fluent.cpp
@@ -520,123 +520,6 @@
     return LocalizedNumberFormatter(std::move(fMacros), locale);
 }
 
-SymbolsWrapper::SymbolsWrapper(const SymbolsWrapper& other) {
-    doCopyFrom(other);
-}
-
-SymbolsWrapper::SymbolsWrapper(SymbolsWrapper&& src) U_NOEXCEPT {
-    doMoveFrom(std::move(src));
-}
-
-SymbolsWrapper& SymbolsWrapper::operator=(const SymbolsWrapper& other) {
-    if (this == &other) {
-        return *this;
-    }
-    doCleanup();
-    doCopyFrom(other);
-    return *this;
-}
-
-SymbolsWrapper& SymbolsWrapper::operator=(SymbolsWrapper&& src) U_NOEXCEPT {
-    if (this == &src) {
-        return *this;
-    }
-    doCleanup();
-    doMoveFrom(std::move(src));
-    return *this;
-}
-
-SymbolsWrapper::~SymbolsWrapper() {
-    doCleanup();
-}
-
-void SymbolsWrapper::setTo(const DecimalFormatSymbols& dfs) {
-    doCleanup();
-    fType = SYMPTR_DFS;
-    fPtr.dfs = new DecimalFormatSymbols(dfs);
-}
-
-void SymbolsWrapper::setTo(const NumberingSystem* ns) {
-    doCleanup();
-    fType = SYMPTR_NS;
-    fPtr.ns = ns;
-}
-
-void SymbolsWrapper::doCopyFrom(const SymbolsWrapper& other) {
-    fType = other.fType;
-    switch (fType) {
-        case SYMPTR_NONE:
-            // No action necessary
-            break;
-        case SYMPTR_DFS:
-            // Memory allocation failures are exposed in copyErrorTo()
-            if (other.fPtr.dfs != nullptr) {
-                fPtr.dfs = new DecimalFormatSymbols(*other.fPtr.dfs);
-            } else {
-                fPtr.dfs = nullptr;
-            }
-            break;
-        case SYMPTR_NS:
-            // Memory allocation failures are exposed in copyErrorTo()
-            if (other.fPtr.ns != nullptr) {
-                fPtr.ns = new NumberingSystem(*other.fPtr.ns);
-            } else {
-                fPtr.ns = nullptr;
-            }
-            break;
-    }
-}
-
-void SymbolsWrapper::doMoveFrom(SymbolsWrapper&& src) {
-    fType = src.fType;
-    switch (fType) {
-        case SYMPTR_NONE:
-            // No action necessary
-            break;
-        case SYMPTR_DFS:
-            fPtr.dfs = src.fPtr.dfs;
-            src.fPtr.dfs = nullptr;
-            break;
-        case SYMPTR_NS:
-            fPtr.ns = src.fPtr.ns;
-            src.fPtr.ns = nullptr;
-            break;
-    }
-}
-
-void SymbolsWrapper::doCleanup() {
-    switch (fType) {
-        case SYMPTR_NONE:
-            // No action necessary
-            break;
-        case SYMPTR_DFS:
-            delete fPtr.dfs;
-            break;
-        case SYMPTR_NS:
-            delete fPtr.ns;
-            break;
-    }
-}
-
-bool SymbolsWrapper::isDecimalFormatSymbols() const {
-    return fType == SYMPTR_DFS;
-}
-
-bool SymbolsWrapper::isNumberingSystem() const {
-    return fType == SYMPTR_NS;
-}
-
-const DecimalFormatSymbols* SymbolsWrapper::getDecimalFormatSymbols() const {
-    U_ASSERT(fType == SYMPTR_DFS);
-    return fPtr.dfs;
-}
-
-const NumberingSystem* SymbolsWrapper::getNumberingSystem() const {
-    U_ASSERT(fType == SYMPTR_NS);
-    return fPtr.ns;
-}
-
-
 FormattedNumber LocalizedNumberFormatter::formatInt(int64_t value, UErrorCode& status) const {
     if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); }
     auto results = new UFormattedNumberData();
diff --git a/icu4c/source/i18n/number_formatimpl.cpp b/icu4c/source/i18n/number_formatimpl.cpp
index c047a1f..19bde1d 100644
--- a/icu4c/source/i18n/number_formatimpl.cpp
+++ b/icu4c/source/i18n/number_formatimpl.cpp
@@ -25,9 +25,6 @@
 using namespace icu::number::impl;
 
 
-MicroPropsGenerator::~MicroPropsGenerator() = default;
-
-
 NumberFormatterImpl::NumberFormatterImpl(const MacroProps& macros, UErrorCode& status)
     : NumberFormatterImpl(macros, true, status) {
 }
@@ -162,6 +159,8 @@
             || !(isPercent || isPermille)
             || isCompactNotation
         );
+    bool isMixedUnit = isCldrUnit && (uprv_strcmp(macros.unit.getType(), "") == 0) &&
+                       macros.unit.getComplexity(status) == UMEASURE_UNIT_MIXED;
 
     // Select the numbering system.
     LocalPointer<const NumberingSystem> nsLocal;
@@ -241,7 +240,8 @@
     // Unit Preferences and Conversions as our first step
     if (macros.usage.isSet()) {
         if (!isCldrUnit) {
-            // We only support "usage" when the input unit is a CLDR Unit.
+            // We only support "usage" when the input unit is specified, and is
+            // a CLDR Unit.
             status = U_ILLEGAL_ARGUMENT_ERROR;
             return nullptr;
         }
@@ -249,6 +249,10 @@
             new UsagePrefsHandler(macros.locale, macros.unit, macros.usage.fUsage, chain, status);
         fUsagePrefsHandler.adoptInsteadAndCheckErrorCode(usagePrefsHandler, status);
         chain = fUsagePrefsHandler.getAlias();
+    } else if (isMixedUnit) {
+        auto unitConversionHandler = new UnitConversionHandler(macros.unit, chain, status);
+        fUnitConversionHandler.adoptInsteadAndCheckErrorCode(unitConversionHandler, status);
+        chain = fUnitConversionHandler.getAlias();
     }
 
     // Multiplier
@@ -265,16 +269,14 @@
         precision = Precision::integer().withMinDigits(2);
     } else if (isCurrency) {
         precision = Precision::currency(UCURR_USAGE_STANDARD);
+    } else if (macros.usage.isSet()) {
+        // Bogus Precision - it will get set in the UsagePrefsHandler instead
+        precision = Precision();
     } else {
         precision = Precision::maxFraction(6);
     }
     UNumberFormatRoundingMode roundingMode;
-    if (macros.roundingMode != kDefaultMode) {
-        roundingMode = macros.roundingMode;
-    } else {
-        // Temporary until ICU 64
-        roundingMode = precision.fRoundingMode;
-    }
+    roundingMode = macros.roundingMode;
     fMicros.rounder = {precision, roundingMode, currency, status};
     if (U_FAILURE(status)) {
         return nullptr;
@@ -375,6 +377,14 @@
                     resolvePluralRules(macros.rules, macros.locale, status), chain, status),
                 status);
             chain = fLongNameMultiplexer.getAlias();
+        } else if (isMixedUnit) {
+            fMixedUnitLongNameHandler.adoptInsteadAndCheckErrorCode(new MixedUnitLongNameHandler(),
+                                                                    status);
+            MixedUnitLongNameHandler::forMeasureUnit(
+                macros.locale, macros.unit, unitWidth,
+                resolvePluralRules(macros.rules, macros.locale, status), chain,
+                fMixedUnitLongNameHandler.getAlias(), status);
+            chain = fMixedUnitLongNameHandler.getAlias();
         } else {
             fLongNameHandler.adoptInsteadAndCheckErrorCode(new LongNameHandler(), status);
             LongNameHandler::forMeasureUnit(macros.locale, macros.unit, macros.perUnit, unitWidth,
diff --git a/icu4c/source/i18n/number_formatimpl.h b/icu4c/source/i18n/number_formatimpl.h
index 062191a..5cd549e 100644
--- a/icu4c/source/i18n/number_formatimpl.h
+++ b/icu4c/source/i18n/number_formatimpl.h
@@ -94,6 +94,7 @@
     // Other fields possibly used by the number formatting pipeline:
     // TODO: Convert more of these LocalPointers to value objects to reduce the number of news?
     LocalPointer<const UsagePrefsHandler> fUsagePrefsHandler;
+    LocalPointer<const UnitConversionHandler> fUnitConversionHandler;
     LocalPointer<const DecimalFormatSymbols> fSymbols;
     LocalPointer<const PluralRules> fRules;
     LocalPointer<const ParsedPatternInfo> fPatternInfo;
@@ -101,6 +102,10 @@
     LocalPointer<MutablePatternModifier> fPatternModifier;
     LocalPointer<ImmutablePatternModifier> fImmutablePatternModifier;
     LocalPointer<LongNameHandler> fLongNameHandler;
+    // TODO: use a common base class that enables fLongNameHandler,
+    // fLongNameMultiplexer, and fMixedUnitLongNameHandler to be merged into one
+    // member?
+    LocalPointer<MixedUnitLongNameHandler> fMixedUnitLongNameHandler;
     LocalPointer<const LongNameMultiplexer> fLongNameMultiplexer;
     LocalPointer<const CompactHandler> fCompactHandler;
 
diff --git a/icu4c/source/i18n/number_integerwidth.cpp b/icu4c/source/i18n/number_integerwidth.cpp
index d62aef4..10b8534 100644
--- a/icu4c/source/i18n/number_integerwidth.cpp
+++ b/icu4c/source/i18n/number_integerwidth.cpp
@@ -40,6 +40,9 @@
 }
 
 void IntegerWidth::apply(impl::DecimalQuantity& quantity, UErrorCode& status) const {
+    if (U_FAILURE(status)) {
+        return;
+    }
     if (fHasError) {
         status = U_ILLEGAL_ARGUMENT_ERROR;
     } else if (fUnion.minMaxInt.fMaxInt == -1) {
diff --git a/icu4c/source/i18n/number_longnames.cpp b/icu4c/source/i18n/number_longnames.cpp
index 7ace7fd..691fb13 100644
--- a/icu4c/source/i18n/number_longnames.cpp
+++ b/icu4c/source/i18n/number_longnames.cpp
@@ -38,6 +38,7 @@
  * `per` forms.
  */
 constexpr int32_t PER_INDEX = StandardPlural::Form::COUNT + 1;
+// Number of keys in the array populated by PluralTableSink.
 constexpr int32_t ARRAY_LENGTH = StandardPlural::Form::COUNT + 2;
 
 static int32_t getIndex(const char* pluralKeyword, UErrorCode& status) {
@@ -52,6 +53,11 @@
     }
 }
 
+// Selects a string out of the `strings` array which corresponds to the
+// specified plural form, with fallback to the OTHER form.
+//
+// The `strings` array must have ARRAY_LENGTH items: one corresponding to each
+// of the plural forms, plus a display name ("dnam") and a "per" form.
 static UnicodeString getWithPlural(
         const UnicodeString* strings,
         StandardPlural::Form plural,
@@ -101,12 +107,18 @@
 
 // NOTE: outArray MUST have room for all StandardPlural values.  No bounds checking is performed.
 
-// Populates outArray with `locale`-specific values for `unit` through use of
-// PluralTableSink, reading from resources *unitsNarrow* and *unitsShort* (for
-// width UNUM_UNIT_WIDTH_NARROW), or just *unitsShort* (for width
-// UNUM_UNIT_WIDTH_SHORT). For other widths, it would read just "units".
-//
-// outArray must be of fixed length ARRAY_LENGTH.
+/**
+ * Populates outArray with `locale`-specific values for `unit` through use of
+ * PluralTableSink. Only the set of basic units are supported!
+ *
+ * Reading from resources *unitsNarrow* and *unitsShort* (for width
+ * UNUM_UNIT_WIDTH_NARROW), or just *unitsShort* (for width
+ * UNUM_UNIT_WIDTH_SHORT). For other widths, it reads just "units".
+ *
+ * @param unit must have a type and subtype (i.e. it must be a unit listed in
+ *     gTypes and gSubTypes in measunit.cpp).
+ * @param outArray must be of fixed length ARRAY_LENGTH.
+ */
 void getMeasureData(const Locale &locale, const MeasureUnit &unit, const UNumberUnitWidth &width,
                     UnicodeString *outArray, UErrorCode &status) {
     PluralTableSink sink(outArray);
@@ -204,24 +216,26 @@
 
 } // namespace
 
-// TODO(units,hugovdm): deal properly with "perUnit" parameter here:
 void LongNameHandler::forMeasureUnit(const Locale &loc, const MeasureUnit &unitRef,
                                      const MeasureUnit &perUnit, const UNumberUnitWidth &width,
                                      const PluralRules *rules, const MicroPropsGenerator *parent,
                                      LongNameHandler *fillIn, UErrorCode &status) {
-    if (fillIn == nullptr) {
-        status = U_INTERNAL_PROGRAM_ERROR;
-        return;
-    }
+    // Not valid for mixed units that aren't built-in units, and there should
+    // not be any built-in mixed units!
+    U_ASSERT(uprv_strlen(unitRef.getType()) > 0 || unitRef.getComplexity(status) != UMEASURE_UNIT_MIXED);
+    U_ASSERT(fillIn != nullptr);
     if (uprv_strlen(unitRef.getType()) == 0 || uprv_strlen(perUnit.getType()) == 0) {
-        // TODO(ICU-20941): Unsanctioned unit. Not yet fully supported. Set an error code.
+        // TODO(ICU-20941): Unsanctioned unit. Not yet fully supported. Set an
+        // error code. Once we support not-built-in units here, unitRef may be
+        // anything, but if not built-in, perUnit has to be "none".
         status = U_UNSUPPORTED_ERROR;
         return;
     }
 
     MeasureUnit unit = unitRef;
     if (uprv_strcmp(perUnit.getType(), "none") != 0) {
-        // Compound unit: first try to simplify (e.g., meters per second is its own unit).
+        // Compound unit: first try to simplify (e.g. "meter per second" is a
+        // built-in unit).
         bool isResolved = false;
         MeasureUnit resolved = MeasureUnit::resolveUnitPerUnit(unit, perUnit, &isResolved);
         if (isResolved) {
@@ -244,7 +258,6 @@
                                      status);
 }
 
-// TODO(units,hugovdm): deal properly with "perUnit" parameter here:
 void LongNameHandler::forCompoundUnit(const Locale &loc, const MeasureUnit &unit,
                                       const MeasureUnit &perUnit, const UNumberUnitWidth &width,
                                       const PluralRules *rules, const MicroPropsGenerator *parent,
@@ -390,6 +403,131 @@
     return &fModifiers[plural];
 }
 
+void MixedUnitLongNameHandler::forMeasureUnit(const Locale &loc, const MeasureUnit &mixedUnit,
+                                              const UNumberUnitWidth &width, const PluralRules *rules,
+                                              const MicroPropsGenerator *parent,
+                                              MixedUnitLongNameHandler *fillIn, UErrorCode &status) {
+    U_ASSERT(mixedUnit.getComplexity(status) == UMEASURE_UNIT_MIXED);
+    U_ASSERT(fillIn != nullptr);
+
+    LocalArray<MeasureUnit> individualUnits =
+        mixedUnit.splitToSingleUnits(fillIn->fMixedUnitCount, status);
+    fillIn->fMixedUnitData.adoptInstead(new UnicodeString[fillIn->fMixedUnitCount * ARRAY_LENGTH]);
+    for (int32_t i = 0; i < fillIn->fMixedUnitCount; i++) {
+        // Grab data for each of the components.
+        UnicodeString *unitData = &fillIn->fMixedUnitData[i * ARRAY_LENGTH];
+        getMeasureData(loc, individualUnits[i], width, unitData, status);
+    }
+
+    UListFormatterWidth listWidth = ULISTFMT_WIDTH_SHORT;
+    if (width == UNUM_UNIT_WIDTH_NARROW) {
+        listWidth = ULISTFMT_WIDTH_NARROW;
+    } else if (width == UNUM_UNIT_WIDTH_FULL_NAME) {
+        // This might be the same as SHORT in most languages:
+        listWidth = ULISTFMT_WIDTH_WIDE;
+    }
+    fillIn->fListFormatter.adoptInsteadAndCheckErrorCode(
+        ListFormatter::createInstance(loc, ULISTFMT_TYPE_UNITS, listWidth, status), status);
+    fillIn->rules = rules;
+    fillIn->parent = parent;
+
+    // We need a localised NumberFormatter for the integers of the bigger units
+    // (providing Arabic numerals, for example).
+    fillIn->fIntegerFormatter = NumberFormatter::withLocale(loc);
+}
+
+void MixedUnitLongNameHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micros,
+                                               UErrorCode &status) const {
+    U_ASSERT(fMixedUnitCount > 1);
+    if (parent != nullptr) {
+        parent->processQuantity(quantity, micros, status);
+    }
+    micros.modOuter = getMixedUnitModifier(quantity, micros, status);
+}
+
+const Modifier *MixedUnitLongNameHandler::getMixedUnitModifier(DecimalQuantity &quantity,
+                                                               MicroProps &micros,
+                                                               UErrorCode &status) const {
+    // TODO(icu-units#21): mixed units without usage() is not yet supported.
+    // That should be the only reason why this happens, so delete this whole if
+    // once fixed:
+    if (micros.mixedMeasuresCount == 0) {
+        status = U_UNSUPPORTED_ERROR;
+        return &micros.helpers.emptyWeakModifier;
+    }
+    U_ASSERT(micros.mixedMeasuresCount > 0);
+    // mixedMeasures does not contain the last value:
+    U_ASSERT(fMixedUnitCount == micros.mixedMeasuresCount + 1);
+    U_ASSERT(fListFormatter.isValid());
+
+    // Algorithm:
+    //
+    // For the mixed-units measurement of: "3 yard, 1 foot, 2.6 inch", we should
+    // find "3 yard" and "1 foot" in micros.mixedMeasures.
+    //
+    // Obtain long-names with plural forms corresponding to measure values:
+    //   * {0} yards, {0} foot, {0} inches
+    //
+    // Format the integer values appropriately and modify with the format
+    // strings:
+    //   - 3 yards, 1 foot
+    //
+    // Use ListFormatter to combine, with one placeholder:
+    //   - 3 yards, 1 foot and {0} inches
+    //
+    // Return a SimpleModifier for this pattern, letting the rest of the
+    // pipeline take care of the remaining inches.
+
+    LocalArray<UnicodeString> outputMeasuresList(new UnicodeString[fMixedUnitCount], status);
+    if (U_FAILURE(status)) {
+        return &micros.helpers.emptyWeakModifier;
+    }
+
+    for (int32_t i = 0; i < micros.mixedMeasuresCount; i++) {
+        DecimalQuantity fdec;
+        fdec.setToLong(micros.mixedMeasures[i]);
+        StandardPlural::Form pluralForm = utils::getStandardPlural(rules, fdec);
+
+        UnicodeString simpleFormat =
+            getWithPlural(&fMixedUnitData[i * ARRAY_LENGTH], pluralForm, status);
+        SimpleFormatter compiledFormatter(simpleFormat, 0, 1, status);
+
+        UnicodeString num;
+        auto appendable = UnicodeStringAppendable(num);
+        fIntegerFormatter.formatDecimalQuantity(fdec, status).appendTo(appendable, status);
+        compiledFormatter.format(num, outputMeasuresList[i], status);
+    }
+
+    UnicodeString *finalSimpleFormats = &fMixedUnitData[(fMixedUnitCount - 1) * ARRAY_LENGTH];
+    StandardPlural::Form finalPlural = utils::getPluralSafe(micros.rounder, rules, quantity, status);
+    UnicodeString finalSimpleFormat = getWithPlural(finalSimpleFormats, finalPlural, status);
+    SimpleFormatter finalFormatter(finalSimpleFormat, 0, 1, status);
+    finalFormatter.format(UnicodeString(u"{0}"), outputMeasuresList[fMixedUnitCount - 1], status);
+
+    // Combine list into a "premixed" pattern
+    UnicodeString premixedFormatPattern;
+    fListFormatter->format(outputMeasuresList.getAlias(), fMixedUnitCount, premixedFormatPattern,
+                           status);
+    SimpleFormatter premixedCompiled(premixedFormatPattern, 0, 1, status);
+    if (U_FAILURE(status)) {
+        return &micros.helpers.emptyWeakModifier;
+    }
+
+    // Return a SimpleModifier for the "premixed" pattern
+    micros.helpers.mixedUnitModifier =
+        SimpleModifier(premixedCompiled, kUndefinedField, false, {this, SIGNUM_POS_ZERO, finalPlural});
+    return &micros.helpers.mixedUnitModifier;
+}
+
+const Modifier *MixedUnitLongNameHandler::getModifier(Signum /*signum*/,
+                                                      StandardPlural::Form /*plural*/) const {
+    // TODO(units): investigate this method when investigating where
+    // LongNameHandler::getModifier() gets used. To be sure it remains
+    // unreachable:
+    UPRV_UNREACHABLE;
+    return nullptr;
+}
+
 LongNameMultiplexer *
 LongNameMultiplexer::forMeasureUnits(const Locale &loc, const MaybeStackVector<MeasureUnit> &units,
                                      const UNumberUnitWidth &width, const PluralRules *rules,
@@ -399,16 +537,23 @@
         return nullptr;
     }
     U_ASSERT(units.length() > 0);
+    if (result->fHandlers.resize(units.length()) == nullptr) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return nullptr;
+    }
     result->fMeasureUnits.adoptInstead(new MeasureUnit[units.length()]);
     for (int32_t i = 0, length = units.length(); i < length; i++) {
-        // Create empty new LongNameHandler:
-        LongNameHandler *lnh =
-            result->fLongNameHandlers.emplaceBackAndCheckErrorCode(status);
-        result->fMeasureUnits[i] = *units[i];
-        // Fill in LongNameHandler:
-        LongNameHandler::forMeasureUnit(loc, *units[i],
-                                        MeasureUnit(), // TODO(units): deal with COMPOUND and MIXED units
-                                        width, rules, NULL, lnh, status);
+        const MeasureUnit& unit = *units[i];
+        result->fMeasureUnits[i] = unit;
+        if (unit.getComplexity(status) == UMEASURE_UNIT_MIXED) {
+            MixedUnitLongNameHandler *mlnh = result->fMixedUnitHandlers.createAndCheckErrorCode(status);
+            MixedUnitLongNameHandler::forMeasureUnit(loc, unit, width, rules, NULL, mlnh, status);
+            result->fHandlers[i] = mlnh;
+        } else {
+            LongNameHandler *lnh = result->fLongNameHandlers.createAndCheckErrorCode(status);
+            LongNameHandler::forMeasureUnit(loc, unit, MeasureUnit(), width, rules, NULL, lnh, status);
+            result->fHandlers[i] = lnh;
+        }
         if (U_FAILURE(status)) {
             return nullptr;
         }
@@ -424,12 +569,15 @@
     fParent->processQuantity(quantity, micros, status);
 
     // Call the correct LongNameHandler based on outputUnit
-    for (int i = 0; i < fLongNameHandlers.length(); i++) {
+    for (int i = 0; i < fHandlers.getCapacity(); i++) {
         if (fMeasureUnits[i] == micros.outputUnit) {
-            fLongNameHandlers[i]->processQuantity(quantity, micros, status);
+            fHandlers[i]->processQuantity(quantity, micros, status);
             return;
         }
     }
+    if (U_FAILURE(status)) {
+        return;
+    }
     // We shouldn't receive any outputUnit for which we haven't already got a
     // LongNameHandler:
     status = U_INTERNAL_PROGRAM_ERROR;
diff --git a/icu4c/source/i18n/number_longnames.h b/icu4c/source/i18n/number_longnames.h
index db08c11..ace517c 100644
--- a/icu4c/source/i18n/number_longnames.h
+++ b/icu4c/source/i18n/number_longnames.h
@@ -8,6 +8,7 @@
 #define __NUMBER_LONGNAMES_H__
 
 #include "cmemory.h"
+#include "unicode/listformatter.h"
 #include "unicode/uversion.h"
 #include "number_utils.h"
 #include "number_modifiers.h"
@@ -34,17 +35,47 @@
     forCurrencyLongNames(const Locale &loc, const CurrencyUnit &currency, const PluralRules *rules,
                          const MicroPropsGenerator *parent, UErrorCode &status);
 
+    /**
+     * Construct a localized LongNameHandler for the specified MeasureUnit.
+     *
+     * Compound units can be constructed via `unit` and `perUnit`. Both of these
+     * must then be built-in units.
+     *
+     * Mixed units are not supported, use MixedUnitLongNameHandler::forMeasureUnit.
+     *
+     * This function uses a fillIn intead of returning a pointer, because we
+     * want to fill in instances in a MemoryPool (which cannot adopt pointers it
+     * didn't create itself).
+     *
+     * @param loc The desired locale.
+     * @param unit The measure unit to construct a LongNameHandler for. If
+     *     `perUnit` is also defined, `unit` must not be a mixed unit.
+     * @param perUnit If `unit` is a mixed unit, `perUnit` must be "none".
+     * @param width Specifies the desired unit rendering.
+     * @param rules Does not take ownership.
+     * @param parent Does not take ownership.
+     * @param fillIn Required.
+     */
     static void forMeasureUnit(const Locale &loc, const MeasureUnit &unit, const MeasureUnit &perUnit,
                                const UNumberUnitWidth &width, const PluralRules *rules,
                                const MicroPropsGenerator *parent, LongNameHandler *fillIn,
                                UErrorCode &status);
 
+    /**
+     * Selects the plural-appropriate Modifier from the set of fModifiers based
+     * on the plural form.
+     */
     void
     processQuantity(DecimalQuantity &quantity, MicroProps &micros, UErrorCode &status) const U_OVERRIDE;
 
+    // TODO(units): investigate whether we might run into Mixed Unit trouble
+    // with this. This override for ModifierStore::getModifier does not support
+    // mixed units: investigate under which circumstances it gets called (check
+    // both ImmutablePatternModifier and in NumberRangeFormatterImpl).
     const Modifier* getModifier(Signum signum, StandardPlural::Form plural) const U_OVERRIDE;
 
   private:
+    // A set of pre-computed modifiers, one for each plural form.
     SimpleModifier fModifiers[StandardPlural::Form::COUNT];
     // Not owned
     const PluralRules *rules;
@@ -58,34 +89,136 @@
     LongNameHandler() : rules(nullptr), parent(nullptr) {
     }
 
-    friend class MemoryPool<LongNameHandler>; // To enable emplaceBack();
+    // Enables MemoryPool<LongNameHandler>::emplaceBack(): requires access to
+    // the private constructors.
+    friend class MemoryPool<LongNameHandler>;
+
+    // Allow macrosToMicroGenerator to call the private default constructor.
     friend class NumberFormatterImpl;
 
+    // Fills in LongNameHandler fields for formatting compound units identified
+    // via `unit` and `perUnit`. Both `unit` and `perUnit` need to be built-in
+    // units (for which data exists).
     static void forCompoundUnit(const Locale &loc, const MeasureUnit &unit, const MeasureUnit &perUnit,
                                 const UNumberUnitWidth &width, const PluralRules *rules,
                                 const MicroPropsGenerator *parent, LongNameHandler *fillIn,
                                 UErrorCode &status);
 
+    // Sets fModifiers to use the patterns from `simpleFormats`.
     void simpleFormatsToModifiers(const UnicodeString *simpleFormats, Field field, UErrorCode &status);
+
+    // Sets fModifiers to a combination of `leadFormats` (one per plural form)
+    // and `trailFormat` appended to each.
+    //
+    // With a leadFormat of "{0}m" and a trailFormat of "{0}/s", it produces a
+    // pattern of "{0}m/s" by inserting the leadFormat pattern into trailFormat.
     void multiSimpleFormatsToModifiers(const UnicodeString *leadFormats, UnicodeString trailFormat,
                                        Field field, UErrorCode &status);
 };
 
-const int MAX_PREFS_COUNT = 10;
+// Similar to LongNameHandler, but only for MIXED units.
+class MixedUnitLongNameHandler : public MicroPropsGenerator, public ModifierStore, public UMemory {
+  public:
+    /**
+     * Construct a localized MixedUnitLongNameHandler for the specified
+     * MeasureUnit. It must be a MIXED unit.
+     *
+     * This function uses a fillIn intead of returning a pointer, because we
+     * want to fill in instances in a MemoryPool (which cannot adopt pointers it
+     * didn't create itself).
+     *
+     * @param loc The desired locale.
+     * @param mixedUnit The mixed measure unit to construct a
+     *     MixedUnitLongNameHandler for.
+     * @param width Specifies the desired unit rendering.
+     * @param rules Does not take ownership.
+     * @param parent Does not take ownership.
+     * @param fillIn Required.
+     */
+    static void forMeasureUnit(const Locale &loc, const MeasureUnit &mixedUnit,
+                               const UNumberUnitWidth &width, const PluralRules *rules,
+                               const MicroPropsGenerator *parent, MixedUnitLongNameHandler *fillIn,
+                               UErrorCode &status);
+
+    /**
+     * Produces a plural-appropriate Modifier for a mixed unit: `quantity` is
+     * taken as the final smallest unit, while the larger unit values must be
+     * provided via `micros.mixedMeasures`.
+     */
+    void processQuantity(DecimalQuantity &quantity, MicroProps &micros,
+                         UErrorCode &status) const U_OVERRIDE;
+
+    // Required for ModifierStore. And ModifierStore is required by
+    // SimpleModifier constructor's last parameter. We assert his will never get
+    // called though.
+    const Modifier *getModifier(Signum signum, StandardPlural::Form plural) const U_OVERRIDE;
+
+  private:
+    // Not owned
+    const PluralRules *rules;
+    // Not owned
+    const MicroPropsGenerator *parent;
+
+    // Total number of units in the MeasureUnit this LongNameHandler was
+    // configured for: for "foot-and-inch", this will be 2. (If not a mixed unit,
+    // this will be 1.)
+    int32_t fMixedUnitCount = 1;
+    // If this LongNameHandler is for a mixed unit, this stores unit data for
+    // each of the individual units. For each unit, it stores ARRAY_LENGTH
+    // strings, as returned by getMeasureData. (Each unit with index `i` has
+    // ARRAY_LENGTH strings starting at index `i*ARRAY_LENGTH` in this array.)
+    LocalArray<UnicodeString> fMixedUnitData;
+    // A localized NumberFormatter used to format the integer-valued bigger
+    // units of Mixed Unit measurements.
+    LocalizedNumberFormatter fIntegerFormatter;
+    // A localised list formatter for joining mixed units together.
+    LocalPointer<ListFormatter> fListFormatter;
+
+    MixedUnitLongNameHandler(const PluralRules *rules, const MicroPropsGenerator *parent)
+        : rules(rules), parent(parent) {
+    }
+
+    MixedUnitLongNameHandler() : rules(nullptr), parent(nullptr) {
+    }
+
+    // Allow macrosToMicroGenerator to call the private default constructor.
+    friend class NumberFormatterImpl;
+
+    // Enables MemoryPool<LongNameHandler>::emplaceBack(): requires access to
+    // the private constructors.
+    friend class MemoryPool<MixedUnitLongNameHandler>;
+
+    // Fills in LongNameHandler fields for formatting mixed units. Each unit in
+    // a mixed unit must be a built-in unit.
+    static void forMixedUnit(const Locale &loc, const MeasureUnit &unit, const UNumberUnitWidth &width,
+                             const PluralRules *rules, const MicroPropsGenerator *parent,
+                             MixedUnitLongNameHandler *fillIn, UErrorCode &status);
+
+    // For a mixed unit, returns a Modifier that takes only one parameter: the
+    // smallest and final unit of the set. The bigger units' values and labels
+    // get baked into this Modifier, together with the unit label of the final
+    // unit.
+    const Modifier *getMixedUnitModifier(DecimalQuantity &quantity, MicroProps &micros,
+                                         UErrorCode &status) const;
+};
 
 /**
  * A MicroPropsGenerator that multiplexes between different LongNameHandlers,
- * depending on the outputUnit (micros.helpers.outputUnit should be set earlier
- * in the chain).
+ * depending on the outputUnit.
+ *
+ * See processQuantity() for the input requirements.
  */
 class LongNameMultiplexer : public MicroPropsGenerator, public UMemory {
   public:
-    // FIXME: docstring?
+    // Produces a multiplexer for LongNameHandlers, one for each unit in
+    // `units`. An individual unit might be a mixed unit.
     static LongNameMultiplexer *forMeasureUnits(const Locale &loc,
                                                 const MaybeStackVector<MeasureUnit> &units,
                                                 const UNumberUnitWidth &width, const PluralRules *rules,
                                                 const MicroPropsGenerator *parent, UErrorCode &status);
 
+    // The output unit must be provided via `micros.outputUnit`, it must match
+    // one of the units provided to the factory function.
     void processQuantity(DecimalQuantity &quantity, MicroProps &micros,
                          UErrorCode &status) const U_OVERRIDE;
 
@@ -95,8 +228,14 @@
      * earlier MicroPropsGenerators in the chain, LongNameMultiplexer keeps the
      * parent link, while the LongNameHandlers are given no parents.
      */
-    MaybeStackVector<LongNameHandler> fLongNameHandlers;
+    MemoryPool<LongNameHandler> fLongNameHandlers;
+    MemoryPool<MixedUnitLongNameHandler> fMixedUnitHandlers;
+    // Unowned pointers to instances owned by MaybeStackVectors.
+    MaybeStackArray<MicroPropsGenerator *, 8> fHandlers;
+    // Each MeasureUnit corresponds to the same-index MicroPropsGenerator
+    // pointed to in fHandlers.
     LocalArray<MeasureUnit> fMeasureUnits;
+
     const MicroPropsGenerator *fParent;
 
     LongNameMultiplexer(const MicroPropsGenerator *parent) : fParent(parent) {
diff --git a/icu4c/source/i18n/number_mapper.cpp b/icu4c/source/i18n/number_mapper.cpp
index ec61743..e2a0d28 100644
--- a/icu4c/source/i18n/number_mapper.cpp
+++ b/icu4c/source/i18n/number_mapper.cpp
@@ -92,6 +92,8 @@
     int32_t minSig = properties.minimumSignificantDigits;
     int32_t maxSig = properties.maximumSignificantDigits;
     double roundingIncrement = properties.roundingIncrement;
+    // Not assigning directly to macros.roundingMode here: we change
+    // roundingMode if and when we also change macros.precision.
     RoundingMode roundingMode = properties.roundingMode.getOrDefault(UNUM_ROUND_HALFEVEN);
     bool explicitMinMaxFrac = minFrac != -1 || maxFrac != -1;
     bool explicitMinMaxSig = minSig != -1 || maxSig != -1;
@@ -145,7 +147,7 @@
         precision = Precision::constructCurrency(currencyUsage);
     }
     if (!precision.isBogus()) {
-        precision.fRoundingMode = roundingMode;
+        macros.roundingMode = roundingMode;
         macros.precision = precision;
     }
 
@@ -239,7 +241,7 @@
                 // TODO: Reset maxSig_ = 1 + minFrac_ to follow the spec.
                 macros.precision = Precision::constructSignificant(minSig_, maxSig_);
             }
-            macros.precision.fRoundingMode = roundingMode;
+            macros.roundingMode = roundingMode;
         }
     }
 
diff --git a/icu4c/source/i18n/number_microprops.h b/icu4c/source/i18n/number_microprops.h
index cb68c41..7258cc2 100644
--- a/icu4c/source/i18n/number_microprops.h
+++ b/icu4c/source/i18n/number_microprops.h
@@ -22,6 +22,51 @@
 U_NAMESPACE_BEGIN namespace number {
 namespace impl {
 
+/**
+ * A copyable container for the integer values of mixed unit measurements.
+ *
+ * If memory allocation fails during copying, no values are copied and status is
+ * set to U_MEMORY_ALLOCATION_ERROR.
+ */
+class IntMeasures : public MaybeStackArray<int64_t, 2> {
+  public:
+    /**
+     * Default constructor initializes with internal T[stackCapacity] buffer.
+     *
+     * Stack Capacity: most mixed units are expected to consist of two or three
+     * subunits, so one or two integer measures should be enough.
+     */
+    IntMeasures() : MaybeStackArray<int64_t, 2>() {
+    }
+
+    /**
+     * Copy constructor.
+     *
+     * If memory allocation fails during copying, no values are copied and
+     * status is set to U_MEMORY_ALLOCATION_ERROR.
+     */
+    IntMeasures(const IntMeasures &other) : MaybeStackArray<int64_t, 2>() {
+        this->operator=(other);
+    }
+
+    // Assignment operator
+    IntMeasures &operator=(const IntMeasures &rhs) {
+        if (this == &rhs) {
+            return *this;
+        }
+        copyFrom(rhs, status);
+        return *this;
+    }
+
+    /** Move constructor */
+    IntMeasures(IntMeasures &&src) = default;
+
+    /** Move assignment */
+    IntMeasures &operator=(IntMeasures &&src) = default;
+
+    UErrorCode status = U_ZERO_ERROR;
+};
+
 // TODO(units): generated by MicroPropsGenerator, but inherits from it too. Do
 // we want to better document why? There's an explanation for processQuantity:
 //  * As MicroProps is the "base instance", this implementation of
@@ -41,22 +86,48 @@
 
     // Note: This struct has no direct ownership of the following pointers.
     const DecimalFormatSymbols* symbols;
+
+    // Pointers to Modifiers provided by the number formatting pipeline (when
+    // the value is known):
+
+    // A Modifier provided by LongNameHandler, used for currency long names and
+    // units. If there is no LongNameHandler needed, this should be an
+    // EmptyModifier. (This is typically the third modifier applied.)
     const Modifier* modOuter;
+    // A Modifier for short currencies and compact notation. (This is typically
+    // the second modifier applied.)
     const Modifier* modMiddle = nullptr;
+    // A Modifier provided by ScientificHandler, used for scientific notation.
+    // This is typically the first modifier applied.
     const Modifier* modInner;
 
     // The following "helper" fields may optionally be used during the MicroPropsGenerator.
     // They live here to retain memory.
     struct {
+        // The ScientificModifier for which ScientificHandler is responsible.
+        // ScientificHandler::processQuantity() modifies this Modifier.
         ScientificModifier scientificModifier;
+        // EmptyModifier used for modOuter
         EmptyModifier emptyWeakModifier{false};
+        // EmptyModifier used for modInner
         EmptyModifier emptyStrongModifier{true};
         MultiplierFormatHandler multiplier;
+        // A Modifier used for Mixed Units. When formatting mixed units,
+        // LongNameHandler assigns this Modifier.
+        SimpleModifier mixedUnitModifier;
     } helpers;
 
-    // The MeasureUnit with which the output measurement is represented.
+    // The MeasureUnit with which the output is represented. May also have
+    // UMEASURE_UNIT_MIXED complexity, in which case mixedMeasures comes into
+    // play.
     MeasureUnit outputUnit;
 
+    // In the case of mixed units, this is the set of integer-only units
+    // *preceding* the final unit.
+    IntMeasures mixedMeasures;
+    // Number of mixedMeasures that have been populated
+    int32_t mixedMeasuresCount = 0;
+
     MicroProps() = default;
 
     MicroProps(const MicroProps& other) = default;
diff --git a/icu4c/source/i18n/number_rounding.cpp b/icu4c/source/i18n/number_rounding.cpp
index 3ffce67..1489667 100644
--- a/icu4c/source/i18n/number_rounding.cpp
+++ b/icu4c/source/i18n/number_rounding.cpp
@@ -5,13 +5,16 @@
 
 #if !UCONFIG_NO_FORMATTING
 
+#include "charstr.h"
 #include "uassert.h"
 #include "unicode/numberformatter.h"
 #include "number_types.h"
 #include "number_decimalquantity.h"
 #include "double-conversion.h"
 #include "number_roundingutils.h"
+#include "number_skeletons.h"
 #include "putilimp.h"
+#include "string_segment.h"
 
 using namespace icu;
 using namespace icu::number;
@@ -19,6 +22,40 @@
 
 
 using double_conversion::DoubleToStringConverter;
+using icu::StringSegment;
+
+// Most blueprint_helpers live in number_skeletons.cpp. This one is in
+// number_rounding.cpp for dependency reasons.
+void blueprint_helpers::parseIncrementOption(const StringSegment &segment, MacroProps &macros,
+                                             UErrorCode &status) {
+    // Need to do char <-> UChar conversion...
+    U_ASSERT(U_SUCCESS(status));
+    CharString buffer;
+    SKELETON_UCHAR_TO_CHAR(buffer, segment.toTempUnicodeString(), 0, segment.length(), status);
+
+    // Utilize DecimalQuantity/decNumber to parse this for us.
+    DecimalQuantity dq;
+    UErrorCode localStatus = U_ZERO_ERROR;
+    dq.setToDecNumber({buffer.data(), buffer.length()}, localStatus);
+    if (U_FAILURE(localStatus)) {
+        // throw new SkeletonSyntaxException("Invalid rounding increment", segment, e);
+        status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+        return;
+    }
+    double increment = dq.toDouble();
+
+    // We also need to figure out how many digits. Do a brute force string operation.
+    int decimalOffset = 0;
+    while (decimalOffset < segment.length() && segment.charAt(decimalOffset) != '.') {
+        decimalOffset++;
+    }
+    if (decimalOffset == segment.length()) {
+        macros.precision = Precision::increment(increment);
+    } else {
+        int32_t fractionLength = segment.length() - decimalOffset - 1;
+        macros.precision = Precision::increment(increment).withMinFraction(fractionLength);
+    }
+}
 
 namespace {
 
@@ -84,7 +121,7 @@
 
 
 Precision Precision::unlimited() {
-    return Precision(RND_NONE, {}, kDefaultMode);
+    return Precision(RND_NONE, {});
 }
 
 FractionPrecision Precision::integer() {
@@ -229,7 +266,7 @@
     settings.fMaxSig = -1;
     PrecisionUnion union_;
     union_.fracSig = settings;
-    return {RND_FRACTION, union_, kDefaultMode};
+    return {RND_FRACTION, union_};
 }
 
 Precision Precision::constructSignificant(int32_t minSig, int32_t maxSig) {
@@ -240,7 +277,7 @@
     settings.fMaxSig = static_cast<digits_t>(maxSig);
     PrecisionUnion union_;
     union_.fracSig = settings;
-    return {RND_SIGNIFICANT, union_, kDefaultMode};
+    return {RND_SIGNIFICANT, union_};
 }
 
 Precision
@@ -250,7 +287,7 @@
     settings.fMaxSig = static_cast<digits_t>(maxSig);
     PrecisionUnion union_;
     union_.fracSig = settings;
-    return {RND_FRACTION_SIGNIFICANT, union_, kDefaultMode};
+    return {RND_FRACTION_SIGNIFICANT, union_};
 }
 
 IncrementPrecision Precision::constructIncrement(double increment, int32_t minFrac) {
@@ -270,18 +307,18 @@
         // NOTE: In C++, we must return the correct value type with the correct union.
         // It would be invalid to return a RND_FRACTION here because the methods on the
         // IncrementPrecision type assume that the union is backed by increment data.
-        return {RND_INCREMENT_ONE, union_, kDefaultMode};
+        return {RND_INCREMENT_ONE, union_};
     } else if (singleDigit == 5) {
-        return {RND_INCREMENT_FIVE, union_, kDefaultMode};
+        return {RND_INCREMENT_FIVE, union_};
     } else {
-        return {RND_INCREMENT, union_, kDefaultMode};
+        return {RND_INCREMENT, union_};
     }
 }
 
 CurrencyPrecision Precision::constructCurrency(UCurrencyUsage usage) {
     PrecisionUnion union_;
     union_.currencyUsage = usage;
-    return {RND_CURRENCY, union_, kDefaultMode};
+    return {RND_CURRENCY, union_};
 }
 
 
@@ -341,6 +378,9 @@
 
 /** This is the method that contains the actual rounding logic. */
 void RoundingImpl::apply(impl::DecimalQuantity &value, UErrorCode& status) const {
+    if (U_FAILURE(status)) {
+        return;
+    }
     if (fPassThrough) {
         return;
     }
diff --git a/icu4c/source/i18n/number_roundingutils.h b/icu4c/source/i18n/number_roundingutils.h
index 3e37f31..c6e5c77 100644
--- a/icu4c/source/i18n/number_roundingutils.h
+++ b/icu4c/source/i18n/number_roundingutils.h
@@ -44,6 +44,9 @@
 inline bool
 getRoundingDirection(bool isEven, bool isNegative, Section section, RoundingMode roundingMode,
                      UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return false;
+    }
     switch (roundingMode) {
         case RoundingMode::UNUM_ROUND_UP:
             // round away from zero
@@ -187,6 +190,12 @@
     Precision fPrecision;
     UNumberFormatRoundingMode fRoundingMode;
     bool fPassThrough = true;  // default value
+
+    // Permits access to fPrecision.
+    friend class UsagePrefsHandler;
+
+    // Permits access to fPrecision.
+    friend class UnitConversionHandler;
 };
 
 
diff --git a/icu4c/source/i18n/number_skeletons.cpp b/icu4c/source/i18n/number_skeletons.cpp
index 7c2a759..7bfcb69 100644
--- a/icu4c/source/i18n/number_skeletons.cpp
+++ b/icu4c/source/i18n/number_skeletons.cpp
@@ -152,21 +152,6 @@
 } UPRV_BLOCK_MACRO_END
 
 
-#define SKELETON_UCHAR_TO_CHAR(dest, src, start, end, status) (void)(dest); \
-UPRV_BLOCK_MACRO_BEGIN { \
-    UErrorCode conversionStatus = U_ZERO_ERROR; \
-    (dest).appendInvariantChars({FALSE, (src).getBuffer() + (start), (end) - (start)}, conversionStatus); \
-    if (conversionStatus == U_INVARIANT_CONVERSION_ERROR) { \
-        /* Don't propagate the invariant conversion error; it is a skeleton syntax error */ \
-        (status) = U_NUMBER_SKELETON_SYNTAX_ERROR; \
-        return; \
-    } else if (U_FAILURE(conversionStatus)) { \
-        (status) = conversionStatus; \
-        return; \
-    } \
-} UPRV_BLOCK_MACRO_END
-
-
 } // anonymous namespace
 
 
@@ -480,6 +465,7 @@
 MacroProps skeleton::parseSkeleton(
         const UnicodeString& skeletonString, int32_t& errOffset, UErrorCode& status) {
     U_ASSERT(U_SUCCESS(status));
+    U_ASSERT(kSerializedStemTrie != nullptr);
 
     // Add a trailing whitespace to the end of the skeleton string to make code cleaner.
     UnicodeString tempSkeletonString(skeletonString);
@@ -586,6 +572,8 @@
 ParseState
 skeleton::parseStem(const StringSegment& segment, const UCharsTrie& stemTrie, SeenMacroProps& seen,
                     MacroProps& macros, UErrorCode& status) {
+    U_ASSERT(U_SUCCESS(status));
+
     // First check for "blueprint" stems, which start with a "signal char"
     switch (segment.charAt(0)) {
         case u'.':
@@ -764,6 +752,7 @@
 
 ParseState skeleton::parseOption(ParseState stem, const StringSegment& segment, MacroProps& macros,
                                  UErrorCode& status) {
+    U_ASSERT(U_SUCCESS(status));
 
     ///// Required options: /////
 
@@ -992,6 +981,7 @@
 
 void blueprint_helpers::parseMeasureUnitOption(const StringSegment& segment, MacroProps& macros,
                                                UErrorCode& status) {
+    U_ASSERT(U_SUCCESS(status));
     const UnicodeString stemString = segment.toTempUnicodeString();
 
     // NOTE: The category (type) of the unit is guaranteed to be a valid subtag (alphanumeric)
@@ -1007,7 +997,6 @@
     }
 
     // Need to do char <-> UChar conversion...
-    U_ASSERT(U_SUCCESS(status));
     CharString type;
     SKELETON_UCHAR_TO_CHAR(type, stemString, 0, firstHyphen, status);
     CharString subType;
@@ -1069,7 +1058,15 @@
         return;
     }
 
-    // TODO(ICU-20941): Clean this up.
+    // Mixed units can only be represented by a full MeasureUnit instances, so
+    // we ignore macros.perUnit.
+    if (fullUnit.complexity == UMEASURE_UNIT_MIXED) {
+        macros.unit = std::move(fullUnit).build(status);
+        return;
+    }
+
+    // TODO(ICU-20941): Clean this up (see also
+    // https://github.com/icu-units/icu/issues/35).
     for (int32_t i = 0; i < fullUnit.units.length(); i++) {
         SingleUnitImpl* subUnit = fullUnit.units[i];
         if (subUnit->dimensionality > 0) {
@@ -1336,36 +1333,8 @@
     return true;
 }
 
-void blueprint_helpers::parseIncrementOption(const StringSegment& segment, MacroProps& macros,
-                                             UErrorCode& status) {
-    // Need to do char <-> UChar conversion...
-    U_ASSERT(U_SUCCESS(status));
-    CharString buffer;
-    SKELETON_UCHAR_TO_CHAR(buffer, segment.toTempUnicodeString(), 0, segment.length(), status);
-
-    // Utilize DecimalQuantity/decNumber to parse this for us.
-    DecimalQuantity dq;
-    UErrorCode localStatus = U_ZERO_ERROR;
-    dq.setToDecNumber({buffer.data(), buffer.length()}, localStatus);
-    if (U_FAILURE(localStatus)) {
-        // throw new SkeletonSyntaxException("Invalid rounding increment", segment, e);
-        status = U_NUMBER_SKELETON_SYNTAX_ERROR;
-        return;
-    }
-    double increment = dq.toDouble();
-
-    // We also need to figure out how many digits. Do a brute force string operation.
-    int decimalOffset = 0;
-    while (decimalOffset < segment.length() && segment.charAt(decimalOffset) != '.') {
-        decimalOffset++;
-    }
-    if (decimalOffset == segment.length()) {
-        macros.precision = Precision::increment(increment);
-    } else {
-        int32_t fractionLength = segment.length() - decimalOffset - 1;
-        macros.precision = Precision::increment(increment).withMinFraction(fractionLength);
-    }
-}
+// blueprint_helpers::parseIncrementOption lives in number_rounding.cpp for
+// dependencies reasons.
 
 void blueprint_helpers::generateIncrementOption(double increment, int32_t trailingZeros, UnicodeString& sb,
                                                 UErrorCode&) {
@@ -1551,10 +1520,14 @@
     } else if (utils::unitIsPermille(macros.unit)) {
         sb.append(u"permille", -1);
         return true;
-    } else {
+    } else if (uprv_strcmp(macros.unit.getType(), "") != 0) {
         sb.append(u"measure-unit/", -1);
         blueprint_helpers::generateMeasureUnitOption(macros.unit, sb, status);
         return true;
+    } else {
+        // TODO(icu-units#35): add support for not-built-in units.
+        status = U_UNSUPPORTED_ERROR;
+        return false;
     }
 }
 
@@ -1573,7 +1546,7 @@
     }
 }
 
-bool GeneratorHelpers::usage(const MacroProps& macros, UnicodeString& sb, UErrorCode&) {
+bool GeneratorHelpers::usage(const MacroProps& macros, UnicodeString& sb, UErrorCode& /* status */) {
     if (macros.usage.fLength > 0) {
         sb.append(u"usage/", -1);
         sb.append(UnicodeString(macros.usage.fUsage, -1, US_INV));
diff --git a/icu4c/source/i18n/number_skeletons.h b/icu4c/source/i18n/number_skeletons.h
index 313c7ac..38dfa19 100644
--- a/icu4c/source/i18n/number_skeletons.h
+++ b/icu4c/source/i18n/number_skeletons.h
@@ -246,6 +246,10 @@
 
 void parseMeasurePerUnitOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status);
 
+/**
+ * Parses unit identifiers like "meter-per-second" and "foot-and-inch", as
+ * specified via a "unit/" concise skeleton.
+ */
 void parseIdentifierUnitOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status);
 
 void parseUnitUsageOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status);
@@ -355,6 +359,24 @@
     bool scale = false;
 };
 
+namespace {
+
+#define SKELETON_UCHAR_TO_CHAR(dest, src, start, end, status) (void)(dest); \
+UPRV_BLOCK_MACRO_BEGIN { \
+    UErrorCode conversionStatus = U_ZERO_ERROR; \
+    (dest).appendInvariantChars({false, (src).getBuffer() + (start), (end) - (start)}, conversionStatus); \
+    if (conversionStatus == U_INVARIANT_CONVERSION_ERROR) { \
+        /* Don't propagate the invariant conversion error; it is a skeleton syntax error */ \
+        (status) = U_NUMBER_SKELETON_SYNTAX_ERROR; \
+        return; \
+    } else if (U_FAILURE(conversionStatus)) { \
+        (status) = conversionStatus; \
+        return; \
+    } \
+} UPRV_BLOCK_MACRO_END
+
+} // namespace
+
 } // namespace impl
 } // namespace number
 U_NAMESPACE_END
diff --git a/icu4c/source/i18n/number_symbolswrapper.cpp b/icu4c/source/i18n/number_symbolswrapper.cpp
new file mode 100644
index 0000000..5f7648d
--- /dev/null
+++ b/icu4c/source/i18n/number_symbolswrapper.cpp
@@ -0,0 +1,125 @@
+// © 2020 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "number_microprops.h"
+#include "unicode/numberformatter.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+SymbolsWrapper::SymbolsWrapper(const SymbolsWrapper &other) {
+    doCopyFrom(other);
+}
+
+SymbolsWrapper::SymbolsWrapper(SymbolsWrapper &&src) U_NOEXCEPT {
+    doMoveFrom(std::move(src));
+}
+
+SymbolsWrapper &SymbolsWrapper::operator=(const SymbolsWrapper &other) {
+    if (this == &other) {
+        return *this;
+    }
+    doCleanup();
+    doCopyFrom(other);
+    return *this;
+}
+
+SymbolsWrapper &SymbolsWrapper::operator=(SymbolsWrapper &&src) U_NOEXCEPT {
+    if (this == &src) {
+        return *this;
+    }
+    doCleanup();
+    doMoveFrom(std::move(src));
+    return *this;
+}
+
+SymbolsWrapper::~SymbolsWrapper() {
+    doCleanup();
+}
+
+void SymbolsWrapper::setTo(const DecimalFormatSymbols &dfs) {
+    doCleanup();
+    fType = SYMPTR_DFS;
+    fPtr.dfs = new DecimalFormatSymbols(dfs);
+}
+
+void SymbolsWrapper::setTo(const NumberingSystem *ns) {
+    doCleanup();
+    fType = SYMPTR_NS;
+    fPtr.ns = ns;
+}
+
+void SymbolsWrapper::doCopyFrom(const SymbolsWrapper &other) {
+    fType = other.fType;
+    switch (fType) {
+    case SYMPTR_NONE:
+        // No action necessary
+        break;
+    case SYMPTR_DFS:
+        // Memory allocation failures are exposed in copyErrorTo()
+        if (other.fPtr.dfs != nullptr) {
+            fPtr.dfs = new DecimalFormatSymbols(*other.fPtr.dfs);
+        } else {
+            fPtr.dfs = nullptr;
+        }
+        break;
+    case SYMPTR_NS:
+        // Memory allocation failures are exposed in copyErrorTo()
+        if (other.fPtr.ns != nullptr) {
+            fPtr.ns = new NumberingSystem(*other.fPtr.ns);
+        } else {
+            fPtr.ns = nullptr;
+        }
+        break;
+    }
+}
+
+void SymbolsWrapper::doMoveFrom(SymbolsWrapper &&src) {
+    fType = src.fType;
+    switch (fType) {
+    case SYMPTR_NONE:
+        // No action necessary
+        break;
+    case SYMPTR_DFS:
+        fPtr.dfs = src.fPtr.dfs;
+        src.fPtr.dfs = nullptr;
+        break;
+    case SYMPTR_NS:
+        fPtr.ns = src.fPtr.ns;
+        src.fPtr.ns = nullptr;
+        break;
+    }
+}
+
+void SymbolsWrapper::doCleanup() {
+    switch (fType) {
+    case SYMPTR_NONE:
+        // No action necessary
+        break;
+    case SYMPTR_DFS:
+        delete fPtr.dfs;
+        break;
+    case SYMPTR_NS:
+        delete fPtr.ns;
+        break;
+    }
+}
+
+bool SymbolsWrapper::isDecimalFormatSymbols() const {
+    return fType == SYMPTR_DFS;
+}
+
+bool SymbolsWrapper::isNumberingSystem() const {
+    return fType == SYMPTR_NS;
+}
+
+const DecimalFormatSymbols *SymbolsWrapper::getDecimalFormatSymbols() const {
+    U_ASSERT(fType == SYMPTR_DFS);
+    return fPtr.dfs;
+}
+
+const NumberingSystem *SymbolsWrapper::getNumberingSystem() const {
+    U_ASSERT(fType == SYMPTR_NS);
+    return fPtr.ns;
+}
diff --git a/icu4c/source/i18n/number_types.h b/icu4c/source/i18n/number_types.h
index 8180fe5..8078851 100644
--- a/icu4c/source/i18n/number_types.h
+++ b/icu4c/source/i18n/number_types.h
@@ -262,7 +262,7 @@
  */
 class U_I18N_API MicroPropsGenerator {
   public:
-    virtual ~MicroPropsGenerator();
+    virtual ~MicroPropsGenerator() = default;
 
     /**
      * Considers the given {@link DecimalQuantity}, optionally mutates it, and
diff --git a/icu4c/source/i18n/number_usageprefs.cpp b/icu4c/source/i18n/number_usageprefs.cpp
index 8a2669a..cd426f4 100644
--- a/icu4c/source/i18n/number_usageprefs.cpp
+++ b/icu4c/source/i18n/number_usageprefs.cpp
@@ -10,6 +10,7 @@
 #include "number_decimalquantity.h"
 #include "number_microprops.h"
 #include "number_roundingutils.h"
+#include "number_skeletons.h"
 #include "unicode/char16ptr.h"
 #include "unicode/currunit.h"
 #include "unicode/fmtable.h"
@@ -18,9 +19,13 @@
 #include "unicode/platform.h"
 #include "unicode/unum.h"
 #include "unicode/urename.h"
+#include "units_data.h"
 
+using namespace icu;
 using namespace icu::number;
 using namespace icu::number::impl;
+using icu::StringSegment;
+using icu::units::ConversionRates;
 
 // Copy constructor
 Usage::Usage(const Usage &other) : fUsage(nullptr), fLength(other.fLength), fError(other.fError) {
@@ -41,10 +46,7 @@
     return *this;
 }
 
-// Move constructor - can it be improved by taking over src's "this" instead of
-// copying contents? Swapping pointers makes sense for heap objects but not for
-// stack objects.
-// *this = std::move(src);
+// Move constructor
 Usage::Usage(Usage &&src) U_NOEXCEPT : fUsage(src.fUsage), fLength(src.fLength), fError(src.fError) {
     // Take ownership away from src if necessary
     src.fUsage = nullptr;
@@ -84,8 +86,43 @@
     fUsage[fLength] = 0;
 }
 
+void mixedMeasuresToMicros(const MaybeStackVector<Measure> &measures, DecimalQuantity *quantity,
+                           MicroProps *micros, UErrorCode status) {
+    micros->mixedMeasuresCount = measures.length() - 1;
+    if (micros->mixedMeasuresCount > 0) {
+#ifdef U_DEBUG
+        U_ASSERT(micros->outputUnit.getComplexity(status) == UMEASURE_UNIT_MIXED);
+        U_ASSERT(U_SUCCESS(status));
+        // Check that we received measurements with the expected MeasureUnits:
+        int32_t singleUnitsCount;
+        LocalArray<MeasureUnit> singleUnits =
+            micros->outputUnit.splitToSingleUnits(singleUnitsCount, status);
+        U_ASSERT(U_SUCCESS(status));
+        U_ASSERT(measures.length() == singleUnitsCount);
+        for (int32_t i = 0; i < measures.length(); i++) {
+            U_ASSERT(measures[i]->getUnit() == singleUnits[i]);
+        }
+#endif
+        // Mixed units: except for the last value, we pass all values to the
+        // LongNameHandler via micros->mixedMeasures.
+        if (micros->mixedMeasures.getCapacity() < micros->mixedMeasuresCount) {
+            if (micros->mixedMeasures.resize(micros->mixedMeasuresCount) == nullptr) {
+                status = U_MEMORY_ALLOCATION_ERROR;
+                return;
+            }
+        }
+        for (int32_t i = 0; i < micros->mixedMeasuresCount; i++) {
+            micros->mixedMeasures[i] = measures[i]->getNumber().getInt64();
+        }
+    } else {
+        micros->mixedMeasuresCount = 0;
+    }
+    // The last value (potentially the only value) gets passed on via quantity.
+    quantity->setToDouble(measures[measures.length() - 1]->getNumber().getDouble());
+}
+
 UsagePrefsHandler::UsagePrefsHandler(const Locale &locale,
-                                     const MeasureUnit inputUnit,
+                                     const MeasureUnit &inputUnit,
                                      const StringPiece usage,
                                      const MicroPropsGenerator *parent,
                                      UErrorCode &status)
@@ -102,25 +139,95 @@
 
     quantity.roundToInfinity(); // Enables toDouble
     const auto routed = fUnitsRouter.route(quantity.toDouble(), status);
-    const auto& routedUnits = routed.measures;
-    micros.outputUnit = routedUnits[0]->getUnit();
-    quantity.setToDouble(routedUnits[0]->getNumber().getDouble());
-
-    // TODO(units): here we are always overriding Precision. (1) get precision
-    // from fUnitsRouter, (2) ensure we use the UnitPreference skeleton's
-    // precision only when there isn't an explicit override we prefer to use.
-    // This needs to be handled within
-    // NumberFormatterImpl::macrosToMicroGenerator in number_formatimpl.cpp
-    // TODO: Use precision from `routed` result.
-    Precision precision = Precision::integer().withMinDigits(2);
-    UNumberFormatRoundingMode roundingMode;
-    // Temporary until ICU 64?
-    roundingMode = precision.fRoundingMode;
-    CurrencyUnit currency(u"", status);
-    micros.rounder = {precision, roundingMode, currency, status};
     if (U_FAILURE(status)) {
         return;
     }
+    const MaybeStackVector<Measure>& routedUnits = routed.measures;
+    micros.outputUnit = routed.outputUnit.copy(status).build(status);
+    if (U_FAILURE(status)) {
+        return;
+    }
+
+    mixedMeasuresToMicros(routedUnits, &quantity, &micros, status);
+
+    UnicodeString precisionSkeleton = routed.precision;
+    if (micros.rounder.fPrecision.isBogus()) {
+        if (precisionSkeleton.length() > 0) {
+            micros.rounder.fPrecision = parseSkeletonToPrecision(precisionSkeleton, status);
+        } else {
+            // We use the same rounding mode as COMPACT notation: known to be a
+            // human-friendly rounding mode: integers, but add a decimal digit
+            // as needed to ensure we have at least 2 significant digits.
+            micros.rounder.fPrecision = Precision::integer().withMinDigits(2);
+        }
+    }
+}
+
+Precision UsagePrefsHandler::parseSkeletonToPrecision(icu::UnicodeString precisionSkeleton,
+                                                      UErrorCode status) {
+    if (U_FAILURE(status)) {
+        // As a member of UsagePrefsHandler, which is a friend of Precision, we
+        // get access to the default constructor.
+        return {};
+    }
+    constexpr int32_t kSkelPrefixLen = 20;
+    if (!precisionSkeleton.startsWith(UNICODE_STRING_SIMPLE("precision-increment/"))) {
+        status = U_INVALID_FORMAT_ERROR;
+        return {};
+    }
+    U_ASSERT(precisionSkeleton[kSkelPrefixLen - 1] == u'/');
+    StringSegment segment(precisionSkeleton, false);
+    segment.adjustOffset(kSkelPrefixLen);
+    MacroProps macros;
+    blueprint_helpers::parseIncrementOption(segment, macros, status);
+    return macros.precision;
+}
+
+UnitConversionHandler::UnitConversionHandler(const MeasureUnit &unit, const MicroPropsGenerator *parent,
+                                             UErrorCode &status)
+    : fOutputUnit(unit), fParent(parent) {
+    MeasureUnitImpl temp;
+    const MeasureUnitImpl &outputUnit = MeasureUnitImpl::forMeasureUnit(unit, temp, status);
+    const MeasureUnitImpl *inputUnit = &outputUnit;
+    MaybeStackVector<MeasureUnitImpl> singleUnits;
+    U_ASSERT(outputUnit.complexity == UMEASURE_UNIT_MIXED);
+    // When we wish to support unit conversion, replace the above assert with this if:
+    // if (outputUnit.complexity == UMEASURE_UNIT_MIXED) {
+    {
+        singleUnits = outputUnit.extractIndividualUnits(status);
+        U_ASSERT(singleUnits.length() > 0);
+        inputUnit = singleUnits[0];
+    }
+    // TODO: this should become an initOnce thing? Review with other
+    // ConversionRates usages.
+    ConversionRates conversionRates(status);
+    if (U_FAILURE(status)) {
+        return;
+    }
+    fUnitConverter.adoptInsteadAndCheckErrorCode(
+        new ComplexUnitsConverter(*inputUnit, outputUnit, conversionRates, status), status);
+}
+
+void UnitConversionHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micros,
+                                            UErrorCode &status) const {
+    fParent->processQuantity(quantity, micros, status);
+    if (U_FAILURE(status)) {
+        return;
+    }
+    quantity.roundToInfinity(); // Enables toDouble
+    MaybeStackVector<Measure> measures = fUnitConverter->convert(quantity.toDouble(), status);
+    micros.outputUnit = fOutputUnit;
+    if (U_FAILURE(status)) {
+        return;
+    }
+
+    mixedMeasuresToMicros(measures, &quantity, &micros, status);
+
+    // TODO: add tests to explore behaviour that may suggest a more
+    // human-centric default rounder?
+    // if (micros.rounder.fPrecision.isBogus()) {
+    //     micros.rounder.fPrecision = Precision::integer().withMinDigits(2);
+    // }
 }
 
 #endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/number_usageprefs.h b/icu4c/source/i18n/number_usageprefs.h
index fa56c1e..178b09d 100644
--- a/icu4c/source/i18n/number_usageprefs.h
+++ b/icu4c/source/i18n/number_usageprefs.h
@@ -9,18 +9,23 @@
 
 #include "cmemory.h"
 #include "number_types.h"
+#include "unicode/listformatter.h"
+#include "unicode/localpointer.h"
 #include "unicode/locid.h"
 #include "unicode/measunit.h"
 #include "unicode/stringpiece.h"
 #include "unicode/uobject.h"
-#include "unitsrouter.h"
+#include "units_converter.h"
+#include "units_router.h"
 
 U_NAMESPACE_BEGIN
+
+using ::icu::units::ComplexUnitsConverter;
+using ::icu::units::UnitsRouter;
+
 namespace number {
 namespace impl {
 
-using ::icu::units::UnitsRouter;
-
 /**
  * A MicroPropsGenerator which uses UnitsRouter to produce output converted to a
  * MeasureUnit appropriate for a particular localized usage: see
@@ -28,12 +33,15 @@
  */
 class U_I18N_API UsagePrefsHandler : public MicroPropsGenerator, public UMemory {
   public:
-    UsagePrefsHandler(const Locale &locale, const MeasureUnit inputUnit, const StringPiece usage,
+    UsagePrefsHandler(const Locale &locale, const MeasureUnit &inputUnit, const StringPiece usage,
                       const MicroPropsGenerator *parent, UErrorCode &status);
 
     /**
-     * Obtains the appropriate output value, MeasurementUnit and
+     * Obtains the appropriate output value, MeasureUnit and
      * rounding/precision behaviour from the UnitsRouter.
+     *
+     * The output unit is passed on to the LongNameHandler via
+     * micros.outputUnit.
      */
     void processQuantity(DecimalQuantity &quantity, MicroProps &micros,
                          UErrorCode &status) const U_OVERRIDE;
@@ -52,6 +60,62 @@
   private:
     UnitsRouter fUnitsRouter;
     const MicroPropsGenerator *fParent;
+
+    static Precision parseSkeletonToPrecision(icu::UnicodeString precisionSkeleton, UErrorCode status);
+};
+
+} // namespace impl
+} // namespace number
+
+// Export explicit template instantiations of LocalPointerBase and LocalPointer.
+// This is required when building DLLs for Windows. (See datefmt.h,
+// collationiterator.h, erarules.h and others for similar examples.)
+//
+// Note: These need to be outside of the number::impl namespace, or Clang will
+// generate a compile error.
+#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
+#if defined(_MSC_VER)
+// Ignore warning 4661 as LocalPointerBase does not use operator== or operator!=
+#pragma warning(push)
+#pragma warning(disable: 4661)
+#endif
+template class U_I18N_API LocalPointerBase<ComplexUnitsConverter>;
+template class U_I18N_API LocalPointer<ComplexUnitsConverter>;
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+#endif
+
+namespace number {
+namespace impl {
+
+/**
+ * A MicroPropsGenerator which converts a measurement from a simple MeasureUnit
+ * to a Mixed MeasureUnit.
+ */
+class U_I18N_API UnitConversionHandler : public MicroPropsGenerator, public UMemory {
+  public:
+    /**
+     * Constructor.
+     *
+     * @param unit Specifies both the input and output MeasureUnit: if it is a
+     *     MIXED unit, the input MeasureUnit will be just the biggest unit of
+     *     the sequence.
+     * @param parent The parent MicroPropsGenerator.
+     * @param status Receives status.
+     */
+    UnitConversionHandler(const MeasureUnit &unit, const MicroPropsGenerator *parent,
+                          UErrorCode &status);
+
+    /**
+     * Obtains the appropriate output values from the Unit Converter.
+     */
+    void processQuantity(DecimalQuantity &quantity, MicroProps &micros,
+                         UErrorCode &status) const U_OVERRIDE;
+  private:
+    MeasureUnit fOutputUnit;
+    LocalPointer<ComplexUnitsConverter> fUnitConverter;
+    const MicroPropsGenerator *fParent;
 };
 
 } // namespace impl
diff --git a/icu4c/source/i18n/sources.txt b/icu4c/source/i18n/sources.txt
index 8c989ed..b26485d 100644
--- a/icu4c/source/i18n/sources.txt
+++ b/icu4c/source/i18n/sources.txt
@@ -32,7 +32,6 @@
 collationtailoring.cpp
 collationweights.cpp
 compactdecimalformat.cpp
-complexunitsconverter.cpp
 coptccal.cpp
 cpdtrans.cpp
 csdetect.cpp
@@ -122,6 +121,7 @@
 number_rounding.cpp
 number_scientific.cpp
 number_skeletons.cpp
+number_symbolswrapper.cpp
 number_usageprefs.cpp
 number_utils.cpp
 numfmt.cpp
@@ -210,9 +210,10 @@
 umsg.cpp
 unesctrn.cpp
 uni2name.cpp
-unitconverter.cpp
-unitsdata.cpp
-unitsrouter.cpp
+units_data.cpp
+units_complexconverter.cpp
+units_converter.cpp
+units_router.cpp
 unum.cpp
 unumsys.cpp
 upluralrules.cpp
diff --git a/icu4c/source/i18n/unicode/numberformatter.h b/icu4c/source/i18n/unicode/numberformatter.h
index bc4326f..a4d0724 100644
--- a/icu4c/source/i18n/unicode/numberformatter.h
+++ b/icu4c/source/i18n/unicode/numberformatter.h
@@ -707,12 +707,8 @@
     typedef PrecisionUnion::FractionSignificantSettings FractionSignificantSettings;
     typedef PrecisionUnion::IncrementSettings IncrementSettings;
 
-    /** The Precision encapsulates the RoundingMode when used within the implementation. */
-    UNumberFormatRoundingMode fRoundingMode;
-
-    Precision(const PrecisionType& type, const PrecisionUnion& union_,
-              UNumberFormatRoundingMode roundingMode)
-            : fType(type), fUnion(union_), fRoundingMode(roundingMode) {}
+    Precision(const PrecisionType& type, const PrecisionUnion& union_)
+            : fType(type), fUnion(union_) {}
 
     Precision(UErrorCode errorCode) : fType(RND_ERROR) {
         fUnion.errorCode = errorCode;
@@ -746,8 +742,6 @@
 
     static CurrencyPrecision constructCurrency(UCurrencyUsage usage);
 
-    static Precision constructPassThrough();
-
     // To allow MacroProps/MicroProps to initialize bogus instances:
     friend struct impl::MacroProps;
     friend struct impl::MicroProps;
@@ -769,9 +763,7 @@
     // To allow access to the skeleton generation code:
     friend class impl::GeneratorHelpers;
 
-    // TODO(units): revisit when UnitsRouter is changed: do we still need this
-    // once Precision is returned by UnitsRouter? For now, we allow access to
-    // Precision constructor from UsagePrefsHandler:
+    // To allow access to isBogus and the default (bogus) constructor:
     friend class impl::UsagePrefsHandler;
 };
 
diff --git a/icu4c/source/i18n/complexunitsconverter.cpp b/icu4c/source/i18n/units_complexconverter.cpp
similarity index 73%
rename from icu4c/source/i18n/complexunitsconverter.cpp
rename to icu4c/source/i18n/units_complexconverter.cpp
index 7ad1c5f..f145030 100644
--- a/icu4c/source/i18n/complexunitsconverter.cpp
+++ b/icu4c/source/i18n/units_complexconverter.cpp
@@ -8,14 +8,14 @@
 #include <cmath>
 
 #include "cmemory.h"
-#include "complexunitsconverter.h"
 #include "uarrsort.h"
 #include "uassert.h"
 #include "unicode/fmtable.h"
 #include "unicode/localpointer.h"
 #include "unicode/measunit.h"
 #include "unicode/measure.h"
-#include "unitconverter.h"
+#include "units_complexconverter.h"
+#include "units_converter.h"
 
 U_NAMESPACE_BEGIN
 namespace units {
@@ -30,6 +30,11 @@
 
     U_ASSERT(units_.length() != 0);
 
+    // Save the desired order of output units before we sort units_
+    for (int32_t i = 0; i < units_.length(); i++) {
+        outputUnits_.emplaceBackAndCheckErrorCode(status, units_[i]->copy(status).build(status));
+    }
+
     // NOTE:
     //  This comparator is used to sort the units in a descending order. Therefore, we return -1 if
     //  the left is bigger than right and so on.
@@ -101,13 +106,21 @@
 }
 
 MaybeStackVector<Measure> ComplexUnitsConverter::convert(double quantity, UErrorCode &status) const {
+    // TODO(icu-units#63): test negative numbers!
+    // TODO(hugovdm): return an error for "foot-and-foot"?
     MaybeStackVector<Measure> result;
 
     for (int i = 0, n = unitConverters_.length(); i < n; ++i) {
         quantity = (*unitConverters_[i]).convert(quantity);
         if (i < n - 1) {
-            int64_t newQuantity = floor(quantity);
-            Formattable formattableNewQuantity(newQuantity);
+            // The double type has 15 decimal digits of precision. For choosing
+            // whether to use the current unit or the next smaller unit, we
+            // therefore nudge up the number with which the thresholding
+            // decision is made. However after the thresholding, we use the
+            // original values to ensure unbiased accuracy (to the extent of
+            // double's capabilities).
+            int64_t roundedQuantity = floor(quantity * (1 + DBL_EPSILON));
+            Formattable formattableNewQuantity(roundedQuantity);
 
             // NOTE: Measure would own its MeasureUnit.
             MeasureUnit *type = new MeasureUnit(units_[i]->copy(status).build(status));
@@ -115,7 +128,14 @@
 
             // Keep the residual of the quantity.
             //   For example: `3.6 feet`, keep only `0.6 feet`
-            quantity -= newQuantity;
+            //
+            // When the calculation is near enough +/- DBL_EPSILON, we round to
+            // zero. (We also ensure no negative values here.)
+            if ((quantity - roundedQuantity) / quantity < DBL_EPSILON) {
+                quantity = 0;
+            } else {
+                quantity -= roundedQuantity;
+            }
         } else { // LAST ELEMENT
             Formattable formattableQuantity(quantity);
 
@@ -125,6 +145,24 @@
         }
     }
 
+    MaybeStackVector<Measure> orderedResult;
+    int32_t unitsCount = outputUnits_.length();
+    U_ASSERT(unitsCount == units_.length());
+    Measure **arr = result.getAlias();
+    // O(N^2) is fine: mixed units' unitsCount is usually 2 or 3.
+    for (int32_t i = 0; i < unitsCount; i++) {
+        for (int32_t j = i; j < unitsCount; j++) {
+            // Find the next expected unit, and swap it into place.
+            if (result[j]->getUnit() == *outputUnits_[i]) {
+                if (j != i) {
+                    Measure *tmp = arr[j];
+                    arr[j] = arr[i];
+                    arr[i] = tmp;
+                }
+            }
+        }
+    }
+
     return result;
 }
 
diff --git a/icu4c/source/i18n/complexunitsconverter.h b/icu4c/source/i18n/units_complexconverter.h
similarity index 64%
rename from icu4c/source/i18n/complexunitsconverter.h
rename to icu4c/source/i18n/units_complexconverter.h
index 1cf2eb4..fc355d9 100644
--- a/icu4c/source/i18n/complexunitsconverter.h
+++ b/icu4c/source/i18n/units_complexconverter.h
@@ -4,18 +4,36 @@
 #include "unicode/utypes.h"
 
 #if !UCONFIG_NO_FORMATTING
-#ifndef __COMPLEXUNITSCONVERTER_H__
-#define __COMPLEXUNITSCONVERTER_H__
+#ifndef __UNITS_COMPLEXCONVERTER_H__
+#define __UNITS_COMPLEXCONVERTER_H__
 
 #include "cmemory.h"
 #include "measunit_impl.h"
 #include "unicode/errorcode.h"
 #include "unicode/measure.h"
-#include "unitconverter.h"
-#include "unitsdata.h"
+#include "units_converter.h"
+#include "units_data.h"
 
 U_NAMESPACE_BEGIN
 
+// Export explicit template instantiations of MaybeStackArray, MemoryPool and
+// MaybeStackVector. This is required when building DLLs for Windows. (See
+// datefmt.h, collationiterator.h, erarules.h and others for similar examples.)
+//
+// 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<MeasureUnitImpl*, 8>;
+template class U_I18N_API MemoryPool<MeasureUnitImpl, 8>;
+template class U_I18N_API MaybeStackVector<MeasureUnitImpl, 8>;
+template class U_I18N_API MaybeStackArray<MeasureUnit*, 8>;
+template class U_I18N_API MemoryPool<MeasureUnit, 8>;
+template class U_I18N_API MaybeStackVector<MeasureUnit, 8>;
+#endif
+
 namespace units {
 
 /**
@@ -27,7 +45,7 @@
  *    single unit to another single unit). Therefore, `ComplexUnitsConverter` class contains multiple
  *    instances of the `UnitConverter` to perform the conversion.
  */
-class U_I18N_API ComplexUnitsConverter : UMemory {
+class U_I18N_API ComplexUnitsConverter : public UMemory {
   public:
     /**
      * Constructor of `ComplexUnitsConverter`.
@@ -59,12 +77,15 @@
 
   private:
     MaybeStackVector<UnitConverter> unitConverters_;
+    // Individual units of mixed units, sorted big to small
     MaybeStackVector<MeasureUnitImpl> units_;
+    // Individual units of mixed units, sorted in desired output order
+    MaybeStackVector<MeasureUnit> outputUnits_;
 };
 
 } // namespace units
 U_NAMESPACE_END
 
-#endif //__COMPLEXUNITSCONVERTER_H__
+#endif //__UNITS_COMPLEXCONVERTER_H__
 
 #endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/unitconverter.cpp b/icu4c/source/i18n/units_converter.cpp
similarity index 98%
rename from icu4c/source/i18n/unitconverter.cpp
rename to icu4c/source/i18n/units_converter.cpp
index bf472f5..3463387 100644
--- a/icu4c/source/i18n/unitconverter.cpp
+++ b/icu4c/source/i18n/units_converter.cpp
@@ -13,7 +13,7 @@
 #include "unicode/errorcode.h"
 #include "unicode/localpointer.h"
 #include "unicode/stringpiece.h"
-#include "unitconverter.h"
+#include "units_converter.h"
 #include <algorithm>
 #include <cmath>
 #include <stdlib.h>
@@ -516,11 +516,7 @@
         result = 1.0 / result;
     }
 
-    // TODO: remove the multiplication by 1.000,000,000,001 after using `decNumber`
-
-    // Multiply the result by 1.000,000,000,001 to fix the deterioration from using `double` (the
-    // deterioration is around 15 to 17 decimal digit).
-    return result * 1.000000000001;
+    return result;
 }
 
 } // namespace units
diff --git a/icu4c/source/i18n/unitconverter.h b/icu4c/source/i18n/units_converter.h
similarity index 96%
rename from icu4c/source/i18n/unitconverter.h
rename to icu4c/source/i18n/units_converter.h
index 3b66dbd..2f5dad8 100644
--- a/icu4c/source/i18n/unitconverter.h
+++ b/icu4c/source/i18n/units_converter.h
@@ -4,16 +4,16 @@
 #include "unicode/utypes.h"
 
 #if !UCONFIG_NO_FORMATTING
-#ifndef __UNITCONVERTER_H__
-#define __UNITCONVERTER_H__
+#ifndef __UNITS_CONVERTER_H__
+#define __UNITS_CONVERTER_H__
 
 #include "cmemory.h"
 #include "measunit_impl.h"
 #include "unicode/errorcode.h"
 #include "unicode/stringpiece.h"
 #include "unicode/uobject.h"
-#include "unitconverter.h"
-#include "unitsdata.h"
+#include "units_converter.h"
+#include "units_data.h"
 
 U_NAMESPACE_BEGIN
 namespace units {
@@ -81,7 +81,7 @@
 /**
  * Represents the conversion rate between `source` and `target`.
  */
-struct ConversionRate : public UMemory {
+struct U_I18N_API ConversionRate : public UMemory {
     const MeasureUnitImpl source;
     const MeasureUnitImpl target;
     double factorNum = 1;
@@ -159,6 +159,6 @@
 } // namespace units
 U_NAMESPACE_END
 
-#endif //__UNITCONVERTER_H__
+#endif //__UNITS_CONVERTER_H__
 
 #endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/unitsdata.cpp b/icu4c/source/i18n/units_data.cpp
similarity index 98%
rename from icu4c/source/i18n/unitsdata.cpp
rename to icu4c/source/i18n/units_data.cpp
index 098c9f5..42bd624 100644
--- a/icu4c/source/i18n/unitsdata.cpp
+++ b/icu4c/source/i18n/units_data.cpp
@@ -11,7 +11,7 @@
 #include "uassert.h"
 #include "unicode/unistr.h"
 #include "unicode/ures.h"
-#include "unitsdata.h"
+#include "units_data.h"
 #include "uresimp.h"
 #include "util.h"
 #include <utility>
@@ -293,9 +293,7 @@
         } else if (uprv_strcmp(desired.usage.data(), "default") != 0) {
             desired.usage.truncate(0).append("default", status);
         } else {
-            // TODO(icu-units/icu#36): reconsider consistency of errors.
-            // Currently this U_MISSING_RESOURCE_ERROR propagates when a
-            // U_NUMBER_SKELETON_SYNTAX_ERROR might be much more intuitive.
+            // "default" is not supposed to be missing for any valid category.
             status = U_MISSING_RESOURCE_ERROR;
             return -1;
         }
@@ -310,6 +308,7 @@
             idx = binarySearch(metadata, desired, &foundCategory, &foundUsage, &foundRegion, status);
         }
         if (!foundRegion) {
+            // "001" is not supposed to be missing for any valid usage.
             status = U_MISSING_RESOURCE_ERROR;
             return -1;
         }
diff --git a/icu4c/source/i18n/unitsdata.h b/icu4c/source/i18n/units_data.h
similarity index 78%
rename from icu4c/source/i18n/unitsdata.h
rename to icu4c/source/i18n/units_data.h
index df5f591..b6fe8e8 100644
--- a/icu4c/source/i18n/unitsdata.h
+++ b/icu4c/source/i18n/units_data.h
@@ -4,8 +4,8 @@
 #include "unicode/utypes.h"
 
 #if !UCONFIG_NO_FORMATTING
-#ifndef __GETUNITSDATA_H__
-#define __GETUNITSDATA_H__
+#ifndef __UNITS_DATA_H__
+#define __UNITS_DATA_H__
 
 #include <limits>
 
@@ -26,10 +26,10 @@
  * Categories are found in `unitQuantities` in the `units` resource (see
  * `units.txt`).
  *
- * TODO(hugovdm): if we give unitsdata.cpp access to the functionality of
- * `extractCompoundBaseUnit` which is currently in unitconverter.cpp, we could
+ * TODO(hugovdm): if we give units_data.cpp access to the functionality of
+ * `extractCompoundBaseUnit` which is currently in units_converter.cpp, we could
  * support all units for which there is a category. Does it make sense to move
- * that function to unitsdata.cpp?
+ * that function to units_data.cpp?
  */
 CharString U_I18N_API getUnitCategory(const char *baseUnitIdentifier, UErrorCode &status);
 
@@ -59,6 +59,22 @@
     CharString offset;
 };
 
+} // namespace units
+
+// Export explicit template instantiations of MaybeStackArray, MemoryPool and
+// MaybeStackVector. This is required when building DLLs for Windows. (See
+// datefmt.h, collationiterator.h, erarules.h and others for similar examples.)
+//
+// 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::ConversionRateInfo*, 8>;
+template class U_I18N_API MemoryPool<units::ConversionRateInfo, 8>;
+template class U_I18N_API MaybeStackVector<units::ConversionRateInfo, 8>;
+#endif
+
+namespace units {
+
 /**
  * Returns ConversionRateInfo for all supported conversions.
  *
@@ -136,6 +152,25 @@
                       bool *foundRegion) const;
 };
 
+} // namespace units
+
+// Export explicit template instantiations of MaybeStackArray, MemoryPool and
+// MaybeStackVector. This is required when building DLLs for Windows. (See
+// datefmt.h, collationiterator.h, erarules.h and others for similar examples.)
+//
+// 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::UnitPreferenceMetadata*, 8>;
+template class U_I18N_API MemoryPool<units::UnitPreferenceMetadata, 8>;
+template class U_I18N_API MaybeStackVector<units::UnitPreferenceMetadata, 8>;
+template class U_I18N_API MaybeStackArray<units::UnitPreference*, 8>;
+template class U_I18N_API MemoryPool<units::UnitPreference, 8>;
+template class U_I18N_API MaybeStackVector<units::UnitPreference, 8>;
+#endif
+
+namespace units {
+
 /**
  * Unit Preferences information for various locales and usages.
  */
@@ -189,6 +224,6 @@
 } // namespace units
 U_NAMESPACE_END
 
-#endif //__GETUNITSDATA_H__
+#endif //__UNITS_DATA_H__
 
 #endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/unitsrouter.cpp b/icu4c/source/i18n/units_router.cpp
similarity index 87%
rename from icu4c/source/i18n/unitsrouter.cpp
rename to icu4c/source/i18n/units_router.cpp
index 7381d55..759ae2b 100644
--- a/icu4c/source/i18n/unitsrouter.cpp
+++ b/icu4c/source/i18n/units_router.cpp
@@ -12,8 +12,8 @@
 #include "number_decimalquantity.h"
 #include "resource.h"
 #include "unicode/measure.h"
-#include "unitsdata.h"
-#include "unitsrouter.h"
+#include "units_data.h"
+#include "units_router.h"
 
 U_NAMESPACE_BEGIN
 namespace units {
@@ -70,19 +70,19 @@
 RouteResult UnitsRouter::route(double quantity, UErrorCode &status) const {
     for (int i = 0, n = converterPreferences_.length(); i < n; i++) {
         const auto &converterPreference = *converterPreferences_[i];
-
-        if (converterPreference.converter.greaterThanOrEqual(quantity, converterPreference.limit)) {
-            return RouteResult(converterPreference.converter.convert(quantity, status), //
-                               converterPreference.precision                            //
-            );
+        if (converterPreference.converter.greaterThanOrEqual(quantity * (1 + DBL_EPSILON),
+                                                             converterPreference.limit)) {
+            return RouteResult(converterPreference.converter.convert(quantity, status),
+                               converterPreference.precision,
+                               converterPreference.targetUnit.copy(status));
         }
     }
 
     // In case of the `quantity` does not fit in any converter limit, use the last converter.
     const auto &lastConverterPreference = (*converterPreferences_[converterPreferences_.length() - 1]);
-    return RouteResult(lastConverterPreference.converter.convert(quantity, status), //
-                       lastConverterPreference.precision                            //
-    );
+    return RouteResult(lastConverterPreference.converter.convert(quantity, status),
+                       lastConverterPreference.precision,
+                       lastConverterPreference.targetUnit.copy(status));
 }
 
 const MaybeStackVector<MeasureUnit> *UnitsRouter::getOutputUnits() const {
diff --git a/icu4c/source/i18n/unitsrouter.h b/icu4c/source/i18n/units_router.h
similarity index 70%
rename from icu4c/source/i18n/unitsrouter.h
rename to icu4c/source/i18n/units_router.h
index 6828466..e6b74aa 100644
--- a/icu4c/source/i18n/unitsrouter.h
+++ b/icu4c/source/i18n/units_router.h
@@ -4,18 +4,18 @@
 #include "unicode/utypes.h"
 
 #if !UCONFIG_NO_FORMATTING
-#ifndef __UNITSROUTER_H__
-#define __UNITSROUTER_H__
+#ifndef __UNITS_ROUTER_H__
+#define __UNITS_ROUTER_H__
 
 #include <limits>
 
 #include "cmemory.h"
-#include "complexunitsconverter.h"
 #include "measunit_impl.h"
 #include "unicode/measunit.h"
 #include "unicode/stringpiece.h"
 #include "unicode/uobject.h"
-#include "unitsdata.h"
+#include "units_complexconverter.h"
+#include "units_data.h"
 
 U_NAMESPACE_BEGIN
 
@@ -25,11 +25,25 @@
 namespace units {
 
 struct RouteResult : UMemory {
+    // A list of measures: a single measure for single units, multiple measures
+    // for mixed units.
+    //
+    // TODO(icu-units/icu#21): figure out the right mixed unit API.
     MaybeStackVector<Measure> measures;
+
+    // A skeleton string starting with a precision-increment.
+    //
+    // TODO(hugovdm): generalise? or narrow down to only a precision-increment?
+    // or document that other skeleton elements are ignored?
     UnicodeString precision;
 
-    RouteResult(MaybeStackVector<Measure> measures, UnicodeString precision)
-        : measures(std::move(measures)), precision(std::move(precision)) {}
+    // The output unit for this RouteResult. This may be a MIXED unit - for
+    // example: "yard-and-foot-and-inch", for which `measures` will have three
+    // elements.
+    MeasureUnitImpl outputUnit;
+
+    RouteResult(MaybeStackVector<Measure> measures, UnicodeString precision, MeasureUnitImpl outputUnit)
+        : measures(std::move(measures)), precision(std::move(precision)), outputUnit(std::move(outputUnit)) {}
 };
 
 /**
@@ -46,6 +60,10 @@
     double limit;
     UnicodeString precision;
 
+    // The output unit for this ConverterPreference. This may be a MIXED unit -
+    // for example: "yard-and-foot-and-inch".
+    MeasureUnitImpl targetUnit;
+
     // In case there is no limit, the limit will be -inf.
     ConverterPreference(const MeasureUnitImpl &source, const MeasureUnitImpl &complexTarget,
                         UnicodeString precision, const ConversionRates &ratesInfo, UErrorCode &status)
@@ -56,9 +74,25 @@
                         double limit, UnicodeString precision, const ConversionRates &ratesInfo,
                         UErrorCode &status)
         : converter(source, complexTarget, ratesInfo, status), limit(limit),
-          precision(std::move(precision)) {}
+          precision(std::move(precision)), targetUnit(complexTarget.copy(status)) {}
 };
 
+} // namespace units
+
+// Export explicit template instantiations of MaybeStackArray, MemoryPool and
+// MaybeStackVector. This is required when building DLLs for Windows. (See
+// datefmt.h, collationiterator.h, erarules.h and others for similar examples.)
+//
+// 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::ConverterPreference*, 8>;
+template class U_I18N_API MemoryPool<units::ConverterPreference, 8>;
+template class U_I18N_API MaybeStackVector<units::ConverterPreference, 8>;
+#endif
+
+namespace units {
+
 /**
  * `UnitsRouter` responsible for converting from a single unit (such as `meter` or `meter-per-second`) to
  * one of the complex units based on the limits.
@@ -114,6 +148,6 @@
 } // namespace units
 U_NAMESPACE_END
 
-#endif //__UNITSROUTER_H__
+#endif //__UNITS_ROUTER_H__
 
 #endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/test/depstest/dependencies.txt b/icu4c/source/test/depstest/dependencies.txt
index f746aab..bee3766 100644
--- a/icu4c/source/test/depstest/dependencies.txt
+++ b/icu4c/source/test/depstest/dependencies.txt
@@ -869,7 +869,8 @@
     dayperiodrules
     listformatter
     formatting formattable_cnv regex regex_cnv translit
-    double_conversion number_representation number_output numberformatter number_skeletons numberparser
+    double_conversion number_representation number_output numberformatter
+    number_skeletons number_usageprefs numberparser
     units_extra unitsformatter
     universal_time_scale
     uclean_i18n
@@ -976,11 +977,9 @@
     standardplural.o plurrule.o
   deps
     # FormattedNumber internals:
-    number_representation format formatted_value_sbimpl
+    number_representation format formatted_value_sbimpl units
     # PluralRules internals:
     unifiedcache
-    # Unit Formatting
-    units
 
 group: numberformatter
     # ICU 60+ NumberFormatter API
@@ -989,17 +988,43 @@
     number_decimfmtprops.o
     number_fluent.o number_formatimpl.o
     number_grouping.o number_integerwidth.o number_longnames.o
-    number_mapper.o number_modifiers.o number_multiplier.o
+    number_mapper.o number_modifiers.o
     number_notation.o number_padding.o
-    number_patternmodifier.o number_patternstring.o number_rounding.o
-    number_scientific.o number_usageprefs.o
-    currpinf.o dcfmtsym.o numsys.o
+    number_patternmodifier.o number_patternstring.o
+    number_scientific.o
+    currpinf.o
     numrange_fluent.o numrange_impl.o
   deps
     decnumber double_conversion formattable units unitsformatter
-    number_representation number_output
+    listformatter number_representation number_output
+    numsys
+    number_usageprefs
+    number_rounding
+    number_symbolswrapper
     uclean_i18n common
 
+group: numsys
+    dcfmtsym.o
+    numsys.o
+  deps
+    currency
+    resourcebundle
+    uclean_i18n
+
+group: number_usageprefs
+    number_multiplier.o
+    number_usageprefs.o
+  deps
+    number_rounding
+    number_symbolswrapper
+    unitsformatter
+
+group: number_rounding
+    number_rounding.o
+  deps
+    currency
+    number_representation
+
 group: number_skeletons
     # Number skeleton support; separated from numberformatter
     number_skeletons.o number_capi.o number_asformat.o numrange_capi.o
@@ -1007,6 +1032,12 @@
     numberformatter
     units_extra
 
+group: number_symbolswrapper
+    number_symbolswrapper.o
+  deps
+    platform
+    numsys
+
 group: numberparser
     numparse_affixes.o numparse_compositions.o numparse_currency.o
     numparse_decimal.o numparse_impl.o numparse_parsednumber.o
@@ -1076,7 +1107,7 @@
     stringenumeration errorcode
 
 group: unitsformatter
-    unitsdata.o unitconverter.o complexunitsconverter.o unitsrouter.o
+    units_data.o units_converter.o units_complexconverter.o units_router.o
   deps
     resourcebundle units_extra double_conversion number_representation formattable sort
 
diff --git a/icu4c/source/test/intltest/Makefile.in b/icu4c/source/test/intltest/Makefile.in
index cb356c4..13d3ea8 100644
--- a/icu4c/source/test/intltest/Makefile.in
+++ b/icu4c/source/test/intltest/Makefile.in
@@ -69,7 +69,7 @@
 numbertest_parse.o numbertest_doubleconversion.o numbertest_skeletons.o \
 static_unisets_test.o numfmtdatadriventest.o numbertest_range.o erarulestest.o \
 formattedvaluetest.o formatted_string_builder_test.o numbertest_permutation.o \
-unitsdatatest.o unitstest.o unitsroutertest.o
+units_data_test.o units_router_test.o units_test.o
 
 DEPS = $(OBJECTS:.o=.d)
 
diff --git a/icu4c/source/test/intltest/intltest.vcxproj b/icu4c/source/test/intltest/intltest.vcxproj
index e6cee37..319c3ab 100644
--- a/icu4c/source/test/intltest/intltest.vcxproj
+++ b/icu4c/source/test/intltest/intltest.vcxproj
@@ -285,9 +285,9 @@
     <ClCompile Include="formattedvaluetest.cpp" />
     <ClCompile Include="localebuildertest.cpp" />
     <ClCompile Include="localematchertest.cpp" />
-    <ClCompile Include="unitsdatatest.cpp" />
-    <ClCompile Include="unitstest.cpp" />
-    <ClCompile Include="unitsroutertest.cpp" />
+    <ClCompile Include="units_data_test.cpp" />
+    <ClCompile Include="units_router_test.cpp" />
+    <ClCompile Include="units_test.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="colldata.h" />
diff --git a/icu4c/source/test/intltest/intltest.vcxproj.filters b/icu4c/source/test/intltest/intltest.vcxproj.filters
index bba4e92..b706980 100644
--- a/icu4c/source/test/intltest/intltest.vcxproj.filters
+++ b/icu4c/source/test/intltest/intltest.vcxproj.filters
@@ -550,13 +550,13 @@
     <ClCompile Include="localematchertest.cpp">
       <Filter>locales &amp; resources</Filter>
     </ClCompile>
-    <ClCompile Include="unitsdatatest.cpp">
+    <ClCompile Include="units_data_test.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
-    <ClCompile Include="unitstest.cpp">
+    <ClCompile Include="units_router_test.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
-    <ClCompile Include="unitsroutertest.cpp">
+    <ClCompile Include="units_test.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
   </ItemGroup>
diff --git a/icu4c/source/test/intltest/measfmttest.cpp b/icu4c/source/test/intltest/measfmttest.cpp
index 03c5fa8..938163e 100644
--- a/icu4c/source/test/intltest/measfmttest.cpp
+++ b/icu4c/source/test/intltest/measfmttest.cpp
@@ -82,6 +82,7 @@
     void TestNumericTimeSomeSpecialFormats();
     void TestIdentifiers();
     void TestInvalidIdentifiers();
+    void TestParseToBuiltIn();
     void TestKilogramIdentifier();
     void TestCompoundUnitOperations();
     void TestDimensionlessBehaviour();
@@ -209,6 +210,7 @@
     TESTCASE_AUTO(TestNumericTimeSomeSpecialFormats);
     TESTCASE_AUTO(TestIdentifiers);
     TESTCASE_AUTO(TestInvalidIdentifiers);
+    TESTCASE_AUTO(TestParseToBuiltIn);
     TESTCASE_AUTO(TestKilogramIdentifier);
     TESTCASE_AUTO(TestCompoundUnitOperations);
     TESTCASE_AUTO(TestDimensionlessBehaviour);
@@ -3514,11 +3516,23 @@
     // and falls back to fr for the "other" form.
     IcuTestErrorCode errorCode(*this, "TestIndividualPluralFallback");
     MeasureFormat mf("fr_CA", UMEASFMT_WIDTH_SHORT, errorCode);
+    if (errorCode.errIfFailureAndReset("MeasureFormat mf(...) failed.")) {
+        return;
+    }
     LocalPointer<Measure> twoDeg(
         new Measure(2.0, MeasureUnit::createGenericTemperature(errorCode), errorCode), errorCode);
+    if (errorCode.errIfFailureAndReset("Creating twoDeg failed.")) {
+        return;
+    }
     UnicodeString expected = UNICODE_STRING_SIMPLE("2\\u00B0").unescape();
     UnicodeString actual;
-    assertEquals("2 deg temp in fr_CA", expected, mf.format(twoDeg.orphan(), actual, errorCode), TRUE);
+    // Formattable adopts the pointer
+    mf.format(Formattable(twoDeg.orphan()), actual, errorCode);
+    if (errorCode.errIfFailureAndReset("mf.format(...) failed.")) {
+        return;
+    }
+    assertEquals("2 deg temp in fr_CA", expected, actual, TRUE);
+    errorCode.errIfFailureAndReset("mf.format failed");
 }
 
 void MeasureFormatTest::Test20332_PersonUnits() {
@@ -3705,6 +3719,33 @@
     }
 }
 
+void MeasureFormatTest::TestParseToBuiltIn() {
+    IcuTestErrorCode status(*this, "TestParseToBuiltIn()");
+    const struct TestCase {
+        const char *identifier;
+        MeasureUnit expectedBuiltIn;
+    } cases[] = {
+        {"meter-per-second-per-second", MeasureUnit::getMeterPerSecondSquared()},
+        {"meter-per-second-second", MeasureUnit::getMeterPerSecondSquared()},
+        {"centimeter-centimeter", MeasureUnit::getSquareCentimeter()},
+        {"square-foot", MeasureUnit::getSquareFoot()},
+        {"pow2-inch", MeasureUnit::getSquareInch()},
+        {"milligram-per-deciliter", MeasureUnit::getMilligramPerDeciliter()},
+        {"pound-force-per-pow2-inch", MeasureUnit::getPoundPerSquareInch()},
+        {"yard-pow2-yard", MeasureUnit::getCubicYard()},
+        {"square-yard-yard", MeasureUnit::getCubicYard()},
+    };
+
+    for (auto &cas : cases) {
+        MeasureUnit fromIdent = MeasureUnit::forIdentifier(cas.identifier, status);
+        status.assertSuccess();
+        assertEquals("forIdentifier returns a normal built-in unit when it exists",
+                     cas.expectedBuiltIn.getOffset(), fromIdent.getOffset());
+        assertEquals("type", cas.expectedBuiltIn.getType(), fromIdent.getType());
+        assertEquals("subType", cas.expectedBuiltIn.getSubtype(), fromIdent.getSubtype());
+    }
+}
+
 // Kilogram is a "base unit", although it's also "gram" with a kilo- prefix.
 // This tests that it is handled in the preferred manner.
 void MeasureFormatTest::TestKilogramIdentifier() {
diff --git a/icu4c/source/test/intltest/numbertest.h b/icu4c/source/test/intltest/numbertest.h
index c96c329..4bae2c1 100644
--- a/icu4c/source/test/intltest/numbertest.h
+++ b/icu4c/source/test/intltest/numbertest.h
@@ -55,6 +55,8 @@
     void unitMeasure();
     void unitCompoundMeasure();
     void unitUsage();
+    void unitUsageErrorCodes();
+    void unitUsageSkeletons();
     void unitCurrency();
     void unitPercent();
     void percentParity();
@@ -85,6 +87,7 @@
     void localPointerCAPI();
     void toObject();
     void toDecimalNumber();
+    void microPropsInternals();
 
     void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0);
 
diff --git a/icu4c/source/test/intltest/numbertest_api.cpp b/icu4c/source/test/intltest/numbertest_api.cpp
index cb30123..cce8ddf 100644
--- a/icu4c/source/test/intltest/numbertest_api.cpp
+++ b/icu4c/source/test/intltest/numbertest_api.cpp
@@ -11,12 +11,14 @@
 #include <memory>
 #include "unicode/unum.h"
 #include "unicode/numberformatter.h"
+#include "unicode/testlog.h"
+#include "unicode/utypes.h"
 #include "number_asformat.h"
 #include "number_types.h"
 #include "number_utils.h"
-#include "numbertest.h"
-#include "unicode/utypes.h"
 #include "number_utypes.h"
+#include "number_microprops.h"
+#include "numbertest.h"
 
 using number::impl::UFormattedNumberData;
 
@@ -76,6 +78,8 @@
         TESTCASE_AUTO(unitMeasure);
         TESTCASE_AUTO(unitCompoundMeasure);
         TESTCASE_AUTO(unitUsage);
+        TESTCASE_AUTO(unitUsageErrorCodes);
+        TESTCASE_AUTO(unitUsageSkeletons);
         TESTCASE_AUTO(unitCurrency);
         TESTCASE_AUTO(unitPercent);
         if (!quick) {
@@ -113,6 +117,7 @@
         TESTCASE_AUTO(localPointerCAPI);
         TESTCASE_AUTO(toObject);
         TESTCASE_AUTO(toDecimalNumber);
+        TESTCASE_AUTO(microPropsInternals);
     TESTCASE_AUTO_END;
 }
 
@@ -520,6 +525,8 @@
 }
 
 void NumberFormatterApiTest::unitMeasure() {
+    IcuTestErrorCode status(*this, "unitMeasure()");
+
     assertFormatDescending(
             u"Meters Short and unit() method",
             u"measure-unit/length-meter",
@@ -686,82 +693,86 @@
             Locale("es-MX"),
             5,
             u"5 a\u00F1os");
-}
 
-void NumberFormatterApiTest::unitUsage() {
-    UnlocalizedNumberFormatter unloc_formatter =
-        NumberFormatter::with().usage("road").unit(MeasureUnit::getMeter());
-
-    IcuTestErrorCode status(*this, "unitUsage()");
-
-    LocalizedNumberFormatter formatter = unloc_formatter.locale("en-ZA");
-    FormattedNumber formattedNum = formatter.formatDouble(300, status);
-    assertTrue(UnicodeString("unitUsage() en-ZA road, got outputUnit: \"") +
-                   formattedNum.getOutputUnit(status).getIdentifier() + "\"",
-               MeasureUnit::getMeter() == formattedNum.getOutputUnit(status));
-    assertEquals("unitUsage() en-ZA road", "300 m", formattedNum.toString(status));
-    assertFormatDescendingBig(
-            u"unitUsage() en-ZA road",
-            u"measure-unit/length-meter usage/road",
-            u"unit/meter usage/road",
-            unloc_formatter,
-            Locale("en-ZA"),
-            u"87\u00A0650 km",
-            u"8\u00A0765 km",
-            u"877 km",
-            u"88 km",
-            u"8,8 km",
-            u"877 m",
-            u"88 m",
-            u"8,8 m",
-            u"0 m");
-
-    formatter = unloc_formatter.locale("en-GB");
-    formattedNum = formatter.formatDouble(300, status);
-    assertTrue(UnicodeString("unitUsage() en-GB road, got outputUnit: \"") +
-                   formattedNum.getOutputUnit(status).getIdentifier() + "\"",
-               MeasureUnit::getYard() == formattedNum.getOutputUnit(status));
-    assertEquals("unitUsage() en-GB road", "328 yd", formattedNum.toString(status));
-    assertFormatDescendingBig(
-            u"unitUsage() en-GB road",
-            u"measure-unit/length-meter usage/road",
-            u"unit/meter usage/road",
-            unloc_formatter,
-            Locale("en-GB"),
-            u"54,463 mi",
-            u"5,446 mi",
-            u"545 mi",
-            u"54 mi",
-            u"5.4 mi",
-            u"0.54 mi",
-            u"96 yd",
-            u"9.6 yd",
-            u"0 yd");
-
-    formatter = unloc_formatter.locale("en-US");
-    formattedNum = formatter.formatDouble(300, status);
-    assertTrue(UnicodeString("unitUsage() en-US road, got outputUnit: \"") +
-                   formattedNum.getOutputUnit(status).getIdentifier() + "\"",
-               MeasureUnit::getFoot() == formattedNum.getOutputUnit(status));
-    assertEquals("unitUsage() en-US road", "984 ft", formattedNum.toString(status));
-    assertFormatDescendingBig(
-            u"unitUsage() en-US road",
-            u"measure-unit/length-meter usage/road",
-            u"unit/meter usage/road",
-            unloc_formatter,
+    // TODO(icu-units#35): skeleton generation.
+    assertFormatSingle(
+            u"Mixed unit",
+            nullptr,
+            u"unit/yard-and-foot-and-inch",
+            NumberFormatter::with()
+                .unit(MeasureUnit::forIdentifier("yard-and-foot-and-inch", status)),
             Locale("en-US"),
-            u"54,463 mi",
-            u"5,446 mi",
-            u"545 mi",
-            u"54 mi",
-            u"5.4 mi",
-            u"0.54 mi",
-            u"288 ft",
-            u"29 ft",
-            u"0 ft");
+            3.65,
+            "3 yd, 1 ft, 11.4 in");
+
+    // TODO(icu-units#35): skeleton generation.
+    assertFormatSingle(
+            u"Mixed unit, Scientific",
+            nullptr,
+            u"unit/yard-and-foot-and-inch E0",
+            NumberFormatter::with()
+                .unit(MeasureUnit::forIdentifier("yard-and-foot-and-inch", status))
+                .notation(Notation::scientific()),
+            Locale("en-US"),
+            3.65,
+            "3 yd, 1 ft, 1.14E1 in");
+
+    // TODO(icu-units#35): skeleton generation.
+    assertFormatSingle(
+            u"Mixed Unit (Narrow Version)",
+            nullptr,
+            u"unit/metric-ton-and-kilogram-and-gram unit-width-narrow",
+            NumberFormatter::with()
+                .unit(MeasureUnit::forIdentifier("metric-ton-and-kilogram-and-gram", status))
+                .unitWidth(UNUM_UNIT_WIDTH_NARROW),
+            Locale("en-US"),
+            4.28571,
+            u"4t 285kg 710g");
+
+    // TODO(icu-units#35): skeleton generation.
+    assertFormatSingle(
+            u"Mixed Unit (Short Version)",
+            nullptr,
+            u"unit/metric-ton-and-kilogram-and-gram unit-width-short",
+            NumberFormatter::with()
+                .unit(MeasureUnit::forIdentifier("metric-ton-and-kilogram-and-gram", status))
+                .unitWidth(UNUM_UNIT_WIDTH_SHORT),
+            Locale("en-US"),
+            4.28571,
+            u"4 t, 285 kg, 710 g");
+
+    // TODO(icu-units#35): skeleton generation.
+    assertFormatSingle(
+            u"Mixed Unit (Full Name Version)",
+            nullptr,
+            u"unit/metric-ton-and-kilogram-and-gram unit-width-full-name",
+            NumberFormatter::with()
+                .unit(MeasureUnit::forIdentifier("metric-ton-and-kilogram-and-gram", status))
+                .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
+            Locale("en-US"),
+            4.28571,
+            u"4 metric tons, 285 kilograms, 710 grams");
+
+//     // TODO(icu-units#73): deal with this "1 foot 12 inches" problem.
+//     // At the time of writing, this test would pass, but is commented out
+//     // because it reflects undesired behaviour:
+//     assertFormatSingle(
+//             u"Demonstrating the \"1 foot 12 inches\" problem",
+//             nullptr,
+//             u"unit/foot-and-inch",
+//             NumberFormatter::with()
+//                 .unit(MeasureUnit::forIdentifier("foot-and-inch", status))
+//                 .precision(Precision::maxSignificantDigits(4))
+//                 .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
+//             Locale("en-US"),
+//             1.9999,
+//             // This is undesireable but current behaviour:
+//             u"1 foot, 12 inches");
 }
 
 void NumberFormatterApiTest::unitCompoundMeasure() {
+    IcuTestErrorCode status(*this, "unitCompoundMeasure()");
+
     assertFormatDescending(
             u"Meters Per Second Short (unit that simplifies) and perUnit method",
             u"measure-unit/length-meter per-measure-unit/duration-second",
@@ -778,6 +789,17 @@
             u"0.008765 m/s",
             u"0 m/s");
 
+    // TODO(icu-units#35): does not normalize as desired: while "unit/*" does
+    // get split into unit/perUnit, ".unit(*)" and "measure-unit/*" don't:
+    assertFormatSingle(
+        u"Built-in unit, meter-per-second",
+        u"measure-unit/speed-meter-per-second",
+        u"~unit/meter-per-second",
+        NumberFormatter::with().unit(MeasureUnit::getMeterPerSecond()),
+        Locale("en-GB"),
+        2.4,
+        u"2.4 m/s");
+
     assertFormatDescending(
             u"Pounds Per Square Mile Short (secondary unit has per-format) and adoptPerUnit method",
             u"measure-unit/mass-pound per-measure-unit/area-square-mile",
@@ -826,6 +848,427 @@
     //         u"0.08765 J/fur",
     //         u"0.008765 J/fur",
     //         u"0 J/fur");
+
+    // TODO(icu-units#59): THIS UNIT TEST DEMONSTRATES UNDESIREABLE BEHAVIOUR!
+    // When specifying built-in types, one can give both a unit and a perUnit.
+    // Resolving to a built-in unit does not always work.
+    //
+    // (Unit-testing philosophy: do we leave this enabled to demonstrate current
+    // behaviour, and changing behaviour in the future? Or comment it out to
+    // avoid asserting this is "correct"?)
+    assertFormatSingle(
+            u"DEMONSTRATING BAD BEHAVIOUR, TODO(icu-units#59)",
+            u"measure-unit/speed-meter-per-second per-measure-unit/duration-second",
+            u"measure-unit/speed-meter-per-second per-measure-unit/duration-second",
+            NumberFormatter::with()
+                .unit(MeasureUnit::getMeterPerSecond())
+                .perUnit(MeasureUnit::getSecond()),
+            Locale("en-GB"),
+            2.4,
+            "2.4 m/s/s");
+
+    // Testing the rejection of invalid specifications
+
+    // If .unit() is not given a built-in type, .perUnit() is not allowed
+    // (because .unit is now flexible enough to handle compound units,
+    // .perUnit() is supported for backward compatibility).
+    LocalizedNumberFormatter nf = NumberFormatter::with()
+             .unit(MeasureUnit::forIdentifier("furlong-pascal", status))
+             .perUnit(METER)
+             .locale("en-GB");
+    status.assertSuccess(); // Error is only returned once we try to format.
+    FormattedNumber num = nf.formatDouble(2.4, status);
+    if (!status.expectErrorAndReset(U_UNSUPPORTED_ERROR)) {
+        errln(UnicodeString("Expected failure, got: \"") +
+              nf.formatDouble(2.4, status).toString(status) + "\".");
+        status.assertSuccess();
+    }
+
+    // .perUnit() may only be passed a built-in type, "square-second" is not a
+    // built-in type.
+    nf = NumberFormatter::with()
+             .unit(MeasureUnit::getMeter())
+             .perUnit(MeasureUnit::forIdentifier("square-second", status))
+             .locale("en-GB");
+    status.assertSuccess(); // Error is only returned once we try to format.
+    num = nf.formatDouble(2.4, status);
+    if (!status.expectErrorAndReset(U_UNSUPPORTED_ERROR)) {
+        errln(UnicodeString("Expected failure, got: \"") +
+              nf.formatDouble(2.4, status).toString(status) + "\".");
+        status.assertSuccess();
+    }
+}
+
+void NumberFormatterApiTest::unitUsage() {
+    IcuTestErrorCode status(*this, "unitUsage()");
+    UnlocalizedNumberFormatter unloc_formatter;
+    LocalizedNumberFormatter formatter;
+    FormattedNumber formattedNum;
+    UnicodeString uTestCase;
+
+    unloc_formatter = NumberFormatter::with().usage("road").unit(MeasureUnit::getMeter());
+
+    uTestCase = u"unitUsage() en-ZA road";
+    formatter = unloc_formatter.locale("en-ZA");
+    formattedNum = formatter.formatDouble(321, status);
+    status.errIfFailureAndReset("unitUsage() en-ZA road formatDouble");
+    assertTrue(
+            uTestCase + u", got outputUnit: \"" + formattedNum.getOutputUnit(status).getIdentifier() + "\"",
+            MeasureUnit::getMeter() == formattedNum.getOutputUnit(status));
+    assertEquals(uTestCase, "300 m", formattedNum.toString(status));
+    {
+        static const UFieldPosition expectedFieldPositions[] = {
+                {UNUM_INTEGER_FIELD, 0, 3},
+                {UNUM_MEASURE_UNIT_FIELD, 4, 5}};
+        assertNumberFieldPositions(
+                (uTestCase + u" field positions").getTerminatedBuffer(),
+                formattedNum,
+                expectedFieldPositions,
+                UPRV_LENGTHOF(expectedFieldPositions));
+    }
+    assertFormatDescendingBig(
+            uTestCase.getTerminatedBuffer(),
+            u"measure-unit/length-meter usage/road",
+            u"unit/meter usage/road",
+            unloc_formatter,
+            Locale("en-ZA"),
+            u"87\u00A0650 km",
+            u"8\u00A0765 km",
+            u"876 km", // 6.5 rounds down, 7.5 rounds up.
+            u"88 km",
+            u"8,8 km",
+            u"900 m",
+            u"90 m",
+            u"10 m",
+            u"0 m");
+
+    uTestCase = u"unitUsage() en-GB road";
+    formatter = unloc_formatter.locale("en-GB");
+    formattedNum = formatter.formatDouble(321, status);
+    status.errIfFailureAndReset("unitUsage() en-GB road, formatDouble(...)");
+    assertTrue(
+            uTestCase + u", got outputUnit: \"" + formattedNum.getOutputUnit(status).getIdentifier() + "\"",
+            MeasureUnit::getYard() == formattedNum.getOutputUnit(status));
+    status.errIfFailureAndReset("unitUsage() en-GB road, getOutputUnit(...)");
+    assertEquals(uTestCase, "350 yd", formattedNum.toString(status));
+    status.errIfFailureAndReset("unitUsage() en-GB road, toString(...)");
+    {
+        static const UFieldPosition expectedFieldPositions[] = {
+                {UNUM_INTEGER_FIELD, 0, 3},
+                {UNUM_MEASURE_UNIT_FIELD, 4, 6}};
+        assertNumberFieldPositions(
+                (uTestCase + u" field positions").getTerminatedBuffer(),
+                formattedNum,
+                expectedFieldPositions,
+                UPRV_LENGTHOF(expectedFieldPositions));
+    }
+    assertFormatDescendingBig(
+            uTestCase.getTerminatedBuffer(),
+            u"measure-unit/length-meter usage/road",
+            u"unit/meter usage/road",
+            unloc_formatter,
+            Locale("en-GB"),
+            u"54,463 mi",
+            u"5,446 mi",
+            u"545 mi",
+            u"54 mi",
+            u"5.4 mi",
+            u"0.54 mi",
+            u"96 yd",
+            u"9.6 yd",
+            u"0 yd");
+
+    uTestCase = u"unitUsage() en-US road";
+    formatter = unloc_formatter.locale("en-US");
+    formattedNum = formatter.formatDouble(321, status);
+    status.errIfFailureAndReset("unitUsage() en-US road, formatDouble(...)");
+    assertTrue(
+            uTestCase + u", got outputUnit: \"" + formattedNum.getOutputUnit(status).getIdentifier() + "\"",
+            MeasureUnit::getFoot() == formattedNum.getOutputUnit(status));
+    status.errIfFailureAndReset("unitUsage() en-US road, getOutputUnit(...)");
+    assertEquals(uTestCase, "1,050 ft", formattedNum.toString(status));
+    status.errIfFailureAndReset("unitUsage() en-US road, toString(...)");
+    {
+        static const UFieldPosition expectedFieldPositions[] = {
+                {UNUM_GROUPING_SEPARATOR_FIELD, 1, 2},
+                {UNUM_INTEGER_FIELD, 0, 5},
+                {UNUM_MEASURE_UNIT_FIELD, 6, 8}};
+        assertNumberFieldPositions(
+                (uTestCase + u" field positions").getTerminatedBuffer(),
+                formattedNum,
+                expectedFieldPositions,
+                UPRV_LENGTHOF(expectedFieldPositions));
+    }
+    assertFormatDescendingBig(
+            uTestCase.getTerminatedBuffer(),
+            u"measure-unit/length-meter usage/road",
+            u"unit/meter usage/road",
+            unloc_formatter,
+            Locale("en-US"),
+            u"54,463 mi",
+            u"5,446 mi",
+            u"545 mi",
+            u"54 mi",
+            u"5.4 mi",
+            u"0.54 mi",
+            u"300 ft",
+            u"30 ft",
+            u"0 ft");
+
+    unloc_formatter = NumberFormatter::with().usage("person").unit(MeasureUnit::getKilogram());
+    uTestCase = u"unitUsage() en-GB person";
+    formatter = unloc_formatter.locale("en-GB");
+    formattedNum = formatter.formatDouble(80, status);
+    status.errIfFailureAndReset("unitUsage() en-GB person formatDouble");
+    assertTrue(
+        uTestCase + ", got outputUnit: \"" + formattedNum.getOutputUnit(status).getIdentifier() + "\"",
+        MeasureUnit::forIdentifier("stone-and-pound", status) == formattedNum.getOutputUnit(status));
+    status.errIfFailureAndReset("unitUsage() en-GB person - formattedNum.getOutputUnit(status)");
+    assertEquals(uTestCase, "12 st, 8.4 lb", formattedNum.toString(status));
+    status.errIfFailureAndReset("unitUsage() en-GB person, toString(...)");
+    {
+        static const UFieldPosition expectedFieldPositions[] = {
+                // // Desired output: TODO(icu-units#67)
+                // {UNUM_INTEGER_FIELD, 0, 2},
+                // {UNUM_MEASURE_UNIT_FIELD, 3, 5},
+                // {ULISTFMT_LITERAL_FIELD, 5, 6},
+                // {UNUM_INTEGER_FIELD, 7, 8},
+                // {UNUM_DECIMAL_SEPARATOR_FIELD, 8, 9},
+                // {UNUM_FRACTION_FIELD, 9, 10},
+                // {UNUM_MEASURE_UNIT_FIELD, 11, 13}};
+
+                // Current output: rather no fields than wrong fields
+                {UNUM_INTEGER_FIELD, 7, 8},
+                {UNUM_DECIMAL_SEPARATOR_FIELD, 8, 9},
+                {UNUM_FRACTION_FIELD, 9, 10},
+                };
+        assertNumberFieldPositions(
+                (uTestCase + u" field positions").getTerminatedBuffer(),
+                formattedNum,
+                expectedFieldPositions,
+                UPRV_LENGTHOF(expectedFieldPositions));
+    }
+    assertFormatDescending(
+            uTestCase.getTerminatedBuffer(),
+            u"measure-unit/mass-kilogram usage/person",
+            u"unit/kilogram usage/person",
+            unloc_formatter,
+            Locale("en-GB"),
+            u"13,802 st, 7.2 lb",
+            u"1,380 st, 3.5 lb",
+            u"138 st, 0.35 lb",
+            u"13 st, 11 lb",
+            u"1 st, 5.3 lb",
+            u"1 lb, 15 oz",
+            u"0 lb, 3.1 oz",
+            u"0 lb, 0.31 oz",
+            u"0 lb, 0 oz");
+
+   assertFormatDescending(
+            uTestCase.getTerminatedBuffer(),
+            u"usage/person unit-width-narrow measure-unit/mass-kilogram",
+            u"usage/person unit-width-narrow unit/kilogram",
+            unloc_formatter.unitWidth(UNUM_UNIT_WIDTH_NARROW),
+            Locale("en-GB"),
+            u"13,802st 7.2lb",
+            u"1,380st 3.5lb",
+            u"138st 0.35lb",
+            u"13st 11lb",
+            u"1st 5.3lb",
+            u"1lb 15oz",
+            u"0lb 3.1oz",
+            u"0lb 0.31oz",
+            u"0lb 0oz");
+
+   assertFormatDescending(
+            uTestCase.getTerminatedBuffer(),
+            u"usage/person unit-width-short measure-unit/mass-kilogram",
+            u"usage/person unit-width-short unit/kilogram",
+            unloc_formatter.unitWidth(UNUM_UNIT_WIDTH_SHORT),
+            Locale("en-GB"),
+            u"13,802 st, 7.2 lb",
+            u"1,380 st, 3.5 lb",
+            u"138 st, 0.35 lb",
+            u"13 st, 11 lb",
+            u"1 st, 5.3 lb",
+            u"1 lb, 15 oz",
+            u"0 lb, 3.1 oz",
+            u"0 lb, 0.31 oz",
+            u"0 lb, 0 oz");
+
+   assertFormatDescending(
+            uTestCase.getTerminatedBuffer(),
+            u"usage/person unit-width-full-name measure-unit/mass-kilogram",
+            u"usage/person unit-width-full-name unit/kilogram",
+            unloc_formatter.unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
+            Locale("en-GB"),
+            u"13,802 stone, 7.2 pounds",
+            u"1,380 stone, 3.5 pounds",
+            u"138 stone, 0.35 pounds",
+            u"13 stone, 11 pounds",
+            u"1 stone, 5.3 pounds",
+            u"1 pound, 15 ounces",
+            u"0 pounds, 3.1 ounces",
+            u"0 pounds, 0.31 ounces",
+            u"0 pounds, 0 ounces");
+
+    assertFormatDescendingBig(
+        u"Scientific notation with Usage: possible when using a reasonable Precision",
+        u"scientific @### usage/default measure-unit/area-square-meter unit-width-full-name",
+        u"scientific @### usage/default unit/square-meter unit-width-full-name",
+        NumberFormatter::with()
+            .unit(SQUARE_METER)
+            .usage("default")
+            .notation(Notation::scientific())
+            .precision(Precision::minMaxSignificantDigits(1, 4))
+            .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME),
+        Locale("en-ZA"),
+        u"8,765E1 square kilometres",
+        u"8,765E0 square kilometres",
+        u"8,765E1 hectares",
+        u"8,765E0 hectares",
+        u"8,765E3 square metres",
+        u"8,765E2 square metres",
+        u"8,765E1 square metres",
+        u"8,765E0 square metres",
+        u"0E0 square centimetres");
+}
+
+void NumberFormatterApiTest::unitUsageErrorCodes() {
+    IcuTestErrorCode status(*this, "unitUsageErrorCodes()");
+    UnlocalizedNumberFormatter unloc_formatter;
+
+    unloc_formatter = NumberFormatter::forSkeleton(u"unit/foobar", status);
+    // This gives an error, because foobar is an invalid unit:
+    status.expectErrorAndReset(U_NUMBER_SKELETON_SYNTAX_ERROR);
+
+    unloc_formatter = NumberFormatter::forSkeleton(u"usage/foobar", status);
+    // This does not give an error, because usage is not looked up yet.
+    status.errIfFailureAndReset("Expected behaviour: no immediate error for invalid usage");
+    unloc_formatter.locale("en-GB").formatInt(1, status);
+    // Lacking a unit results in a failure. The skeleton is "incomplete", but we
+    // support adding the unit via the fluent API, so it is not an error until
+    // we build the formatting pipeline itself.
+    status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR);
+    // Adding the unit as part of the fluent chain leads to success.
+    unloc_formatter.unit(MeasureUnit::getMeter()).locale("en-GB").formatInt(1, status);
+    status.assertSuccess();
+}
+
+// Tests for the "skeletons" field in unitPreferenceData, as well as precision
+// and notation overrides.
+void NumberFormatterApiTest::unitUsageSkeletons() {
+    IcuTestErrorCode status(*this, "unitUsageSkeletons()");
+
+    assertFormatSingle(
+            u"Default >300m road preference skeletons round to 50m",
+            u"usage/road measure-unit/length-meter",
+            u"usage/road unit/meter",
+            NumberFormatter::with().unit(METER).usage("road"),
+            Locale("en-ZA"),
+            321,
+            u"300 m");
+
+    assertFormatSingle(
+            u"Precision can be overridden: override takes precedence",
+            u"usage/road measure-unit/length-meter @#",
+            u"usage/road unit/meter @#",
+            NumberFormatter::with()
+                .unit(METER)
+                .usage("road")
+                .precision(Precision::maxSignificantDigits(2)),
+            Locale("en-ZA"),
+            321,
+            u"320 m");
+
+    assertFormatSingle(
+            u"Compact notation with Usage: bizarre, but possible (short)",
+            u"compact-short usage/road measure-unit/length-meter",
+            u"compact-short usage/road unit/meter",
+            NumberFormatter::with()
+               .unit(METER)
+               .usage("road")
+               .notation(Notation::compactShort()),
+            Locale("en-ZA"),
+            987654321,
+            u"988K km");
+
+    assertFormatSingle(
+            u"Compact notation with Usage: bizarre, but possible (short, precision override)",
+            u"compact-short usage/road measure-unit/length-meter @#",
+            u"compact-short usage/road unit/meter @#",
+            NumberFormatter::with()
+                .unit(METER)
+                .usage("road")
+                .notation(Notation::compactShort())
+                .precision(Precision::maxSignificantDigits(2)),
+            Locale("en-ZA"),
+            987654321,
+            u"990K km");
+
+    assertFormatSingle(
+            u"Compact notation with Usage: unusual but possible (long)",
+            u"compact-long usage/road measure-unit/length-meter @#",
+            u"compact-long usage/road unit/meter @#",
+            NumberFormatter::with()
+                .unit(METER)
+                .usage("road")
+                .notation(Notation::compactLong())
+                .precision(Precision::maxSignificantDigits(2)),
+            Locale("en-ZA"),
+            987654321,
+            u"990 thousand km");
+
+    assertFormatSingle(
+            u"Compact notation with Usage: unusual but possible (long, precision override)",
+            u"compact-long usage/road measure-unit/length-meter @#",
+            u"compact-long usage/road unit/meter @#",
+            NumberFormatter::with()
+                .unit(METER)
+                .usage("road")
+                .notation(Notation::compactLong())
+                .precision(Precision::maxSignificantDigits(2)),
+            Locale("en-ZA"),
+            987654321,
+            u"990 thousand km");
+
+    assertFormatSingle(
+            u"Scientific notation, not recommended, requires precision override for road",
+            u"scientific usage/road measure-unit/length-meter",
+            u"scientific usage/road unit/meter",
+            NumberFormatter::with().unit(METER).usage("road").notation(Notation::scientific()),
+            Locale("en-ZA"),
+            321.45,
+            // Rounding to the nearest "50" is not exponent-adjusted in scientific notation:
+            u"0E2 m");
+
+    assertFormatSingle(
+            u"Scientific notation with Usage: possible when using a reasonable Precision",
+            u"scientific usage/road measure-unit/length-meter @###",
+            u"scientific usage/road unit/meter @###",
+            NumberFormatter::with()
+                .unit(METER)
+                .usage("road")
+                .notation(Notation::scientific())
+                .precision(Precision::maxSignificantDigits(4)),
+            Locale("en-ZA"),
+            321.45, // 0.45 rounds down, 0.55 rounds up.
+            u"3,214E2 m");
+
+    assertFormatSingle(
+            u"Scientific notation with Usage: possible when using a reasonable Precision",
+            u"scientific usage/default measure-unit/length-astronomical-unit unit-width-full-name",
+            u"scientific usage/default unit/astronomical-unit unit-width-full-name",
+            NumberFormatter::with()
+                .unit(MeasureUnit::forIdentifier("astronomical-unit", status))
+                .usage("default")
+                .notation(Notation::scientific())
+                .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME),
+            Locale("en-ZA"),
+            1e20,
+            u"1,5E28 kilometres");
+
+    status.assertSuccess();
 }
 
 void NumberFormatterApiTest::unitCurrency() {
@@ -3604,6 +4047,33 @@
         "9.8765E+14", fn.toDecimalNumber<std::string>(status).c_str());
 }
 
+void NumberFormatterApiTest::microPropsInternals() {
+    // Verify copy construction and assignment operators.
+    int64_t testValues[2] = {4, 61};
+
+    MicroProps mp;
+    assertEquals("capacity", 2, mp.mixedMeasures.getCapacity());
+    mp.mixedMeasures[0] = testValues[0];
+    mp.mixedMeasures[1] = testValues[1];
+    MicroProps copyConstructed(mp);
+    MicroProps copyAssigned;
+    int64_t *resizeResult = mp.mixedMeasures.resize(4, 4);
+    assertTrue("Resize success", resizeResult != NULL);
+    copyAssigned = mp;
+
+    assertTrue("MicroProps success status", U_SUCCESS(mp.mixedMeasures.status));
+    assertTrue("Copy Constructed success status", U_SUCCESS(copyConstructed.mixedMeasures.status));
+    assertTrue("Copy Assigned success status", U_SUCCESS(copyAssigned.mixedMeasures.status));
+    assertEquals("Original values[0]", testValues[0], mp.mixedMeasures[0]);
+    assertEquals("Original values[1]", testValues[1], mp.mixedMeasures[1]);
+    assertEquals("Copy Constructed[0]", testValues[0], copyConstructed.mixedMeasures[0]);
+    assertEquals("Copy Constructed[1]", testValues[1], copyConstructed.mixedMeasures[1]);
+    assertEquals("Copy Assigned[0]", testValues[0], copyAssigned.mixedMeasures[0]);
+    assertEquals("Copy Assigned[1]", testValues[1], copyAssigned.mixedMeasures[1]);
+    assertEquals("Original capacity", 4, mp.mixedMeasures.getCapacity());
+    assertEquals("Copy Constructed capacity", 2, copyConstructed.mixedMeasures.getCapacity());
+    assertEquals("Copy Assigned capacity", 4, copyAssigned.mixedMeasures.getCapacity());
+}
 
 void NumberFormatterApiTest::assertFormatDescending(
         const char16_t* umessage,
diff --git a/icu4c/source/test/intltest/unitsdatatest.cpp b/icu4c/source/test/intltest/units_data_test.cpp
similarity index 99%
rename from icu4c/source/test/intltest/unitsdatatest.cpp
rename to icu4c/source/test/intltest/units_data_test.cpp
index 3ac36f7..1846451 100644
--- a/icu4c/source/test/intltest/unitsdatatest.cpp
+++ b/icu4c/source/test/intltest/units_data_test.cpp
@@ -5,7 +5,7 @@
 
 #if !UCONFIG_NO_FORMATTING
 
-#include "unitsdata.h"
+#include "units_data.h"
 #include "intltest.h"
 
 using namespace ::icu::units;
diff --git a/icu4c/source/test/intltest/unitsroutertest.cpp b/icu4c/source/test/intltest/units_router_test.cpp
similarity index 96%
rename from icu4c/source/test/intltest/unitsroutertest.cpp
rename to icu4c/source/test/intltest/units_router_test.cpp
index 8d2489e..d43e1c8 100644
--- a/icu4c/source/test/intltest/unitsroutertest.cpp
+++ b/icu4c/source/test/intltest/units_router_test.cpp
@@ -7,7 +7,7 @@
 
 #include "intltest.h"
 #include "unicode/unistr.h"
-#include "unitsrouter.h"
+#include "units_router.h"
 
 
 class UnitsRouterTest : public IntlTest {
diff --git a/icu4c/source/test/intltest/unitstest.cpp b/icu4c/source/test/intltest/units_test.cpp
similarity index 79%
rename from icu4c/source/test/intltest/unitstest.cpp
rename to icu4c/source/test/intltest/units_test.cpp
index 8309bed..8053f1d 100644
--- a/icu4c/source/test/intltest/unitstest.cpp
+++ b/icu4c/source/test/intltest/units_test.cpp
@@ -19,9 +19,10 @@
 #include "unicode/unistr.h"
 #include "unicode/unum.h"
 #include "unicode/ures.h"
-#include "unitconverter.h"
-#include "unitsdata.h"
-#include "unitsrouter.h"
+#include "units_complexconverter.h"
+#include "units_converter.h"
+#include "units_data.h"
+#include "units_router.h"
 #include "uparse.h"
 #include "uresimp.h"
 
@@ -44,6 +45,7 @@
     void testUnitConstantFreshness();
     void testConversionCapability();
     void testConversions();
+    void testComplexUnitsConverter();
     void testComplexUnitConverterSorting();
     void testPreferences();
     void testSiPrefixes();
@@ -62,6 +64,7 @@
     TESTCASE_AUTO(testUnitConstantFreshness);
     TESTCASE_AUTO(testConversionCapability);
     TESTCASE_AUTO(testConversions);
+    TESTCASE_AUTO(testComplexUnitsConverter);
     TESTCASE_AUTO(testComplexUnitConverterSorting);
     TESTCASE_AUTO(testPreferences);
     TESTCASE_AUTO(testSiPrefixes);
@@ -88,7 +91,7 @@
         addSingleFactorConstant(constant, 1, POSITIVE, factor, status);
         if (status.errDataIfFailureAndReset(
                 "addSingleFactorConstant(<%s>, ...).\n\n"
-                "If U_INVALID_FORMAT_ERROR, please check that \"icu4c/source/i18n/unitconverter.cpp\" "
+                "If U_INVALID_FORMAT_ERROR, please check that \"icu4c/source/i18n/units_converter.cpp\" "
                 "has all constants? Is \"%s\" a new constant?\n",
                 constant, constant)) {
             continue;
@@ -105,7 +108,7 @@
         }
         DecimalQuantity dqVal;
         UErrorCode parseStatus = U_ZERO_ERROR;
-        // TODO(units): unify with strToDouble() in unitconverter.cpp
+        // TODO(units): unify with strToDouble() in units_converter.cpp
         dqVal.setToDecNumber(val.toStringPiece(), parseStatus);
         if (!U_SUCCESS(parseStatus)) {
             // Not simple to parse, skip validating this constant's value. (We
@@ -294,19 +297,21 @@
 }
 
 /**
- * Trims whitespace (spaces only) off of the specified string.
+ * Trims whitespace off of the specified string.
  * @param field is two pointers pointing at the start and end of the string.
  * @return A StringPiece with initial and final space characters trimmed off.
  */
 StringPiece trimField(char *(&field)[2]) {
-    char *start = field[0];
-    while (start < field[1] && (start[0]) == ' ') {
-        start++;
+    const char *start = field[0];
+    start = u_skipWhitespace(start);
+    if (start >= field[1]) {
+        start = field[1];
     }
-    int32_t length = (int32_t)(field[1] - start);
-    while (length > 0 && (start[length - 1]) == ' ') {
-        length--;
+    const char *end = field[1];
+    while ((start < end) && U_IS_INV_WHITESPACE(*(end - 1))) {
+        end--;
     }
+    int32_t length = (int32_t)(end - start);
     return StringPiece(start, length);
 }
 
@@ -359,11 +364,13 @@
         return;
     }
 
+    CharString sourceIdent(x, status);
     MeasureUnitImpl sourceUnit = MeasureUnitImpl::forIdentifier(x, status);
     if (status.errIfFailureAndReset("forIdentifier(\"%.*s\")", x.length(), x.data())) {
         return;
     }
 
+    CharString targetIdent(y, status);
     MeasureUnitImpl targetUnit = MeasureUnitImpl::forIdentifier(y, status);
     if (status.errIfFailureAndReset("forIdentifier(\"%.*s\")", y.length(), y.data())) {
         return;
@@ -378,14 +385,14 @@
     // Convertibility:
     auto convertibility = extractConvertibility(sourceUnit, targetUnit, *ctx->conversionRates, status);
     if (status.errIfFailureAndReset("extractConvertibility(<%s>, <%s>, ...)",
-                                    sourceUnit.identifier.data(), targetUnit.identifier.data())) {
+                                    sourceIdent.data(), targetIdent.data())) {
         return;
     }
     CharString msg;
     msg.append("convertible: ", status)
-        .append(sourceUnit.identifier.data(), status)
+        .append(sourceIdent.data(), status)
         .append(" -> ", status)
-        .append(targetUnit.identifier.data(), status);
+        .append(targetIdent.data(), status);
     if (status.errIfFailureAndReset("msg construction")) {
         return;
     }
@@ -394,7 +401,7 @@
     // Conversion:
     UnitConverter converter(sourceUnit, targetUnit, *ctx->conversionRates, status);
     if (status.errIfFailureAndReset("constructor: UnitConverter(<%s>, <%s>, status)",
-                                    sourceUnit.identifier.data(), targetUnit.identifier.data())) {
+                                    sourceIdent.data(), targetIdent.data())) {
         return;
     }
     double got = converter.convert(1000);
@@ -405,7 +412,7 @@
 
 /**
  * Runs data-driven unit tests for unit conversion. It looks for the test cases
- * in source/test/testdata/units/unitsTest.txt, which originates in CLDR.
+ * in source/test/testdata/cldr/units/unitsTest.txt, which originates in CLDR.
  */
 void UnitsTest::testConversions() {
     const char *filename = "unitsTest.txt";
@@ -420,7 +427,7 @@
     }
 
     CharString path(sourceTestDataPath, errorCode);
-    path.appendPathPart("units", errorCode);
+    path.appendPathPart("cldr/units", errorCode);
     path.appendPathPart(filename, errorCode);
 
     ConversionRates rates(errorCode);
@@ -431,6 +438,92 @@
     }
 }
 
+void UnitsTest::testComplexUnitsConverter() {
+    IcuTestErrorCode status(*this, "UnitsTest::testComplexUnitConversions");
+    ConversionRates rates(status);
+    MeasureUnit input = MeasureUnit::getFoot();
+    MeasureUnit output = MeasureUnit::forIdentifier("foot-and-inch", status);
+    MeasureUnitImpl tempInput, tempOutput;
+    const MeasureUnitImpl &inputImpl = MeasureUnitImpl::forMeasureUnit(input, tempInput, status);
+    const MeasureUnitImpl &outputImpl = MeasureUnitImpl::forMeasureUnit(output, tempOutput, status);
+    auto converter = ComplexUnitsConverter(inputImpl, outputImpl, rates, status);
+
+    // Significantly less than 2.0.
+    MaybeStackVector<Measure> measures = converter.convert(1.9999, status);
+    assertEquals("measures length", 2, measures.length());
+    assertEquals("1.9999: measures[0] value", 1.0, measures[0]->getNumber().getDouble(status));
+    assertEquals("1.9999: measures[0] unit", MeasureUnit::getFoot().getIdentifier(),
+                 measures[0]->getUnit().getIdentifier());
+    assertEqualsNear("1.9999: measures[1] value", 11.9988, measures[1]->getNumber().getDouble(status), 0.0001);
+    assertEquals("1.9999: measures[1] unit", MeasureUnit::getInch().getIdentifier(),
+                 measures[1]->getUnit().getIdentifier());
+
+    // TODO: consider factoring out the set of tests to make this function more
+    // data-driven, *after* dealing appropriately with the memory leaks that can
+    // be demonstrated by this code.
+
+    // TODO: reusing measures results in a leak.
+    // A minimal nudge under 2.0.
+    MaybeStackVector<Measure> measures2 = converter.convert((2.0 - DBL_EPSILON), status);
+    assertEquals("measures length", 2, measures2.length());
+    assertEquals("1 - eps: measures[0] value", 2.0, measures2[0]->getNumber().getDouble(status));
+    assertEquals("1 - eps: measures[0] unit", MeasureUnit::getFoot().getIdentifier(),
+                 measures2[0]->getUnit().getIdentifier());
+    assertEquals("1 - eps: measures[1] value", 0.0, measures2[1]->getNumber().getDouble(status));
+    assertEquals("1 - eps: measures[1] unit", MeasureUnit::getInch().getIdentifier(),
+                 measures2[1]->getUnit().getIdentifier());
+
+    // Testing precision with meter and light-year. 1e-16 light years is
+    // 0.946073 meters, and double precision can provide only ~15 decimal
+    // digits, so we don't expect to get anything less than 1 meter.
+
+    // An epsilon's nudge under one light-year: should give 1 ly, 0 m.
+    input = MeasureUnit::getLightYear();
+    output = MeasureUnit::forIdentifier("light-year-and-meter", status);
+    // TODO: reusing tempInput and tempOutput results in a leak.
+    MeasureUnitImpl tempInput3, tempOutput3;
+    const MeasureUnitImpl &inputImpl3 = MeasureUnitImpl::forMeasureUnit(input, tempInput3, status);
+    const MeasureUnitImpl &outputImpl3 = MeasureUnitImpl::forMeasureUnit(output, tempOutput3, status);
+    // TODO: reusing converter results in a leak.
+    ComplexUnitsConverter converter3 = ComplexUnitsConverter(inputImpl3, outputImpl3, rates, status);
+    // TODO: reusing measures results in a leak.
+    MaybeStackVector<Measure> measures3 = converter3.convert((2.0 - DBL_EPSILON), status);
+    assertEquals("measures length", 2, measures3.length());
+    assertEquals("light-year test: measures[0] value", 2.0, measures3[0]->getNumber().getDouble(status));
+    assertEquals("light-year test: measures[0] unit", MeasureUnit::getLightYear().getIdentifier(),
+                 measures3[0]->getUnit().getIdentifier());
+    assertEquals("light-year test: measures[1] value", 0.0, measures3[1]->getNumber().getDouble(status));
+    assertEquals("light-year test: measures[1] unit", MeasureUnit::getMeter().getIdentifier(),
+                 measures3[1]->getUnit().getIdentifier());
+
+    // 1e-15 light years is 9.46073 meters (calculated using "bc" and the CLDR
+    // conversion factor). With double-precision maths, we get 10.5. In this
+    // case, we're off by almost 1 meter.
+    MaybeStackVector<Measure> measures4 = converter3.convert((1.0 + 1e-15), status);
+    assertEquals("measures length", 2, measures4.length());
+    assertEquals("light-year test: measures[0] value", 1.0, measures4[0]->getNumber().getDouble(status));
+    assertEquals("light-year test: measures[0] unit", MeasureUnit::getLightYear().getIdentifier(),
+                 measures4[0]->getUnit().getIdentifier());
+    assertEqualsNear("light-year test: measures[1] value", 10,
+                     measures4[1]->getNumber().getDouble(status), 1);
+    assertEquals("light-year test: measures[1] unit", MeasureUnit::getMeter().getIdentifier(),
+                 measures4[1]->getUnit().getIdentifier());
+
+    // 2e-16 light years is 1.892146 meters. We consider this in the noise, and
+    // thus expect a 0. (This test fails when 2e-16 is increased to 4e-16.)
+    MaybeStackVector<Measure> measures5 = converter3.convert((1.0 + 2e-16), status);
+    assertEquals("measures length", 2, measures5.length());
+    assertEquals("light-year test: measures[0] value", 1.0, measures5[0]->getNumber().getDouble(status));
+    assertEquals("light-year test: measures[0] unit", MeasureUnit::getLightYear().getIdentifier(),
+                 measures5[0]->getUnit().getIdentifier());
+    assertEquals("light-year test: measures[1] value", 0.0,
+                     measures5[1]->getNumber().getDouble(status));
+    assertEquals("light-year test: measures[1] unit", MeasureUnit::getMeter().getIdentifier(),
+                 measures5[1]->getUnit().getIdentifier());
+
+    // TODO(icu-units#63): test negative numbers!
+}
+
 void UnitsTest::testComplexUnitConverterSorting() {
     IcuTestErrorCode status(*this, "UnitsTest::testComplexUnitConverterSorting");
 
@@ -442,11 +535,11 @@
     auto measures = complexConverter.convert(10.0, status);
 
     U_ASSERT(measures.length() == 2);
-    assertEquals("Sorted Data", "foot", measures[0]->getUnit().getIdentifier());
-    assertEquals("Sorted Data", "inch", measures[1]->getUnit().getIdentifier());
+    assertEquals("inch-and-foot unit 0", "inch", measures[0]->getUnit().getIdentifier());
+    assertEquals("inch-and-foot unit 1", "foot", measures[1]->getUnit().getIdentifier());
 
-    assertEqualsNear("Sorted Data", 32, measures[0]->getNumber().getInt64(), 0.00001);
-    assertEqualsNear("Sorted Data", 9.7008, measures[1]->getNumber().getDouble(), 0.0001);
+    assertEqualsNear("inch-and-foot value 0", 9.7008, measures[0]->getNumber().getDouble(), 0.0001);
+    assertEqualsNear("inch-and-foot value 1", 32, measures[1]->getNumber().getInt64(), 0.00001);
 }
 
 /**
@@ -750,7 +843,9 @@
 }
 
 /**
- * Runs data-driven unit tests for unit preferences.
+ * Runs data-driven unit tests for unit preferences. It looks for the test cases
+ * in source/test/testdata/cldr/units/unitPreferencesTest.txt, which originates
+ * in CLDR.
  */
 void UnitsTest::testPreferences() {
     const char *filename = "unitPreferencesTest.txt";
@@ -765,7 +860,7 @@
     }
 
     CharString path(sourceTestDataPath, errorCode);
-    path.appendPathPart("units", errorCode);
+    path.appendPathPart("cldr/units", errorCode);
     path.appendPathPart(filename, errorCode);
 
     parsePreferencesTests(path.data(), ';', fields, maxFields, unitPreferencesTestDataLineFn, this,
diff --git a/icu4c/source/test/testdata/units/unitPreferencesTest.txt b/icu4c/source/test/testdata/units/unitPreferencesTest.txt
deleted file mode 100644
index e67b87b..0000000
--- a/icu4c/source/test/testdata/units/unitPreferencesTest.txt
+++ /dev/null
@@ -1,453 +0,0 @@
-# This file is a copy of common/testData/units/unitPreferencesTest.txt from CLDR.
-# WIP/TODO(hugovdm): determine a good update procedure and document it.
-#
-# Test data for unit preferences
-#  Copyright © 1991-2020 Unicode, Inc.
-#  For terms of use, see http://www.unicode.org/copyright.html
-#  Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
-#  CLDR data files are interpreted according to the LDML specification (http://unicode.org/reports/tr35/)
-#
-# Format:
-#   Quantity;   Usage;  Region; Input (r);  Input (d);  Input Unit; Output (r); Output (d); Output Unit
-#
-# Use: Convert the Input amount & unit according to the Usage and Region.
-#    The result should match the Output amount and unit.
-#    Both rational (r) and double64 (d) forms of the input and output amounts are supplied so that implementations
-#    have two options for testing based on the precision in their implementations. For example:
-#      3429 / 12500; 0.27432; meter;
-#    The Output amount and Unit are repeated for mixed units. In such a case, only the smallest unit will have
-#    both a rational and decimal amount; the others will have a single integer value, such as:
-#      length; person-height; CA; 3429 / 12500; 0.27432; meter; 2; foot; 54 / 5; 10.8; inch
-#    The input and output units are unit identifers; in particular, the output does not have further processing:
-#        • no localization
-#        • no adjustment for pluralization
-#        • no formatted with the skeleton
-#        • no suppression of zero values (for secondary -and- units such as pound in stone-and-pound)
-#
-# Generation: Set GENERATE_TESTS in TestUnits.java, and look at TestUnitPreferences results.
-
-area;   default;    001;    1100000;    1100000.0;  square-meter;   11 / 10;    1.1;    square-kilometer
-area;   default;    001;    1000000;    1000000.0;  square-meter;   1;  1.0;    square-kilometer
-area;   default;    001;    900000; 900000.0;   square-meter;   90; 90.0;   hectare
-area;   default;    001;    10000;  10000.0;    square-meter;   1;  1.0;    hectare
-area;   default;    001;    9000;   9000.0; square-meter;   9000;   9000.0; square-meter
-area;   default;    001;    1;  1.0;    square-meter;   1;  1.0;    square-meter
-area;   default;    001;    9 / 10; 0.9;    square-meter;   9000;   9000.0; square-centimeter
-area;   default;    001;    1 / 10000;  1.0E-4; square-meter;   1;  1.0;    square-centimeter
-area;   default;    001;    9 / 100000; 9.0E-5; square-meter;   9 / 10; 0.9;    square-centimeter
-
-area;   default;    GB; 222577103232 / 78125;   2848986.9213696;    square-meter;   11 / 10;    1.1;    square-mile
-area;   default;    GB; 40468564224 / 15625;    2589988.110336; square-meter;   1;  1.0;    square-mile
-area;   default;    GB; 182108539008 / 78125;   2330989.2993024;    square-meter;   576;    576.0;  acre
-area;   default;    GB; 316160658 / 78125;  4046.8564224;   square-meter;   1;  1.0;    acre
-area;   default;    GB; 1422722961 / 390625;    3642.17078016;  square-meter;   39204;  39204.0;    square-foot
-area;   default;    GB; 145161 / 1562500;   0.09290304; square-meter;   1;  1.0;    square-foot
-area;   default;    GB; 1306449 / 15625000; 0.083612736;    square-meter;   648 / 5;    129.6;  square-inch
-area;   default;    GB; 16129 / 25000000;   6.4516E-4;  square-meter;   1;  1.0;    square-inch
-area;   default;    GB; 145161 / 250000000; 5.80644E-4; square-meter;   9 / 10; 0.9;    square-inch
-
-area;   geograph;   001;    1100000;    1100000.0;  square-meter;   11 / 10;    1.1;    square-kilometer
-area;   geograph;   001;    1000000;    1000000.0;  square-meter;   1;  1.0;    square-kilometer
-area;   geograph;   001;    900000; 900000.0;   square-meter;   9 / 10; 0.9;    square-kilometer
-
-area;   geograph;   GB; 222577103232 / 78125;   2848986.9213696;    square-meter;   11 / 10;    1.1;    square-mile
-area;   geograph;   GB; 40468564224 / 15625;    2589988.110336; square-meter;   1;  1.0;    square-mile
-area;   geograph;   GB; 182108539008 / 78125;   2330989.2993024;    square-meter;   9 / 10; 0.9;    square-mile
-
-area;   land;   001;    11000;  11000.0;    square-meter;   11 / 10;    1.1;    hectare
-area;   land;   001;    10000;  10000.0;    square-meter;   1;  1.0;    hectare
-area;   land;   001;    9000;   9000.0; square-meter;   9 / 10; 0.9;    hectare
-
-area;   land;   GB; 1738883619 / 390625;    4451.54206464;  square-meter;   11 / 10;    1.1;    acre
-area;   land;   GB; 316160658 / 78125;  4046.8564224;   square-meter;   1;  1.0;    acre
-area;   land;   GB; 1422722961 / 390625;    3642.17078016;  square-meter;   9 / 10; 0.9;    acre
-
-concentration;  blood-glucose;  AG; 662435483600000000000000;   6.624354836E23; item-per-cubic-meter;   11 / 10;    1.1;    millimole-per-liter
-concentration;  blood-glucose;  AG; 602214076000000000000000;   6.02214076E23;  item-per-cubic-meter;   1;  1.0;    millimole-per-liter
-concentration;  blood-glucose;  AG; 541992668400000000000000;   5.419926684E23; item-per-cubic-meter;   9 / 10; 0.9;    millimole-per-liter
-
-concentration;  default;    001;    11 / 10;    1.1;    item-per-cubic-meter;   11 / 10;    1.1;    item-per-cubic-meter
-concentration;  default;    001;    1;  1.0;    item-per-cubic-meter;   1;  1.0;    item-per-cubic-meter
-concentration;  default;    001;    9 / 10; 0.9;    item-per-cubic-meter;   9 / 10; 0.9;    item-per-cubic-meter
-
-consumption;    default;    001;    11 / 1000000000;    1.1E-8; cubic-meter-per-meter;  11 / 10;    1.1;    liter-per-100-kilometer
-consumption;    default;    001;    1 / 100000000;  1.0E-8; cubic-meter-per-meter;  1;  1.0;    liter-per-100-kilometer
-consumption;    default;    001;    9 / 1000000000; 9.0E-9; cubic-meter-per-meter;  9 / 10; 0.9;    liter-per-100-kilometer
-
-consumption;    vehicle-fuel;   001;    11 / 1000000000;    1.1E-8; cubic-meter-per-meter;  11 / 10;    1.1;    liter-per-100-kilometer
-consumption;    vehicle-fuel;   001;    1 / 100000000;  1.0E-8; cubic-meter-per-meter;  1;  1.0;    liter-per-100-kilometer
-consumption;    vehicle-fuel;   001;    9 / 1000000000; 9.0E-9; cubic-meter-per-meter;  9 / 10; 0.9;    liter-per-100-kilometer
-
-consumption;    vehicle-fuel;   BR; 11 / 10000000;  1.1E-6; cubic-meter-per-meter;  11 / 10;    1.1;    liter-per-kilometer
-consumption;    vehicle-fuel;   BR; 1 / 1000000;    1.0E-6; cubic-meter-per-meter;  1;  1.0;    liter-per-kilometer
-consumption;    vehicle-fuel;   BR; 9 / 10000000;   9.0E-7; cubic-meter-per-meter;  9 / 10; 0.9;    liter-per-kilometer
-
-consumption-inverse;    default;    001;    110000000;  1.1E8;  meter-per-cubic-meter;  11 / 10;    1.1;    kilometer-per-centiliter
-consumption-inverse;    default;    001;    100000000;  1.0E8;  meter-per-cubic-meter;  1;  1.0;    kilometer-per-centiliter
-consumption-inverse;    default;    001;    90000000;   9.0E7;  meter-per-cubic-meter;  9 / 10; 0.9;    kilometer-per-centiliter
-
-consumption-inverse;    vehicle-fuel;   001;    110000000;  1.1E8;  meter-per-cubic-meter;  11 / 10;    1.1;    kilometer-per-centiliter
-consumption-inverse;    vehicle-fuel;   001;    100000000;  1.0E8;  meter-per-cubic-meter;  1;  1.0;    kilometer-per-centiliter
-consumption-inverse;    vehicle-fuel;   001;    90000000;   9.0E7;  meter-per-cubic-meter;  9 / 10; 0.9;    kilometer-per-centiliter
-
-consumption-inverse;    vehicle-fuel;   US; 52800000000 / 112903;   467658.0781732992;  meter-per-cubic-meter;  11 / 10;    1.1;    mile-per-gallon
-consumption-inverse;    vehicle-fuel;   US; 48000000000 / 112903;   425143.707430272;   meter-per-cubic-meter;  1;  1.0;    mile-per-gallon
-consumption-inverse;    vehicle-fuel;   US; 43200000000 / 112903;   382629.3366872448;  meter-per-cubic-meter;  9 / 10; 0.9;    mile-per-gallon
-
-consumption-inverse;    vehicle-fuel;   CA; 177027840000 / 454609;  389406.8089281118;  meter-per-cubic-meter;  11 / 10;    1.1;    mile-per-gallon-imperial
-consumption-inverse;    vehicle-fuel;   CA; 160934400000 / 454609;  354006.1899346471;  meter-per-cubic-meter;  1;  1.0;    mile-per-gallon-imperial
-consumption-inverse;    vehicle-fuel;   CA; 144840960000 / 454609;  318605.5709411824;  meter-per-cubic-meter;  9 / 10; 0.9;    mile-per-gallon-imperial
-
-duration;   default;    001;    95040;  95040.0;    second; 11 / 10;    1.1;    day
-duration;   default;    001;    86400;  86400.0;    second; 1;  1.0;    day
-duration;   default;    001;    77760;  77760.0;    second; 108 / 5;    21.6;   hour
-duration;   default;    001;    3600;   3600.0; second; 1;  1.0;    hour
-duration;   default;    001;    3240;   3240.0; second; 54; 54.0;   minute
-duration;   default;    001;    60; 60.0;   second; 1;  1.0;    minute
-duration;   default;    001;    54; 54.0;   second; 54; 54.0;   second
-duration;   default;    001;    1;  1.0;    second; 1;  1.0;    second
-duration;   default;    001;    9 / 10; 0.9;    second; 900;    900.0;  millisecond
-duration;   default;    001;    1 / 1000;   0.001;  second; 1;  1.0;    millisecond
-duration;   default;    001;    9 / 10000;  9.0E-4; second; 900;    900.0;  microsecond
-duration;   default;    001;    1 / 1000000;    1.0E-6; second; 1;  1.0;    microsecond
-duration;   default;    001;    9 / 10000000;   9.0E-7; second; 900;    900.0;  nanosecond
-duration;   default;    001;    1 / 1000000000; 1.0E-9; second; 1;  1.0;    nanosecond
-duration;   default;    001;    9 / 10000000000;    9.0E-10;    second; 9 / 10; 0.9;    nanosecond
-
-duration;   media;  001;    66; 66.0;   second; 1;  minute; 6;  6.0;    second
-duration;   media;  001;    60; 60.0;   second; 1;  minute; 0;  0.0;    second
-duration;   media;  001;    54; 54.0;   second; 54; 54.0;   second
-duration;   media;  001;    1;  1.0;    second; 1;  1.0;    second
-duration;   media;  001;    9 / 10; 0.9;    second; 9 / 10; 0.9;    second
-
-energy; default;    001;    3960000;    3960000.0;  kilogram-square-meter-per-square-second;    11 / 10;    1.1;    kilowatt-hour
-energy; default;    001;    3600000;    3600000.0;  kilogram-square-meter-per-square-second;    1;  1.0;    kilowatt-hour
-energy; default;    001;    3240000;    3240000.0;  kilogram-square-meter-per-square-second;    9 / 10; 0.9;    kilowatt-hour
-
-energy; food;   US; 23012 / 5;  4602.4; kilogram-square-meter-per-square-second;    11 / 10;    1.1;    foodcalorie
-energy; food;   US; 4184;   4184.0; kilogram-square-meter-per-square-second;    1;  1.0;    foodcalorie
-energy; food;   US; 18828 / 5;  3765.6; kilogram-square-meter-per-square-second;    9 / 10; 0.9;    foodcalorie
-
-energy; food;   001;    23012 / 5;  4602.4; kilogram-square-meter-per-square-second;    11 / 10;    1.1;    kilocalorie
-energy; food;   001;    4184;   4184.0; kilogram-square-meter-per-square-second;    1;  1.0;    kilocalorie
-energy; food;   001;    18828 / 5;  3765.6; kilogram-square-meter-per-square-second;    9 / 10; 0.9;    kilocalorie
-
-length; default;    001;    1100;   1100.0; meter;  11 / 10;    1.1;    kilometer
-length; default;    001;    1000;   1000.0; meter;  1;  1.0;    kilometer
-length; default;    001;    900;    900.0;  meter;  900;    900.0;  meter
-length; default;    001;    1;  1.0;    meter;  1;  1.0;    meter
-length; default;    001;    9 / 10; 0.9;    meter;  90; 90.0;   centimeter
-length; default;    001;    1 / 100;    0.01;   meter;  1;  1.0;    centimeter
-length; default;    001;    9 / 1000;   0.009;  meter;  9 / 10; 0.9;    centimeter
-
-length; default;    GB; 1106424 / 625;  1770.2784;  meter;  11 / 10;    1.1;    mile
-length; default;    GB; 201168 / 125;   1609.344;   meter;  1;  1.0;    mile
-length; default;    GB; 905256 / 625;   1448.4096;  meter;  4752;   4752.0; foot
-length; default;    GB; 381 / 1250; 0.3048; meter;  1;  1.0;    foot
-length; default;    GB; 3429 / 12500;   0.27432;    meter;  54 / 5; 10.8;   inch
-length; default;    GB; 127 / 5000; 0.0254; meter;  1;  1.0;    inch
-length; default;    GB; 1143 / 50000;   0.02286;    meter;  9 / 10; 0.9;    inch
-
-length; person; 001;    11 / 1000;  0.011;  meter;  11 / 10;    1.1;    centimeter
-length; person; 001;    1 / 100;    0.01;   meter;  1;  1.0;    centimeter
-length; person; 001;    9 / 1000;   0.009;  meter;  9 / 10; 0.9;    centimeter
-
-length; person; CA; 1397 / 50000;   0.02794;    meter;  11 / 10;    1.1;    inch
-length; person; CA; 127 / 5000; 0.0254; meter;  1;  1.0;    inch
-length; person; CA; 1143 / 50000;   0.02286;    meter;  9 / 10; 0.9;    inch
-
-length; person-height;  001;    11 / 1000;  0.011;  meter;  11 / 10;    1.1;    centimeter
-length; person-height;  001;    1 / 100;    0.01;   meter;  1;  1.0;    centimeter
-length; person-height;  001;    9 / 1000;   0.009;  meter;  9 / 10; 0.9;    centimeter
-
-length; person-height;  CA; 11811 / 12500;  0.94488;    meter;  3;  foot;   6 / 5;  1.2;    inch
-length; person-height;  CA; 1143 / 1250;    0.9144; meter;  3;  foot;   0;  0.0;    inch
-length; person-height;  CA; 11049 / 12500;  0.88392;    meter;  174 / 5;    34.8;   inch
-length; person-height;  CA; 127 / 5000; 0.0254; meter;  1;  1.0;    inch
-length; person-height;  CA; 1143 / 50000;   0.02286;    meter;  9 / 10; 0.9;    inch
-
-length; person-height;  AT; 11 / 10;    1.1;    meter;  1;  meter;  10; 10.0;   centimeter
-length; person-height;  AT; 1;  1.0;    meter;  1;  meter;  0;  0.0;    centimeter
-length; person-height;  AT; 9 / 10; 0.9;    meter;  0;  meter;  90; 90.0;   centimeter
-
-length; rainfall;   BR; 11 / 1000;  0.011;  meter;  11 / 10;    1.1;    centimeter
-length; rainfall;   BR; 1 / 100;    0.01;   meter;  1;  1.0;    centimeter
-length; rainfall;   BR; 9 / 1000;   0.009;  meter;  9 / 10; 0.9;    centimeter
-
-length; rainfall;   US; 1397 / 50000;   0.02794;    meter;  11 / 10;    1.1;    inch
-length; rainfall;   US; 127 / 5000; 0.0254; meter;  1;  1.0;    inch
-length; rainfall;   US; 1143 / 50000;   0.02286;    meter;  9 / 10; 0.9;    inch
-
-length; rainfall;   001;    11 / 10000; 0.0011; meter;  11 / 10;    1.1;    millimeter
-length; rainfall;   001;    1 / 1000;   0.001;  meter;  1;  1.0;    millimeter
-length; rainfall;   001;    9 / 10000;  9.0E-4; meter;  9 / 10; 0.9;    millimeter
-
-length; road;   001;    1000;   1000.0; meter;  1;  1.0;    kilometer
-length; road;   001;    900;    900.0;  meter;  9 / 10; 0.9;    kilometer
-length; road;   001;    800;    800.0;  meter;  800;    800.0;  meter
-length; road;   001;    300;    300.0;  meter;  300;    300.0;  meter
-length; road;   001;    2999 / 10;  299.9;  meter;  2999 / 10;  299.9;  meter
-length; road;   001;    1;  1.0;    meter;  1;  1.0;    meter
-length; road;   001;    9 / 10; 0.9;    meter;  9 / 10; 0.9;    meter
-
-length; road;   US; 603504 / 625;   965.6064;   meter;  3 / 5;  0.6;    mile
-length; road;   US; 100584 / 125;   804.672;    meter;  1 / 2;  0.5;    mile
-length; road;   US; 402336 / 625;   643.7376;   meter;  2112;   2112.0; foot
-length; road;   US; 762 / 25;   30.48;  meter;  100;    100.0;  foot
-length; road;   US; 380619 / 12500; 30.44952;   meter;  999 / 10;   99.9;   foot
-length; road;   US; 381 / 1250; 0.3048; meter;  1;  1.0;    foot
-length; road;   US; 3429 / 12500;   0.27432;    meter;  9 / 10; 0.9;    foot
-
-length; road;   GB; 603504 / 625;   965.6064;   meter;  3 / 5;  0.6;    mile
-length; road;   GB; 100584 / 125;   804.672;    meter;  1 / 2;  0.5;    mile
-length; road;   GB; 402336 / 625;   643.7376;   meter;  704;    704.0;  yard
-length; road;   GB; 2286 / 25;  91.44;  meter;  100;    100.0;  yard
-length; road;   GB; 1141857 / 12500;    91.34856;   meter;  999 / 10;   99.9;   yard
-length; road;   GB; 1143 / 1250;    0.9144; meter;  1;  1.0;    yard
-length; road;   GB; 10287 / 12500;  0.82296;    meter;  9 / 10; 0.9;    yard
-
-length; road;   SE; 11000;  11000.0;    meter;  11 / 10;    1.1;    mile-scandinavian
-length; road;   SE; 10000;  10000.0;    meter;  1;  1.0;    mile-scandinavian
-length; road;   SE; 9000;   9000.0; meter;  9;  9.0;    kilometer
-length; road;   SE; 1000;   1000.0; meter;  1;  1.0;    kilometer
-length; road;   SE; 900;    900.0;  meter;  900;    900.0;  meter
-length; road;   SE; 300;    300.0;  meter;  300;    300.0;  meter
-length; road;   SE; 2999 / 10;  299.9;  meter;  2999 / 10;  299.9;  meter
-length; road;   SE; 1;  1.0;    meter;  1;  1.0;    meter
-length; road;   SE; 9 / 10; 0.9;    meter;  9 / 10; 0.9;    meter
-
-length; snowfall;   001;    11 / 1000;  0.011;  meter;  11 / 10;    1.1;    centimeter
-length; snowfall;   001;    1 / 100;    0.01;   meter;  1;  1.0;    centimeter
-length; snowfall;   001;    9 / 1000;   0.009;  meter;  9 / 10; 0.9;    centimeter
-
-length; snowfall;   US; 1397 / 50000;   0.02794;    meter;  11 / 10;    1.1;    inch
-length; snowfall;   US; 127 / 5000; 0.0254; meter;  1;  1.0;    inch
-length; snowfall;   US; 1143 / 50000;   0.02286;    meter;  9 / 10; 0.9;    inch
-
-length; vehicle;    GB; 4191 / 12500;   0.33528;    meter;  1;  foot;   6 / 5;  1.2;    inch
-length; vehicle;    GB; 381 / 1250; 0.3048; meter;  1;  foot;   0;  0.0;    inch
-length; vehicle;    GB; 3429 / 12500;   0.27432;    meter;  0;  foot;   54 / 5; 10.8;   inch
-
-length; vehicle;    001;    11 / 10;    1.1;    meter;  11 / 10;    1.1;    meter
-length; vehicle;    001;    1;  1.0;    meter;  1;  1.0;    meter
-length; vehicle;    001;    9 / 10; 0.9;    meter;  9 / 10; 0.9;    meter
-
-length; vehicle;    MX; 11 / 10;    1.1;    meter;  1;  meter;  10; 10.0;   centimeter
-length; vehicle;    MX; 1;  1.0;    meter;  1;  meter;  0;  0.0;    centimeter
-length; vehicle;    MX; 9 / 10; 0.9;    meter;  0;  meter;  90; 90.0;   centimeter
-
-length; visiblty;   001;    200;    200.0;  meter;  1 / 5;  0.2;    kilometer
-length; visiblty;   001;    100;    100.0;  meter;  1 / 10; 0.1;    kilometer
-length; visiblty;   001;    1;  1.0;    meter;  1;  1.0;    meter
-length; visiblty;   001;    9 / 10; 0.9;    meter;  9 / 10; 0.9;    meter
-length; visiblty;   001;    0;  0.0;    meter;  0;  0.0;    meter
-
-length; visiblty;   DE; 11 / 10;    1.1;    meter;  11 / 10;    1.1;    meter
-length; visiblty;   DE; 1;  1.0;    meter;  1;  1.0;    meter
-length; visiblty;   DE; 9 / 10; 0.9;    meter;  9 / 10; 0.9;    meter
-
-length; visiblty;   GB; 1106424 / 625;  1770.2784;  meter;  11 / 10;    1.1;    mile
-length; visiblty;   GB; 201168 / 125;   1609.344;   meter;  1;  1.0;    mile
-length; visiblty;   GB; 905256 / 625;   1448.4096;  meter;  4752;   4752.0; foot
-length; visiblty;   GB; 381 / 1250; 0.3048; meter;  1;  1.0;    foot
-length; visiblty;   GB; 3429 / 12500;   0.27432;    meter;  9 / 10; 0.9;    foot
-
-mass;   default;    001;    1100;   1100.0; kilogram;   11 / 10;    1.1;    metric-ton
-mass;   default;    001;    1000;   1000.0; kilogram;   1;  1.0;    metric-ton
-mass;   default;    001;    900;    900.0;  kilogram;   900;    900.0;  kilogram
-mass;   default;    001;    1;  1.0;    kilogram;   1;  1.0;    kilogram
-mass;   default;    001;    9 / 10; 0.9;    kilogram;   900;    900.0;  gram
-mass;   default;    001;    1 / 1000;   0.001;  kilogram;   1;  1.0;    gram
-mass;   default;    001;    9 / 10000;  9.0E-4; kilogram;   900;    900.0;  milligram
-mass;   default;    001;    1 / 1000000;    1.0E-6; kilogram;   1;  1.0;    milligram
-mass;   default;    001;    9 / 10000000;   9.0E-7; kilogram;   900;    900.0;  microgram
-mass;   default;    001;    1 / 1000000000; 1.0E-9; kilogram;   1;  1.0;    microgram
-mass;   default;    001;    9 / 10000000000;    9.0E-10;    kilogram;   9 / 10; 0.9;    microgram
-
-mass;   default;    GB; 498951607 / 500000; 997.903214; kilogram;   11 / 10;    1.1;    ton
-mass;   default;    GB; 45359237 / 50000;   907.18474;  kilogram;   1;  1.0;    ton
-mass;   default;    GB; 408233133 / 500000; 816.466266; kilogram;   1800;   1800.0; pound
-mass;   default;    GB; 45359237 / 100000000;   0.45359237; kilogram;   1;  1.0;    pound
-mass;   default;    GB; 408233133 / 1000000000; 0.408233133;    kilogram;   72 / 5; 14.4;   ounce
-mass;   default;    GB; 45359237 / 1600000000;  0.028349523125; kilogram;   1;  1.0;    ounce
-mass;   default;    GB; 408233133 / 16000000000;    0.0255145708125;    kilogram;   9 / 10; 0.9;    ounce
-
-mass;   person; 001;    11 / 10;    1.1;    kilogram;   11 / 10;    1.1;    kilogram
-mass;   person; 001;    1;  1.0;    kilogram;   1;  1.0;    kilogram
-mass;   person; 001;    9 / 10; 0.9;    kilogram;   900;    900.0;  gram
-mass;   person; 001;    1 / 1000;   0.001;  kilogram;   1;  1.0;    gram
-mass;   person; 001;    9 / 10000;  9.0E-4; kilogram;   9 / 10; 0.9;    gram
-
-mass;   person; DZ; 11 / 10;    1.1;    kilogram;   1;  kilogram;   100;    100.0;  gram
-mass;   person; DZ; 1;  1.0;    kilogram;   1;  kilogram;   0;  0.0;    gram
-mass;   person; DZ; 9 / 10; 0.9;    kilogram;   0;  kilogram;   900;    900.0;  gram
-
-mass;   person; US; 498951607 / 1000000000; 0.498951607;    kilogram;   11 / 10;    1.1;    pound
-mass;   person; US; 45359237 / 100000000;   0.45359237; kilogram;   1;  1.0;    pound
-mass;   person; US; 408233133 / 1000000000; 0.408233133;    kilogram;   0;  pound;  72 / 5; 14.4;   ounce
-
-mass;   person; GB; 3492661249 / 500000000; 6.985322498;    kilogram;   1;  stone;  7 / 5;  1.4;    pound
-mass;   person; GB; 317514659 / 50000000;   6.35029318; kilogram;   1;  stone;  0;  0.0;    pound
-mass;   person; GB; 2857631931 / 500000000; 5.715263862;    kilogram;   12; pound;  48 / 5; 9.6;    ounce
-mass;   person; GB; 45359237 / 100000000;   0.45359237; kilogram;   1;  pound;  0;  0.0;    ounce
-mass;   person; GB; 408233133 / 1000000000; 0.408233133;    kilogram;   0;  pound;  72 / 5; 14.4;   ounce
-
-mass;   person; HK; 498951607 / 1000000000; 0.498951607;    kilogram;   1;  pound;  8 / 5;  1.6;    ounce
-mass;   person; HK; 45359237 / 100000000;   0.45359237; kilogram;   1;  pound;  0;  0.0;    ounce
-mass;   person; HK; 408233133 / 1000000000; 0.408233133;    kilogram;   0;  pound;  72 / 5; 14.4;   ounce
-
-mass-density;   blood-glucose;  001;    11 / 1000;  0.011;  kilogram-per-cubic-meter;   11 / 10;    1.1;    milligram-per-deciliter
-mass-density;   blood-glucose;  001;    1 / 100;    0.01;   kilogram-per-cubic-meter;   1;  1.0;    milligram-per-deciliter
-mass-density;   blood-glucose;  001;    9 / 1000;   0.009;  kilogram-per-cubic-meter;   9 / 10; 0.9;    milligram-per-deciliter
-
-mass-density;   default;    001;    11 / 10;    1.1;    kilogram-per-cubic-meter;   11 / 10;    1.1;    kilogram-per-cubic-meter
-mass-density;   default;    001;    1;  1.0;    kilogram-per-cubic-meter;   1;  1.0;    kilogram-per-cubic-meter
-mass-density;   default;    001;    9 / 10; 0.9;    kilogram-per-cubic-meter;   9 / 10; 0.9;    kilogram-per-cubic-meter
-
-power;  default;    001;    1100000000; 1.1E9;  kilogram-square-meter-per-cubic-second; 11 / 10;    1.1;    gigawatt
-power;  default;    001;    1000000000; 1.0E9;  kilogram-square-meter-per-cubic-second; 1;  1.0;    gigawatt
-power;  default;    001;    900000000;  9.0E8;  kilogram-square-meter-per-cubic-second; 900;    900.0;  megawatt
-power;  default;    001;    1000000;    1000000.0;  kilogram-square-meter-per-cubic-second; 1;  1.0;    megawatt
-power;  default;    001;    900000; 900000.0;   kilogram-square-meter-per-cubic-second; 900;    900.0;  kilowatt
-power;  default;    001;    1000;   1000.0; kilogram-square-meter-per-cubic-second; 1;  1.0;    kilowatt
-power;  default;    001;    900;    900.0;  kilogram-square-meter-per-cubic-second; 900;    900.0;  watt
-power;  default;    001;    1;  1.0;    kilogram-square-meter-per-cubic-second; 1;  1.0;    watt
-power;  default;    001;    9 / 10; 0.9;    kilogram-square-meter-per-cubic-second; 900;    900.0;  milliwatt
-power;  default;    001;    1 / 1000;   0.001;  kilogram-square-meter-per-cubic-second; 1;  1.0;    milliwatt
-power;  default;    001;    9 / 10000;  9.0E-4; kilogram-square-meter-per-cubic-second; 9 / 10; 0.9;    milliwatt
-
-power;  engine; 001;    1100;   1100.0; kilogram-square-meter-per-cubic-second; 11 / 10;    1.1;    kilowatt
-power;  engine; 001;    1000;   1000.0; kilogram-square-meter-per-cubic-second; 1;  1.0;    kilowatt
-power;  engine; 001;    900;    900.0;  kilogram-square-meter-per-cubic-second; 9 / 10; 0.9;    kilowatt
-
-power;  engine; GB; 410134929370248621 / 500000000000000;   820.2698587404972;  kilogram-square-meter-per-cubic-second; 11 / 10;    1.1;    horsepower
-power;  engine; GB; 37284993579113511 / 50000000000000; 745.6998715822702;  kilogram-square-meter-per-cubic-second; 1;  1.0;    horsepower
-power;  engine; GB; 335564942212021599 / 500000000000000;   671.1298844240432;  kilogram-square-meter-per-cubic-second; 9 / 10; 0.9;    horsepower
-
-pressure;   baromtrc;   001;    110;    110.0;  kilogram-per-meter-square-second;   11 / 10;    1.1;    hectopascal
-pressure;   baromtrc;   001;    100;    100.0;  kilogram-per-meter-square-second;   1;  1.0;    hectopascal
-pressure;   baromtrc;   001;    90; 90.0;   kilogram-per-meter-square-second;   9 / 10; 0.9;    hectopascal
-
-pressure;   baromtrc;   IN; 37250275043751 / 10000000000;   3725.0275043751;    kilogram-per-meter-square-second;   11 / 10;    1.1;    inch-ofhg
-pressure;   baromtrc;   IN; 3386388640341 / 1000000000; 3386.388640341; kilogram-per-meter-square-second;   1;  1.0;    inch-ofhg
-pressure;   baromtrc;   IN; 30477497763069 / 10000000000;   3047.7497763069;    kilogram-per-meter-square-second;   9 / 10; 0.9;    inch-ofhg
-
-pressure;   baromtrc;   BR; 110;    110.0;  kilogram-per-meter-square-second;   11 / 10;    1.1;    millibar
-pressure;   baromtrc;   BR; 100;    100.0;  kilogram-per-meter-square-second;   1;  1.0;    millibar
-pressure;   baromtrc;   BR; 90; 90.0;   kilogram-per-meter-square-second;   9 / 10; 0.9;    millibar
-
-pressure;   baromtrc;   MX; 293309252313 / 2000000000;  146.6546261565; kilogram-per-meter-square-second;   11 / 10;    1.1;    millimeter-ofhg
-pressure;   baromtrc;   MX; 26664477483 / 200000000;    133.322387415;  kilogram-per-meter-square-second;   1;  1.0;    millimeter-ofhg
-pressure;   baromtrc;   MX; 239980297347 / 2000000000;  119.9901486735; kilogram-per-meter-square-second;   9 / 10; 0.9;    millimeter-ofhg
-
-pressure;   default;    001;    1100000;    1100000.0;  kilogram-per-meter-square-second;   11 / 10;    1.1;    megapascal
-pressure;   default;    001;    1000000;    1000000.0;  kilogram-per-meter-square-second;   1;  1.0;    megapascal
-pressure;   default;    001;    900000; 900000.0;   kilogram-per-meter-square-second;   900000; 900000.0;   pascal
-pressure;   default;    001;    1;  1.0;    kilogram-per-meter-square-second;   1;  1.0;    pascal
-pressure;   default;    001;    9 / 10; 0.9;    kilogram-per-meter-square-second;   9 / 10; 0.9;    pascal
-
-pressure;   default;    GB; 97860875535731 / 12903200000;   7584.233022485197;  kilogram-per-meter-square-second;   11 / 10;    1.1;    pound-force-per-square-inch
-pressure;   default;    GB; 8896443230521 / 1290320000; 6894.757293168361;  kilogram-per-meter-square-second;   1;  1.0;    pound-force-per-square-inch
-pressure;   default;    GB; 80067989074689 / 12903200000;   6205.281563851525;  kilogram-per-meter-square-second;   9 / 10; 0.9;    pound-force-per-square-inch
-
-speed;  default;    001;    11 / 36;    0.3055555555555556; meter-per-second;   11 / 10;    1.1;    kilometer-per-hour
-speed;  default;    001;    5 / 18; 0.2777777777777778; meter-per-second;   1;  1.0;    kilometer-per-hour
-speed;  default;    001;    1 / 4;  0.25;   meter-per-second;   9 / 10; 0.9;    kilometer-per-hour
-
-speed;  default;    GB; 15367 / 31250;  0.491744;   meter-per-second;   11 / 10;    1.1;    mile-per-hour
-speed;  default;    GB; 1397 / 3125;    0.44704;    meter-per-second;   1;  1.0;    mile-per-hour
-speed;  default;    GB; 12573 / 31250;  0.402336;   meter-per-second;   9 / 10; 0.9;    mile-per-hour
-
-speed;  wind;   001;    11 / 36;    0.3055555555555556; meter-per-second;   11 / 10;    1.1;    kilometer-per-hour
-speed;  wind;   001;    5 / 18; 0.2777777777777778; meter-per-second;   1;  1.0;    kilometer-per-hour
-speed;  wind;   001;    1 / 4;  0.25;   meter-per-second;   9 / 10; 0.9;    kilometer-per-hour
-
-speed;  wind;   FI; 11 / 10;    1.1;    meter-per-second;   11 / 10;    1.1;    meter-per-second
-speed;  wind;   FI; 1;  1.0;    meter-per-second;   1;  1.0;    meter-per-second
-speed;  wind;   FI; 9 / 10; 0.9;    meter-per-second;   9 / 10; 0.9;    meter-per-second
-
-speed;  wind;   US; 15367 / 31250;  0.491744;   meter-per-second;   11 / 10;    1.1;    mile-per-hour
-speed;  wind;   US; 1397 / 3125;    0.44704;    meter-per-second;   1;  1.0;    mile-per-hour
-speed;  wind;   US; 12573 / 31250;  0.402336;   meter-per-second;   9 / 10; 0.9;    mile-per-hour
-
-temperature;    default;    001;    1097 / 4;   274.25; kelvin; 11 / 10;    1.1;    celsius
-temperature;    default;    001;    5483 / 20;  274.15; kelvin; 1;  1.0;    celsius
-temperature;    default;    001;    5481 / 20;  274.05; kelvin; 9 / 10; 0.9;    celsius
-
-temperature;    default;    US; 15359 / 60; 255.9833333333333;  kelvin; 11 / 10;    1.1;    fahrenheit
-temperature;    default;    US; 46067 / 180;    255.9277777777778;  kelvin; 1;  1.0;    fahrenheit
-temperature;    default;    US; 46057 / 180;    255.8722222222222;  kelvin; 9 / 10; 0.9;    fahrenheit
-
-temperature;    weather;    001;    1097 / 4;   274.25; kelvin; 11 / 10;    1.1;    celsius
-temperature;    weather;    001;    5483 / 20;  274.15; kelvin; 1;  1.0;    celsius
-temperature;    weather;    001;    5481 / 20;  274.05; kelvin; 9 / 10; 0.9;    celsius
-
-temperature;    weather;    BS; 15359 / 60; 255.9833333333333;  kelvin; 11 / 10;    1.1;    fahrenheit
-temperature;    weather;    BS; 46067 / 180;    255.9277777777778;  kelvin; 1;  1.0;    fahrenheit
-temperature;    weather;    BS; 46057 / 180;    255.8722222222222;  kelvin; 9 / 10; 0.9;    fahrenheit
-
-volume; default;    001;    11 / 10;    1.1;    cubic-meter;    11 / 10;    1.1;    cubic-meter
-volume; default;    001;    1;  1.0;    cubic-meter;    1;  1.0;    cubic-meter
-volume; default;    001;    9 / 10; 0.9;    cubic-meter;    900000; 900000.0;   cubic-centimeter
-volume; default;    001;    1 / 1000000;    1.0E-6; cubic-meter;    1;  1.0;    cubic-centimeter
-volume; default;    001;    9 / 10000000;   9.0E-7; cubic-meter;    9 / 10; 0.9;    cubic-centimeter
-
-volume; default;    GB; 608369751 / 19531250000;    0.0311485312512;    cubic-meter;    11 / 10;    1.1;    cubic-foot
-volume; default;    GB; 55306341 / 1953125000;  0.028316846592; cubic-meter;    1;  1.0;    cubic-foot
-volume; default;    GB; 497757069 / 19531250000;    0.0254851619328;    cubic-meter;    7776 / 5;   1555.2; cubic-inch
-volume; default;    GB; 2048383 / 125000000000; 1.6387064E-5;   cubic-meter;    1;  1.0;    cubic-inch
-volume; default;    GB; 18435447 / 1250000000000;   1.47483576E-5;  cubic-meter;    9 / 10; 0.9;    cubic-inch
-
-volume; fluid;  001;    11 / 10000; 0.0011; cubic-meter;    11 / 10;    1.1;    liter
-volume; fluid;  001;    1 / 1000;   0.001;  cubic-meter;    1;  1.0;    liter
-volume; fluid;  001;    9 / 10000;  9.0E-4; cubic-meter;    900;    900.0;  milliliter
-volume; fluid;  001;    1 / 1000000;    1.0E-6; cubic-meter;    1;  1.0;    milliliter
-volume; fluid;  001;    9 / 10000000;   9.0E-7; cubic-meter;    9 / 10; 0.9;    milliliter
-
-volume; fluid;  US; 5204941203 / 1250000000000; 0.0041639529624;    cubic-meter;    11 / 10;    1.1;    gallon
-volume; fluid;  US; 473176473 / 125000000000;   0.003785411784; cubic-meter;    1;  1.0;    gallon
-volume; fluid;  US; 4258588257 / 1250000000000; 0.0034068706056;    cubic-meter;    18 / 5; 3.6;    quart
-volume; fluid;  US; 473176473 / 500000000000;   9.46352946E-4;  cubic-meter;    1;  1.0;    quart
-volume; fluid;  US; 4258588257 / 5000000000000; 8.517176514E-4; cubic-meter;    9 / 5;  1.8;    pint
-volume; fluid;  US; 473176473 / 1000000000000;  4.73176473E-4;  cubic-meter;    1;  1.0;    pint
-volume; fluid;  US; 4258588257 / 10000000000000;    4.258588257E-4; cubic-meter;    9 / 5;  1.8;    cup
-volume; fluid;  US; 473176473 / 2000000000000;  2.365882365E-4; cubic-meter;    1;  1.0;    cup
-volume; fluid;  US; 4258588257 / 20000000000000;    2.1292941285E-4;    cubic-meter;    36 / 5; 7.2;    fluid-ounce
-volume; fluid;  US; 473176473 / 16000000000000; 2.95735295625E-5;   cubic-meter;    1;  1.0;    fluid-ounce
-volume; fluid;  US; 4258588257 / 160000000000000;   2.661617660625E-5;  cubic-meter;    9 / 5;  1.8;    tablespoon
-volume; fluid;  US; 473176473 / 32000000000000; 1.478676478125E-5;  cubic-meter;    1;  1.0;    tablespoon
-volume; fluid;  US; 4258588257 / 320000000000000;   1.3308088303125E-5; cubic-meter;    27 / 10;    2.7;    teaspoon
-volume; fluid;  US; 157725491 / 32000000000000; 4.92892159375E-6;   cubic-meter;    1;  1.0;    teaspoon
-volume; fluid;  US; 1419529419 / 320000000000000;   4.436029434375E-6;  cubic-meter;    9 / 10; 0.9;    teaspoon
-
-volume; fluid;  GB; 5000699 / 1000000000;   0.005000699;    cubic-meter;    11 / 10;    1.1;    gallon-imperial
-volume; fluid;  GB; 454609 / 100000000; 0.00454609; cubic-meter;    1;  1.0;    gallon-imperial
-volume; fluid;  GB; 4091481 / 1000000000;   0.004091481;    cubic-meter;    144;    144.0;  fluid-ounce-imperial
-volume; fluid;  GB; 454609 / 16000000000;   2.84130625E-5;  cubic-meter;    1;  1.0;    fluid-ounce-imperial
-volume; fluid;  GB; 4091481 / 160000000000; 2.557175625E-5; cubic-meter;    9 / 10; 0.9;    fluid-ounce-imperial
-
-volume; oil;    001;    109303765263 / 625000000000;    0.1748860244208;    cubic-meter;    11 / 10;    1.1;    barrel
-volume; oil;    001;    9936705933 / 62500000000;   0.158987294928; cubic-meter;    1;  1.0;    barrel
-volume; oil;    001;    89430353397 / 625000000000; 0.1430885654352;    cubic-meter;    9 / 10; 0.9;    barrel
-
-volume; vehicle;    US; 5204941203 / 1250000000000; 0.0041639529624;    cubic-meter;    11 / 10;    1.1;    gallon
-volume; vehicle;    US; 473176473 / 125000000000;   0.003785411784; cubic-meter;    1;  1.0;    gallon
-volume; vehicle;    US; 4258588257 / 1250000000000; 0.0034068706056;    cubic-meter;    9 / 10; 0.9;    gallon
-
-volume; vehicle;    001;    11 / 10000; 0.0011; cubic-meter;    11 / 10;    1.1;    liter
-volume; vehicle;    001;    1 / 1000;   0.001;  cubic-meter;    1;  1.0;    liter
-volume; vehicle;    001;    9 / 10000;  9.0E-4; cubic-meter;    9 / 10; 0.9;    liter
-
-year-duration;  default;    001;    11 / 10;    1.1;    year;   11 / 10;    1.1;    year
-year-duration;  default;    001;    1;  1.0;    year;   1;  1.0;    year
-year-duration;  default;    001;    9 / 10; 0.9;    year;   54 / 5; 10.8;   month
-year-duration;  default;    001;    1 / 12; 0.08333333333333333;    year;   1;  1.0;    month
-year-duration;  default;    001;    3 / 40; 0.075;  year;   9 / 10; 0.9;    month
-
-year-duration;  person-age; 001;    13 / 5; 2.6;    year;   13 / 5; 2.6;    year-person
-year-duration;  person-age; 001;    5 / 2;  2.5;    year;   5 / 2;  2.5;    year-person
-year-duration;  person-age; 001;    12 / 5; 2.4;    year;   2;  year-person;    24 / 5; 4.8;    month-person
-year-duration;  person-age; 001;    1;  1.0;    year;   1;  year-person;    0;  0.0;    month-person
-year-duration;  person-age; 001;    9 / 10; 0.9;    year;   54 / 5; 10.8;   month-person
-year-duration;  person-age; 001;    1 / 12; 0.08333333333333333;    year;   1;  1.0;    month-person
-year-duration;  person-age; 001;    3 / 40; 0.075;  year;   9 / 10; 0.9;    month-person
diff --git a/icu4c/source/test/testdata/units/unitsTest.txt b/icu4c/source/test/testdata/units/unitsTest.txt
deleted file mode 100644
index 31b0e25..0000000
--- a/icu4c/source/test/testdata/units/unitsTest.txt
+++ /dev/null
@@ -1,197 +0,0 @@
-# This file is a copy of common/testData/units/unitsTest.txt from CLDR.
-# WIP/TODO(hugovdm): determine a good update procedure and document it.
-#
-# Test data for unit conversions
-#  Copyright © 1991-2020 Unicode, Inc.
-#  For terms of use, see http://www.unicode.org/copyright.html
-#  Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
-#  CLDR data files are interpreted according to the LDML specification (http://unicode.org/reports/tr35/)
-#
-# Format:
-#   Quantity    ;   x   ;   y   ;   conversion to y (rational)  ;   test: 1000 x ⟹ y
-#
-# Use: convert 1000 x units to the y unit; the result should match the final column,
-#   at the given precision. For example, when the last column is 159.1549,
-#   round to 4 decimal digits before comparing.
-# Note that certain conversions are approximate, such as degrees to radians
-#
-# Generation: Set GENERATE_TESTS in TestUnits.java, and look at TestParseUnit results.
-
-acceleration    ;   meter-per-square-second ;   meter-per-square-second ;   1 * x   ;   1,000.00
-acceleration    ;   g-force ;   meter-per-square-second ;   9.80665 * x ;   9806.65
-angle   ;   arc-second  ;   revolution  ;   0.0000625/81 * x    ;   7.716049E-4
-angle   ;   arc-minute  ;   revolution  ;   0.00125/27 * x  ;   0.0462963
-angle   ;   degree  ;   revolution  ;   0.025/9 * x ;   2.777778
-angle   ;   radian  ;   revolution  ;   65,501,488/411,557,987 * x  ;   159.1549
-angle   ;   revolution  ;   revolution  ;   1 * x   ;   1,000.00
-area    ;   square-centimeter   ;   square-meter    ;   0.0001 * x  ;   0.1
-area    ;   square-inch ;   square-meter    ;   0.00064516 * x  ;   0.64516
-area    ;   square-foot ;   square-meter    ;   0.09290304 * x  ;   92.90304
-area    ;   square-yard ;   square-meter    ;   0.83612736 * x  ;   836.1274
-area    ;   square-meter    ;   square-meter    ;   1 * x   ;   1,000.00
-area    ;   dunam   ;   square-meter    ;   1,000 * x   ;   1000000.0
-area    ;   acre    ;   square-meter    ;   4,046.8564224 * x   ;   4046856.0
-area    ;   hectare ;   square-meter    ;   10,000 * x  ;   1.0E7
-area    ;   square-kilometer    ;   square-meter    ;   1,000,000 * x   ;   1.0E9
-area    ;   square-mile ;   square-meter    ;   2,589,988.110336 * x    ;   2.589988E9
-concentration   ;   millimole-per-liter ;   item-per-cubic-meter    ;   602,214,076,000,000,000,000,000 * x ;   6.022141E26
-consumption ;   liter-per-100-kilometer ;   cubic-meter-per-meter   ;   0.00000001 * x  ;   1.0E-5
-consumption ;   liter-per-kilometer ;   cubic-meter-per-meter   ;   0.000001 * x    ;   0.001
-consumption-inverse ;   mile-per-gallon-imperial    ;   meter-per-cubic-meter   ;   160,934,400,000/454,609 * x ;   3.540062E8
-consumption-inverse ;   mile-per-gallon ;   meter-per-cubic-meter   ;   48,000,000,000/112,903 * x  ;   4.251437E8
-digital ;   bit ;   bit ;   1 * x   ;   1,000.00
-digital ;   byte    ;   bit ;   8 * x   ;   8000.0
-digital ;   kilobit ;   bit ;   1,000 * x   ;   1000000.0
-digital ;   kilobyte    ;   bit ;   8,000 * x   ;   8000000.0
-digital ;   megabit ;   bit ;   1,000,000 * x   ;   1.0E9
-digital ;   megabyte    ;   bit ;   8,000,000 * x   ;   8.0E9
-digital ;   gigabit ;   bit ;   1,000,000,000 * x   ;   1.0E12
-digital ;   gigabyte    ;   bit ;   8,000,000,000 * x   ;   8.0E12
-digital ;   terabit ;   bit ;   1,000,000,000,000 * x   ;   1.0E15
-digital ;   terabyte    ;   bit ;   8,000,000,000,000 * x   ;   8.0E15
-digital ;   petabyte    ;   bit ;   8,000,000,000,000,000 * x   ;   8.0E18
-duration    ;   nanosecond  ;   second  ;   0.000000001 * x ;   1.0E-6
-duration    ;   microsecond ;   second  ;   0.000001 * x    ;   0.001
-duration    ;   millisecond ;   second  ;   0.001 * x   ;   1.0
-duration    ;   second  ;   second  ;   1 * x   ;   1,000.00
-duration    ;   minute  ;   second  ;   60 * x  ;   60000.0
-duration    ;   hour    ;   second  ;   3,600 * x   ;   3600000.0
-duration    ;   day ;   second  ;   86,400 * x  ;   8.64E7
-duration    ;   day-person  ;   second  ;   86,400 * x  ;   8.64E7
-duration    ;   week    ;   second  ;   604,800 * x ;   6.048E8
-duration    ;   week-person ;   second  ;   604,800 * x ;   6.048E8
-electric-current    ;   milliampere ;   ampere  ;   0.001 * x   ;   1.0
-electric-current    ;   ampere  ;   ampere  ;   1 * x   ;   1,000.00
-electric-resistance ;   ohm ;   kilogram-square-meter-per-cubic-second-square-ampere    ;   1 * x   ;   1000.0
-energy  ;   electronvolt    ;   kilogram-square-meter-per-square-second ;   0.0000000000000000001602177 * x ;   1.602177E-16
-energy  ;   dalton  ;   kilogram-square-meter-per-square-second ;   0.00000000014924180856 * x  ;   1.492418E-7
-energy  ;   joule   ;   kilogram-square-meter-per-square-second ;   1 * x   ;   1000.0
-energy  ;   newton-meter    ;   kilogram-square-meter-per-square-second ;   1 * x   ;   1000.0
-energy  ;   pound-force-foot    ;   kilogram-square-meter-per-square-second ;   1.3558179483314004 * x  ;   1355.818
-energy  ;   calorie ;   kilogram-square-meter-per-square-second ;   4.184 * x   ;   4184.0
-energy  ;   kilojoule   ;   kilogram-square-meter-per-square-second ;   1,000 * x   ;   1000000.0
-energy  ;   british-thermal-unit    ;   kilogram-square-meter-per-square-second ;   9,489.1523804/9 * x ;   1054350.0
-energy  ;   foodcalorie ;   kilogram-square-meter-per-square-second ;   4,184 * x   ;   4184000.0
-energy  ;   kilocalorie ;   kilogram-square-meter-per-square-second ;   4,184 * x   ;   4184000.0
-energy  ;   kilowatt-hour   ;   kilogram-square-meter-second-per-cubic-second   ;   3,600,000 * x   ;   3.6E9
-energy  ;   therm-us    ;   kilogram-square-meter-per-square-second ;   105,480,400 * x ;   1.054804E11
-force   ;   newton  ;   kilogram-meter-per-square-second    ;   1 * x   ;   1000.0
-force   ;   pound-force ;   kilogram-meter-per-square-second    ;   4.4482216152605 * x ;   4448.222
-frequency   ;   hertz   ;   revolution-per-second   ;   1 * x   ;   1000.0
-frequency   ;   kilohertz   ;   revolution-per-second   ;   1,000 * x   ;   1000000.0
-frequency   ;   megahertz   ;   revolution-per-second   ;   1,000,000 * x   ;   1.0E9
-frequency   ;   gigahertz   ;   revolution-per-second   ;   1,000,000,000 * x   ;   1.0E12
-graphics    ;   dot ;   pixel   ;   1 * x   ;   1000.0
-graphics    ;   pixel   ;   pixel   ;   1 * x   ;   1,000.00
-graphics    ;   megapixel   ;   pixel   ;   1,000,000 * x   ;   1.0E9
-length  ;   picometer   ;   meter   ;   0.000000000001 * x  ;   1.0E-9
-length  ;   nanometer   ;   meter   ;   0.000000001 * x ;   1.0E-6
-length  ;   micrometer  ;   meter   ;   0.000001 * x    ;   0.001
-length  ;   point   ;   meter   ;   0.003175/9 * x  ;   0.3527778
-length  ;   millimeter  ;   meter   ;   0.001 * x   ;   1.0
-length  ;   centimeter  ;   meter   ;   0.01 * x    ;   10.0
-length  ;   inch    ;   meter   ;   0.0254 * x  ;   25.4
-length  ;   decimeter   ;   meter   ;   0.1 * x ;   100.0
-length  ;   foot    ;   meter   ;   0.3048 * x  ;   304.8
-length  ;   yard    ;   meter   ;   0.9144 * x  ;   914.4
-length  ;   meter   ;   meter   ;   1 * x   ;   1,000.00
-length  ;   fathom  ;   meter   ;   1.8288 * x  ;   1828.8
-length  ;   furlong ;   meter   ;   201.168 * x ;   201168.0
-length  ;   kilometer   ;   meter   ;   1,000 * x   ;   1000000.0
-length  ;   mile    ;   meter   ;   1,609.344 * x   ;   1609344.0
-length  ;   nautical-mile   ;   meter   ;   1,852 * x   ;   1852000.0
-length  ;   mile-scandinavian   ;   meter   ;   10,000 * x  ;   1.0E7
-length  ;   100-kilometer   ;   meter   ;   100,000 * x ;   1.0E8
-length  ;   earth-radius    ;   meter   ;   6,378,100 * x   ;   6.3781E9
-length  ;   solar-radius    ;   meter   ;   695,700,000 * x ;   6.957E11
-length  ;   astronomical-unit   ;   meter   ;   149,597,900,000 * x ;   1.495979E14
-length  ;   light-year  ;   meter   ;   9,460,730,000,000,000 * x   ;   9.46073E18
-length  ;   parsec  ;   meter   ;   30,856,780,000,000,000 * x  ;   3.085678E19
-luminous-flux   ;   lux ;   candela-square-meter-per-square-meter   ;   1 * x   ;   1000.0
-luminous-intensity  ;   candela ;   candela ;   1 * x   ;   1,000.00
-mass    ;   microgram   ;   kilogram    ;   0.000000001 * x ;   1.0E-6
-mass    ;   milligram   ;   kilogram    ;   0.000001 * x    ;   0.001
-mass    ;   carat   ;   kilogram    ;   0.0002 * x  ;   0.2
-mass    ;   gram    ;   kilogram    ;   0.001 * x   ;   1.0
-mass    ;   ounce   ;   kilogram    ;   0.028349523125 * x  ;   28.34952
-mass    ;   ounce-troy  ;   kilogram    ;   0.03110348 * x  ;   31.10348
-mass    ;   pound   ;   kilogram    ;   0.45359237 * x  ;   453.5924
-mass    ;   kilogram    ;   kilogram    ;   1 * x   ;   1,000.00
-mass    ;   stone   ;   kilogram    ;   6.35029318 * x  ;   6350.293
-mass    ;   ton ;   kilogram    ;   907.18474 * x   ;   907184.7
-mass    ;   metric-ton  ;   kilogram    ;   1,000 * x   ;   1000000.0
-mass    ;   earth-mass  ;   kilogram    ;   5,972,200,000,000,000,000,000,000 * x   ;   5.9722E27
-mass    ;   solar-mass  ;   kilogram    ;   1,988,470,000,000,000,000,000,000,000,000 * x   ;   1.98847E33
-mass-density    ;   milligram-per-deciliter ;   kilogram-per-cubic-meter    ;   0.01 * x    ;   10.0
-portion ;   permillion  ;   portion ;   0.000001 * x    ;   0.001
-portion ;   permyriad   ;   portion ;   0.0001 * x  ;   0.1
-portion ;   permille    ;   portion ;   0.001 * x   ;   1.0
-portion ;   percent ;   portion ;   0.01 * x    ;   10.0
-portion ;   karat   ;   portion ;   0.125/3 * x ;   41.66667
-portion ;   portion ;   portion ;   1 * x   ;   1,000.00
-power   ;   milliwatt   ;   kilogram-square-meter-per-cubic-second  ;   0.001 * x   ;   1.0
-power   ;   watt    ;   kilogram-square-meter-per-cubic-second  ;   1 * x   ;   1000.0
-power   ;   horsepower  ;   kilogram-square-meter-per-cubic-second  ;   745.69987158227022 * x  ;   745699.9
-power   ;   kilowatt    ;   kilogram-square-meter-per-cubic-second  ;   1,000 * x   ;   1000000.0
-power   ;   megawatt    ;   kilogram-square-meter-per-cubic-second  ;   1,000,000 * x   ;   1.0E9
-power   ;   gigawatt    ;   kilogram-square-meter-per-cubic-second  ;   1,000,000,000 * x   ;   1.0E12
-power   ;   solar-luminosity    ;   kilogram-square-meter-per-cubic-second  ;   382,800,000,000,000,000,000,000,000 * x ;   3.828E29
-pressure    ;   pascal  ;   kilogram-per-meter-square-second    ;   1 * x   ;   1000.0
-pressure    ;   hectopascal ;   kilogram-per-meter-square-second    ;   100 * x ;   100000.0
-pressure    ;   millibar    ;   kilogram-per-meter-square-second    ;   100 * x ;   100000.0
-pressure    ;   millimeter-ofhg ;   kilogram-meter-per-square-meter-square-second   ;   133.322387415 * x   ;   133322.4
-pressure    ;   kilopascal  ;   kilogram-per-meter-square-second    ;   1,000 * x   ;   1000000.0
-pressure    ;   inch-ofhg   ;   kilogram-meter-per-square-meter-square-second   ;   3,386.388640341 * x ;   3386389.0
-pressure    ;   pound-force-per-square-inch ;   kilogram-meter-per-square-meter-square-second   ;   111,205,540.3815125/16,129 * x  ;   6894757.0
-pressure    ;   bar ;   kilogram-per-meter-square-second    ;   100,000 * x ;   1.0E8
-pressure    ;   atmosphere  ;   kilogram-per-meter-square-second    ;   101,325 * x ;   1.01325E8
-pressure    ;   megapascal  ;   kilogram-per-meter-square-second    ;   1,000,000 * x   ;   1.0E9
-pressure-per-length ;   ofhg    ;   kilogram-per-square-meter-square-second ;   133,322.387415 * x  ;   1.333224E8
-resolution  ;   dot-per-inch    ;   pixel-per-meter ;   5,000/127 * x   ;   39370.08
-resolution  ;   pixel-per-inch  ;   pixel-per-meter ;   5,000/127 * x   ;   39370.08
-resolution  ;   dot-per-centimeter  ;   pixel-per-meter ;   100 * x ;   100000.0
-resolution  ;   pixel-per-centimeter    ;   pixel-per-meter ;   100 * x ;   100000.0
-speed   ;   kilometer-per-hour  ;   meter-per-second    ;   2.5/9 * x   ;   277.7778
-speed   ;   mile-per-hour   ;   meter-per-second    ;   0.44704 * x ;   447.04
-speed   ;   knot    ;   meter-per-second    ;   4.63/9 * x  ;   514.4444
-speed   ;   meter-per-second    ;   meter-per-second    ;   1 * x   ;   1,000.00
-substance-amount    ;   item    ;   item    ;   1 * x   ;   1,000.00
-substance-amount    ;   mole    ;   item    ;   602,214,076,000,000,000,000,000 * x ;   6.022141E26
-temperature ;   fahrenheit  ;   kelvin  ;   5/9 * x - 2,298.35/9    ;   810.9278
-temperature ;   kelvin  ;   kelvin  ;   1 * x   ;   1,000.00
-temperature ;   celsius ;   kelvin  ;   1 * x - 273.15  ;   1273.15
-typewidth   ;   em  ;   em  ;   1 * x   ;   1,000.00
-voltage ;   volt    ;   kilogram-square-meter-per-cubic-second-ampere   ;   1 * x   ;   1000.0
-volume  ;   cubic-centimeter    ;   cubic-meter ;   0.000001 * x    ;   0.001
-volume  ;   milliliter  ;   cubic-meter ;   0.000001 * x    ;   0.001
-volume  ;   teaspoon    ;   cubic-meter ;   0.00000492892159375 * x ;   0.004928922
-volume  ;   centiliter  ;   cubic-meter ;   0.00001 * x ;   0.01
-volume  ;   tablespoon  ;   cubic-meter ;   0.00001478676478125 * x ;   0.01478676
-volume  ;   cubic-inch  ;   cubic-meter ;   0.000016387064 * x  ;   0.01638706
-volume  ;   fluid-ounce-imperial    ;   cubic-meter ;   0.0000284130625 * x ;   0.02841306
-volume  ;   fluid-ounce ;   cubic-meter ;   0.0000295735295625 * x  ;   0.02957353
-volume  ;   deciliter   ;   cubic-meter ;   0.0001 * x  ;   0.1
-volume  ;   cup ;   cubic-meter ;   0.0002365882365 * x ;   0.2365882
-volume  ;   cup-metric  ;   cubic-meter ;   0.00025 * x ;   0.25
-volume  ;   pint    ;   cubic-meter ;   0.000473176473 * x  ;   0.4731765
-volume  ;   pint-metric ;   cubic-meter ;   0.0005 * x  ;   0.5
-volume  ;   quart   ;   cubic-meter ;   0.000946352946 * x  ;   0.9463529
-volume  ;   liter   ;   cubic-meter ;   0.001 * x   ;   1.0
-volume  ;   gallon  ;   cubic-meter ;   0.003785411784 * x  ;   3.785412
-volume  ;   gallon-imperial ;   cubic-meter ;   0.00454609 * x  ;   4.54609
-volume  ;   cubic-foot  ;   cubic-meter ;   0.028316846592 * x  ;   28.31685
-volume  ;   bushel  ;   cubic-meter ;   0.03523907016688 * x    ;   35.23907
-volume  ;   hectoliter  ;   cubic-meter ;   0.1 * x ;   100.0
-volume  ;   barrel  ;   cubic-meter ;   0.158987294928 * x  ;   158.9873
-volume  ;   cubic-yard  ;   cubic-meter ;   0.764554857984 * x  ;   764.5549
-volume  ;   cubic-meter ;   cubic-meter ;   1 * x   ;   1,000.00
-volume  ;   megaliter   ;   cubic-meter ;   1,000 * x   ;   1000000.0
-volume  ;   acre-foot   ;   cubic-meter ;   1,233.48183754752 * x   ;   1233482.0
-volume  ;   cubic-kilometer ;   cubic-meter ;   1,000,000,000 * x   ;   1.0E12
-volume  ;   cubic-mile  ;   cubic-meter ;   4,168,181,825.440579584 * x ;   4.168182E12
-year-duration   ;   month   ;   year    ;   0.25/3 * x  ;   83.33333
-year-duration   ;   month-person    ;   year    ;   0.25/3 * x  ;   83.33333
-year-duration   ;   year    ;   year    ;   1 * x   ;   1,000.00
-year-duration   ;   year-person ;   year    ;   1 * x   ;   1000.0
-year-duration   ;   decade  ;   year    ;   10 * x  ;   10000.0
-year-duration   ;   century ;   year    ;   100 * x ;   100000.0