From a0a920246835dc5d7584e96ab1ad92288a06ba14 Mon Sep 17 00:00:00 2001 From: Younies Date: Fri, 14 Feb 2020 14:27:10 +0100 Subject: [PATCH] add most of the functions, still need to be tested --- icu4c/source/i18n/number_decnum.h | 4 +- icu4c/source/i18n/number_utils.cpp | 48 ++++-- icu4c/source/i18n/unitconverter.cpp | 41 +++-- icu4c/source/i18n/unitconverter.h | 210 +++++++++++------------ icu4c/source/test/intltest/intltest.cpp | 44 ++--- icu4c/source/test/intltest/intltest.h | 2 +- icu4c/source/test/intltest/unitstest.cpp | 149 +++++----------- 7 files changed, 226 insertions(+), 272 deletions(-) diff --git a/icu4c/source/i18n/number_decnum.h b/icu4c/source/i18n/number_decnum.h index 548f00eafdd..9ea3017eaba 100644 --- a/icu4c/source/i18n/number_decnum.h +++ b/icu4c/source/i18n/number_decnum.h @@ -48,8 +48,8 @@ class U_I18N_API DecNum : public UMemory { /** Sets the decNumber to the BCD representation. */ void setTo(const uint8_t* bcd, int32_t length, int32_t scale, bool isNegative, UErrorCode& status); - /** Returns the double representation of the `DecNum` */ - double toDouble(UErrorCode& status) const; + /** Returns integral value of the `DecNum` */ + int32_t toInt32() const; void normalize(); diff --git a/icu4c/source/i18n/number_utils.cpp b/icu4c/source/i18n/number_utils.cpp index ad780a72905..61ede694007 100644 --- a/icu4c/source/i18n/number_utils.cpp +++ b/icu4c/source/i18n/number_utils.cpp @@ -238,11 +238,10 @@ void DecNum::setTo(const uint8_t *bcd, int32_t length, int32_t scale, bool isNeg } } -double DecNum::toDouble(UErrorCode &status) const { - double result = 0.0; - // TODO(younies): implement - return result; -} +int32_t DecNum::toInt32() const { + decContext fContext; + return uprv_decNumberToInt32(fData, &fContext); + } void DecNum::normalize() { uprv_decNumberReduce(fData, fData, &fContext); } @@ -281,7 +280,7 @@ void DecNum::add(double rhs, UErrorCode &status) { } void DecNum::add(const DecNum &rhs, UErrorCode &status) { - uprv_decNumberAdd_66(fData, fData, rhs.fData, &fContext); + uprv_decNumberAdd(fData, fData, rhs.fData, &fContext); if (fContext.status != 0) { status = U_INTERNAL_PROGRAM_ERROR; } @@ -294,7 +293,7 @@ void DecNum::subtract(double rhs, UErrorCode &status) { } void DecNum::subtract(const DecNum &rhs, UErrorCode &status) { - uprv_decNumberSubtract_66(fData, fData, rhs.fData, &fContext); + uprv_decNumberSubtract(fData, fData, rhs.fData, &fContext); if (fContext.status != 0) { status = U_INTERNAL_PROGRAM_ERROR; } @@ -305,29 +304,42 @@ bool DecNum::isNegative() const { return decNumberIsNegative(fData.getAlias()); bool DecNum::isZero() const { return decNumberIsZero(fData.getAlias()); } bool DecNum::lessThan(const DecNum &rhs, UErrorCode &status) const { - // return uprv_decNumberCompare_66(fData, fData, rhs.fData, fContext); - - return false; // TODO(younies): implement this function + // lhs < rhs --> lhs - rhs < 0 ==> lhs - rhs (is negative). + DecNum temp; + temp.setTo(*this, status); + temp.subtract(rhs, status); + return temp.isNegative(); } bool DecNum::greaterThan(const DecNum &rhs, UErrorCode &status) const { - // return uprv_decNumberCompare_66(fData, fData, rhs.fData, fContext); + // lhs > rhs --> 0 > rhs - lhs ==> rhs - lhs (is negative). + DecNum temp; + temp.setTo(rhs, status); + temp.subtract(*this, status); - return false; // TODO(younies): implement this function + return temp.isNegative(); } bool DecNum::equalTo(const DecNum &rhs, UErrorCode &status) const { - // return uprv_decNumberCompare_66(fData, fData, rhs.fData, fContext); + // lhs == rhs --> lhs - rhs == 0 ==> lhs - rhs (is zero). + DecNum temp; + temp.setTo(*this, status); + temp.subtract(rhs, status); - return false; // TODO(younies): implement this function + return temp.isZero(); } StringPiece DecNum::toString(UErrorCode &status) const { - std::string result; - StringByteSink output(&result); - toString(output, status); + if (U_FAILURE(status)) { + return StringPiece(); + } + + // "string must be at least dn->digits+14 characters long" + int32_t minCapacity = fData.getAlias()->digits + 14; + MaybeStackArray buffer(minCapacity); + uprv_decNumberToString(fData, buffer.getAlias()); - return StringPiece(result); + return StringPiece(buffer.getAlias()); } void DecNum::toString(ByteSink &output, UErrorCode &status) const { diff --git a/icu4c/source/i18n/unitconverter.cpp b/icu4c/source/i18n/unitconverter.cpp index 90720b40051..ca8ca5bfca8 100644 --- a/icu4c/source/i18n/unitconverter.cpp +++ b/icu4c/source/i18n/unitconverter.cpp @@ -30,7 +30,7 @@ struct Factor { number::impl::DecNum offset; bool reciprocal = false; - int8_t constants[CONSTANTS_COUNT] = {}; + int32_t constants[CONSTANTS_COUNT] = {}; Factor(UErrorCode &status) { factorNum.setTo(1.0, status); @@ -47,7 +47,7 @@ struct Factor { } void divideBy(const Factor &rhs, UErrorCode &status) { - factorNum.divideBy(rhs.factorNum, status); + factorNum.divideBy(rhs.factorNum, status); // Error if Numerator equal zero ! factorDen.divideBy(rhs.factorDen, status); for (int i = 0; i < CONSTANTS_COUNT; i++) constants[i] -= rhs.constants[i]; // TODO(younies): fix this @@ -162,17 +162,17 @@ class UnitConversionRatesSink : public ResourceSink { void addSingleFactorConstant(Factor &factor, StringPiece baseStr, number::impl::DecNum &power, int32_t signal, UErrorCode &status) { if (baseStr == "ft2m") { - factor.constants[CONSTANT_FT2M] += power.toDouble(status); + factor.constants[CONSTANT_FT2M] += power.toInt32(); } else if (baseStr == "G") { - factor.constants[CONSTANT_G] += power.toDouble(status); + factor.constants[CONSTANT_G] += power.toInt32(); } else if (baseStr == "gravity") { - factor.constants[CONSTANT_GRAVITY] += power.toDouble(status); + factor.constants[CONSTANT_GRAVITY] += power.toInt32(); } else if (baseStr == "lb2kg") { - factor.constants[CONSTANT_LB2KG] += power.toDouble(status); + factor.constants[CONSTANT_LB2KG] += power.toInt32(); } else if (baseStr == "cup2m3") { - factor.constants[CONSTANT_CUP2M3] += power.toDouble(status); + factor.constants[CONSTANT_CUP2M3] += power.toInt32(); } else if (baseStr == "pi") { - factor.constants[CONSTANT_PI] += power.toDouble(status); + factor.constants[CONSTANT_PI] += power.toInt32(); } else { if (U_FAILURE(status)) return; @@ -220,7 +220,7 @@ void addFactorElement(Factor &factor, StringPiece elementStr, int32_t signal, UE baseStr = elementStr; } - power.multiplyBy(signalDecNum, status); + power.multiplyBy(signalDecNum, status); // The power needs to take the same sign as `signal`. addSingleFactorConstant(factor, baseStr, power, signal, status); } @@ -298,14 +298,16 @@ void substituteSingleConstant(Factor &factor, int32_t constValue, const DecNum &constSub /* constant actual value, e.g. G= 9.88888 */, UErrorCode &status) { bool positive = constValue >= 0; - bool absConstValue = std::abs(constValue); + int32_t absConstValue = std::abs(constValue); - for (int i = 0; i < absConstValue; i++) { - if (positive) { - factor.factorNum.multiplyBy(constSub, status); - } else { - factor.factorDen.multiplyBy(constSub, status); - } + DecNum finalConstSub; + finalConstSub.setTo(constSub, status); + finalConstSub.multiplyBy(absConstValue, status); + + if (positive) { + factor.factorNum.multiplyBy(finalConstSub, status); + } else { + factor.factorDen.multiplyBy(finalConstSub, status); } } @@ -321,7 +323,9 @@ void substituteConstants(Factor &factor, UErrorCode &status) { constSubs[CONSTANT_LB2KG].setTo("0.453592", status); for (int i = 0; i < CONSTANTS_COUNT; i++) { + if (factor.constants[i] == 0) continue; substituteSingleConstant(factor, factor.constants[i], constSubs[i], status); + factor.constants[i] = 0; } } @@ -344,7 +348,7 @@ void loadConversionRate(ConversionRate &conversionRate, StringPiece source, Stri loadCompoundFactor(TargettoMiddle, target, status); finalFactor.multiplyBy(SourcetoMiddle, status); - finalFactor.divideBy(SourcetoMiddle, status); + finalFactor.divideBy(TargettoMiddle, status); substituteConstants(finalFactor, status); @@ -376,6 +380,9 @@ UnitConverter::UnitConverter(MeasureUnit source, MeasureUnit target, UErrorCode } void UnitConverter::convert(const DecNum &input_value, DecNum &output_value, UErrorCode status) { + std::printf(conversion_rate_.factorNum.toString(status).data()); + std::printf(conversion_rate_.factorDen.toString(status).data()); + std::printf(conversion_rate_.offset.toString(status).data()); DecNum result(input_value, status); result.multiplyBy(conversion_rate_.factorNum, status); diff --git a/icu4c/source/i18n/unitconverter.h b/icu4c/source/i18n/unitconverter.h index 0272abb0477..b28aeedc0dc 100644 --- a/icu4c/source/i18n/unitconverter.h +++ b/icu4c/source/i18n/unitconverter.h @@ -20,7 +20,7 @@ enum Constants { CONSTANT_FT2M, // ft2m stands for foot to meter. CONSTANT_PI, CONSTANT_GRAVITY, - CONSTANT_G, + CONSTANT_G, CONSTANT_CUP2M3, // CUP2M3 stands for cup to cubic meter. CONSTANT_LB2KG, @@ -48,7 +48,7 @@ struct ConversionRate { }; // The data in this namespace are temporary, it is just for testing -namespace temporarily { +namespace temporarily { struct entry { StringPiece source; @@ -58,120 +58,118 @@ struct entry { bool reciprocal; } dataEntries[] = { // Base Units - {"kilogram", "kilogram", "", "", false}, - {"candela", "candela", "", "", false}, - {"meter", "meter", "", "", false}, - {"second", "second", "", "", false}, - {"year", "year", "", "", false}, - {"ampere", "ampere", "", "", false}, - {"kelvin", "kelvin", "", "", false}, - {"revolution", "revolution", "", "", false}, - {"item", "item", "", "", false}, - {"portion", "portion", "", "", false}, - {"bit", "bit", "", "", false}, - {"pixel", "pixel", "", "", false}, - {"em", "em", "", "", false}, + {"kilogram", "kilogram", "1", "0", false}, + {"candela", "candela", "1", "0", false}, + {"meter", "meter", "1", "0", false}, + {"second", "second", "1", "0", false}, + {"year", "year", "1", "0", false}, + {"ampere", "ampere", "1", "0", false}, + {"kelvin", "kelvin", "1", "0", false}, + {"revolution", "revolution", "1", "0", false}, + {"item", "item", "1", "0", false}, + {"portion", "portion", "1", "0", false}, + {"bit", "bit", "1", "0", false}, + {"pixel", "pixel", "1", "0", false}, + {"em", "em", "1", "0", false}, // Unit conversions Rates - {"atmosphere", "kilogram-per-meter-square-second", "101325", "", false}, - {"byte", "bit", "8", "", false}, - {"day", "second", "86400", "", false}, - {"day-person", "second", "86400", "", false}, - {"hour", "second", "3600", "", false}, - {"minute", "second", "60", "", false}, - {"week", "second", "604800", "", false}, - {"week-person", "second", "604800", "", false}, - {"ohm", "kilogram-square-meter-per-cubic-second-square-ampere", "1", "", false}, - {"volt", "kilogram-square-meter-per-cubic-second-ampere", "1", "", false}, - {"light-year", "meter", "9460730000000000", "", false}, - {"parsec", "meter", "30856780000000000", "", false}, - {"g-force", "meter-per-square-second", "gravity", "", false}, - {"degree", "revolution", "1/360", "", false}, - {"arc-minute", "revolution", "1/360*60", "", false}, - {"arc-second", "revolution", "1/360*60*60", "", false}, - {"radian", "revolution", "1/2*PI", "", false}, - {"mole", "item", "602214076000000000000000", "", false}, - {"percent", "portion", "1/100", "", false}, - {"permille", "portion", "1/1000", "", false}, - {"permyriad", "portion", "1/10000", "", false}, - {"calorie", "kilogram-square-meter-per-square-second", "4.184", "", false}, - {"electronvolt", "kilogram-square-meter-per-square-second", "0.0000000000000000001602177", "", + {"atmosphere", "kilogram-per-meter-square-second", "101325", "0", false}, + {"byte", "bit", "8", "0", false}, + {"day", "second", "86400", "0", false}, + {"day-person", "second", "86400", "0", false}, + {"hour", "second", "3600", "0", false}, + {"minute", "second", "60", "0", false}, + {"week", "second", "604800", "0", false}, + {"week-person", "second", "604800", "0", false}, + {"ohm", "kilogram-square-meter-per-cubic-second-square-ampere", "1", "0", false}, + {"volt", "kilogram-square-meter-per-cubic-second-ampere", "1", "0", false}, + {"light-year", "meter", "9460730000000000", "0", false}, + {"parsec", "meter", "30856780000000000", "0", false}, + {"g-force", "meter-per-square-second", "gravity", "0", false}, + {"degree", "revolution", "1/360", "0", false}, + {"arc-minute", "revolution", "1/360*60", "0", false}, + {"arc-second", "revolution", "1/360*60*60", "0", false}, + {"radian", "revolution", "1/2*PI", "0", false}, + {"mole", "item", "602214076000000000000000", "0", false}, + {"percent", "portion", "1/100", "0", false}, + {"permille", "portion", "1/1000", "0", false}, + {"permyriad", "portion", "1/10000", "0", false}, + {"calorie", "kilogram-square-meter-per-square-second", "4.184", "0", false}, + {"electronvolt", "kilogram-square-meter-per-square-second", "0.0000000000000000001602177", "0", false}, - {"foodcalorie", "kilogram-square-meter-per-square-second", "4184", "", false}, - {"hertz", "revolution-per-second", "1", "", false}, - {"astronomical-unit", "meter", "149597900000", "", false}, - {"acre", "square-meter", "ft2m^2*43560", "", false}, - {"therm-us", "kilogram-square-meter-per-square-second", "105506000", "", false}, - {"pound-force", "kilogram-meter-per-square-second", "lb2kg*gravity", "", false}, - {"fathom", "meter", "ft2m*6", "", false}, - {"foot", "meter", "ft2m", "", false}, - {"furlong", "meter", "ft2m*660", "", false}, - {"inch", "meter", "ft2m/12", "", false}, - {"mile", "meter", "ft2m*5280", "", false}, - {"nautical-mile", "meter", "1852", "", false}, - {"yard", "meter", "ft2m*3", "", false}, - {"100-kilometer", "meter", "100000", "", false}, - {"ounce", "kilogram", "lb2kg/16", "", false}, - {"ounce-troy", "kilogram", "0.03110348", "", false}, - {"pound", "kilogram", "lb2kg", "", false}, - {"stone", "kilogram", "lb2kg*14", "", false}, - {"ton", "kilogram", "lb2kg*2000", "", false}, - {"horsepower", "kilogram-square-meter-per-cubic-second", "ft2m*lb2kg*gravity*550", "", false}, - {"inch-hg", "kilogram-per-meter-square-second", "3386.389", "", false}, - {"knot", "meter-per-second", "1852/3600", "", false}, + {"foodcalorie", "kilogram-square-meter-per-square-second", "4184", "0", false}, + {"hertz", "revolution-per-second", "1", "0", false}, + {"astronomical-unit", "meter", "149597900000", "0", false}, + {"acre", "square-meter", "ft2m^2*43560", "0", false}, + {"therm-us", "kilogram-square-meter-per-square-second", "105506000", "0", false}, + {"pound-force", "kilogram-meter-per-square-second", "lb2kg*gravity", "0", false}, + {"fathom", "meter", "ft2m*6", "0", false}, + {"foot", "meter", "ft2m", "0", false}, + {"furlong", "meter", "ft2m*660", "0", false}, + {"inch", "meter", "ft2m/12", "0", false}, + {"mile", "meter", "ft2m*5280", "0", false}, + {"nautical-mile", "meter", "1852", "0", false}, + {"yard", "meter", "ft2m*3", "0", false}, + {"100-kilometer", "meter", "100000", "0", false}, + {"ounce", "kilogram", "lb2kg/16", "0", false}, + {"ounce-troy", "kilogram", "0.03110348", "0", false}, + {"pound", "kilogram", "lb2kg", "0", false}, + {"stone", "kilogram", "lb2kg*14", "0", false}, + {"ton", "kilogram", "lb2kg*2000", "0", false}, + {"horsepower", "kilogram-square-meter-per-cubic-second", "ft2m*lb2kg*gravity*550", "0", false}, + {"inch-hg", "kilogram-per-meter-square-second", "3386.389", "0", false}, + {"knot", "meter-per-second", "1852/3600", "0", false}, {"fahrenheit", "kelvin", "5/9", "2298.35/9", false}, - {"barrel", "cubic-meter", "cup2m3*672", "", false}, - {"bushel", "cubic-meter", "0.03523907", "", false}, - {"cup", "cubic-meter", "cup2m3", "", false}, - {"fluid-ounce", "cubic-meter", "cup2m3/8", "", false}, - {"gallon", "cubic-meter", "cup2m3*16", "", false}, - {"tablespoon", "cubic-meter", "cup2m3/16", "", false}, - {"teaspoon", "cubic-meter", "cup2m3/48", "", false}, - {"karat", "portion", "1/24", "", false}, - {"pint", "cubic-meter", "cup2m3*2", "", false}, - {"quart", "cubic-meter", "cup2m3*4", "", false}, - {"fluid-ounce-imperial", "cubic-meter", "0.00002841306", "", false}, - {"gallon-imperial", "cubic-meter", "0.00454609", "", false}, - {"dunam", "square-meter", "1000", "", false}, - {"mile-scandinavian", "meter", "10000", "", false}, - {"hectare", "square-meter", "10000", "", false}, - {"joule", "kilogram-square-meter-per-square-second", "1", "", false}, - {"newton", "kilogram-meter-per-square-second", "1", "", false}, - {"carat", "kilogram", "0.0002", "", false}, - {"gram", "kilogram", "0.001", "", false}, - {"metric-ton", "kilogram", "1000", "", false}, - {"watt", "kilogram-square-meter-per-cubic-second", "1", "", false}, - {"bar", "kilogram-per-meter-square-second", "100000", "", false}, - {"pascal", "kilogram-per-meter-square-second", "1", "", false}, + {"barrel", "cubic-meter", "cup2m3*672", "0", false}, + {"bushel", "cubic-meter", "0.03523907", "0", false}, + {"cup", "cubic-meter", "cup2m3", "0", false}, + {"fluid-ounce", "cubic-meter", "cup2m3/8", "0", false}, + {"gallon", "cubic-meter", "cup2m3*16", "0", false}, + {"tablespoon", "cubic-meter", "cup2m3/16", "0", false}, + {"teaspoon", "cubic-meter", "cup2m3/48", "0", false}, + {"karat", "portion", "1/24", "0", false}, + {"pint", "cubic-meter", "cup2m3*2", "0", false}, + {"quart", "cubic-meter", "cup2m3*4", "0", false}, + {"fluid-ounce-imperial", "cubic-meter", "0.00002841306", "0", false}, + {"gallon-imperial", "cubic-meter", "0.00454609", "0", false}, + {"dunam", "square-meter", "1000", "0", false}, + {"mile-scandinavian", "meter", "10000", "0", false}, + {"hectare", "square-meter", "10000", "0", false}, + {"joule", "kilogram-square-meter-per-square-second", "1", "0", false}, + {"newton", "kilogram-meter-per-square-second", "1", "0", false}, + {"carat", "kilogram", "0.0002", "0", false}, + {"gram", "kilogram", "0.001", "0", false}, + {"metric-ton", "kilogram", "1000", "0", false}, + {"watt", "kilogram-square-meter-per-cubic-second", "1", "0", false}, + {"bar", "kilogram-per-meter-square-second", "100000", "0", false}, + {"pascal", "kilogram-per-meter-square-second", "1", "0", false}, {"celsius", "kelvin", "1", "-273.15", false}, - {"cup-metric", "cubic-meter", "0.00025", "", false}, - {"liter", "cubic-meter", "0.001", "", false}, - {"pint-metric", "cubic-meter", "0.0005", "", false}, - {"centimeter", "meter", "1/100", "", false}, - {"century", "year", "100", "", false}, - {"decade", "year", "10", "", false}, - {"dot", "pixel", "100", "", false}, - {"month", "year", "12", "", false}, - {"month-person", "year", "12", "", false}, - {"solar-luminosity", "kilogram-square-meter-per-cubic-second", "382800000000000000000000000", "", + {"cup-metric", "cubic-meter", "0.00025", "0", false}, + {"liter", "cubic-meter", "0.001", "0", false}, + {"pint-metric", "cubic-meter", "0.0005", "0", false}, + {"centimeter", "meter", "1/100", "0", false}, + {"century", "year", "100", "0", false}, + {"decade", "year", "10", "0", false}, + {"dot", "pixel", "100", "0", false}, + {"month", "year", "12", "0", false}, + {"month-person", "year", "12", "0", false}, + {"solar-luminosity", "kilogram-square-meter-per-cubic-second", "382800000000000000000000000", "0", false}, - {"solar-radius", "meter", "132712440000000000000/G", "", false}, - {"earth-radius", "meter", "6378100", "", false}, - {"solar-mass", "kilogram", "19884700000000000000000000000000", "", false}, - {"earth-mass", "kilogram", "5972200000000000000000000", "", false}, - {"year-person", "year", "1", "", false}, - {"part-per-million", "portion", "1/1000000", "", false}, - {"millimeter-of-mercury", "kilogram-per-meter-square-second", "10132500/760000", "", false}, - {"british-thermal-unit", "kilogram-square-meter-per-square-second", "1055.06", "", false}, - {"point", "meter", "ft2m/864", "", false}, - {"dalton", "kilogram-square-meter-per-square-second", "0.000000000149241808560", "", false}, - {"lux", "candela-square-meter-per-square-meter", "1", "", false}, + {"solar-radius", "meter", "132712440000000000000/G", "0", false}, + {"earth-radius", "meter", "6378100", "0", false}, + {"solar-mass", "kilogram", "19884700000000000000000000000000", "0", false}, + {"earth-mass", "kilogram", "5972200000000000000000000", "0", false}, + {"year-person", "year", "1", "0", false}, + {"part-per-million", "portion", "1/1000000", "0", false}, + {"millimeter-of-mercury", "kilogram-per-meter-square-second", "10132500/760000", "0", false}, + {"british-thermal-unit", "kilogram-square-meter-per-square-second", "1055.06", "0", false}, + {"point", "meter", "ft2m/864", "0", false}, + {"dalton", "kilogram-square-meter-per-square-second", "0.000000000149241808560", "0", false}, + {"lux", "candela-square-meter-per-square-meter", "1", "0", false}, }; } // namespace temporarily - - /** * Converts from a source `MeasureUnit` to a target `MeasureUnit`. */ diff --git a/icu4c/source/test/intltest/intltest.cpp b/icu4c/source/test/intltest/intltest.cpp index 5231d7e86db..097086ec95e 100644 --- a/icu4c/source/test/intltest/intltest.cpp +++ b/icu4c/source/test/intltest/intltest.cpp @@ -44,6 +44,7 @@ #include "udbgutil.h" #include "umutex.h" #include "uoptions.h" +#include "number_decnum.h" #ifdef XP_MAC_CONSOLE #include @@ -2155,18 +2156,12 @@ UBool IntlTest::assertEquals(const char* message, return TRUE; } -std::string decNumToString(const number::impl::DecNum& decNum) { - std::string result; - // TODO(younies): implement. - return result; -} - UBool IntlTest::assertEquals(const char* message, const number::impl::DecNum& expected, const number::impl::DecNum& actual) { UErrorCode status; if (!expected.equalTo(actual, status)) { - std::string expectedAsString = decNumToString(expected); - std::string actualAsString = decNumToString(actual); + std::string expectedAsString = expected.toString(status).data(); + std::string actualAsString = actual.toString(status).data(); errln((UnicodeString)"FAIL: " + message + "; got " + actualAsString.c_str() + "; expected " + expectedAsString.c_str()); @@ -2174,33 +2169,40 @@ UBool IntlTest::assertEquals(const char* message, } #ifdef VERBOSE_ASSERTIONS else { - logln((UnicodeString)"Ok: " + message + "; got " + decNumToString(actual).c_str()); + logln((UnicodeString)"Ok: " + message + "; got " + static_cast(actual.toString(status).data()).c_str()); } #endif return TRUE; } -UBool IntlTest::assertNearlyEquals(const char* message, - const number::impl::DecNum& expected, const number::impl::DecNum& actual, double precision){ - UErrorCode status; - double diff = std::abs( expected.toDouble(status) - actual.toDouble(status) ); +UBool IntlTest::assertEqualsNear(const char *message, const number::impl::DecNum &expected, + const number::impl::DecNum &actual, double precision) { + UErrorCode status = UErrorCode::U_ZERO_ERROR; + number::impl::DecNum difference; - if (!U_FAILURE(status) && diff <= precision) { - std::string expectedAsString = decNumToString(expected); - std::string actualAsString = decNumToString(actual); - errln((UnicodeString)"FAIL: " + message + - "; got " + actualAsString.c_str() + - "; expected " + expectedAsString.c_str()); + number::impl::DecNum decNumPrecision; + decNumPrecision.setTo(precision, status); + + difference.setTo(expected, status); + difference.subtract(actual, status); + if (difference.isNegative()) difference.multiplyBy(-1, status); + + if (difference.greaterThan(decNumPrecision, status) || U_FAILURE(status) || true) { + std::string expectedAsString = expected.toString(status).data(); + std::string actualAsString = actual.toString(status).data(); + errln((UnicodeString) "FAIL: " + message + "; got " + actualAsString.c_str() + "; expected " + + expectedAsString.c_str()); return FALSE; } #ifdef VERBOSE_ASSERTIONS else { - logln((UnicodeString)"Ok: " + message + "; got " + decNumToString(actual).c_str()); + logln((UnicodeString) "Ok: " + message + "; got " + + static_cast(actual.toString(status).data()).c_str()); } #endif return TRUE; } - + static char ASSERT_BUF[256]; static const char* extractToAssertBuf(const UnicodeString& message) { diff --git a/icu4c/source/test/intltest/intltest.h b/icu4c/source/test/intltest/intltest.h index dc771fdc260..964df7aa4f3 100644 --- a/icu4c/source/test/intltest/intltest.h +++ b/icu4c/source/test/intltest/intltest.h @@ -306,7 +306,7 @@ public: const std::vector& expected, const std::vector& actual); UBool assertEquals(const char* message, const number::impl::DecNum& expected, const number::impl::DecNum& actual); - UBool assertNearlyEquals(const char* message, + UBool assertEqualsNear(const char* message, const number::impl::DecNum& expected, const number::impl::DecNum& actual, double precision); #if !UCONFIG_NO_FORMATTING UBool assertEquals(const char* message, const Formattable& expected, diff --git a/icu4c/source/test/intltest/unitstest.cpp b/icu4c/source/test/intltest/unitstest.cpp index da980637ebf..a604c8c3157 100644 --- a/icu4c/source/test/intltest/unitstest.cpp +++ b/icu4c/source/test/intltest/unitstest.cpp @@ -7,6 +7,14 @@ #include "../../i18n/unitconverter.h" #include "intltest.h" +#include "number_decnum.h" + +struct UnitConversionTestCase { + const StringPiece source; + const StringPiece target; + const double inputValue; + const double expectedValue; +}; class UnitsTest : public IntlTest { public: @@ -21,8 +29,7 @@ class UnitsTest : public IntlTest { void testArea(); // TODO(younies): fix this. - void assertConversion(StringPiece message, StringPiece source, StringPiece target, double inputValue, - double expectedValue); + void verifyTestCase(const UnitConversionTestCase &testCase); }; extern IntlTest *createUnitsTest() { return new UnitsTest(); } @@ -40,22 +47,36 @@ void UnitsTest::runIndexedTest(int32_t index, UBool exec, const char *&name, cha TESTCASE_AUTO_END; } +void UnitsTest::verifyTestCase(const UnitConversionTestCase &testCase) { + UErrorCode status; + + MeasureUnit sourceUnit = MeasureUnit::forIdentifier(testCase.source, status); + MeasureUnit targetUnit = MeasureUnit::forIdentifier(testCase.target, status); + + UnitConverter converter(sourceUnit, targetUnit, status); + + number::impl::DecNum inputValue; + inputValue.setTo(testCase.inputValue, status); + + number::impl::DecNum expectedValue; + expectedValue.setTo(testCase.expectedValue, status); + + number::impl::DecNum actualConversionResult; + converter.convert(inputValue, actualConversionResult, status); + + assertEqualsNear("test Conversion", expectedValue, actualConversionResult, 0.01); +} + void UnitsTest::testBasic() { IcuTestErrorCode status(*this, "Units testBasic"); - // Test Cases - struct TestCase { - const StringPiece source; - const StringPiece target; - const double inputValue; - const double expectedValue; - } testCases[]{ + UnitConversionTestCase testCases[]{ {"meter", "foot", 1.0, 3.28084}, // {"kilometer", "foot", 1.0, 328.084} // }; for (const auto &testCase : testCases) { - UErrorCode status; + UErrorCode status = U_ZERO_ERROR; MeasureUnit sourceUnit = MeasureUnit::forIdentifier(testCase.source, status); MeasureUnit targetUnit = MeasureUnit::forIdentifier(testCase.target, status); @@ -71,19 +92,14 @@ void UnitsTest::testBasic() { number::impl::DecNum actualConversionResult; converter.convert(inputValue, actualConversionResult, status); - assertNearlyEquals("test Conversion", actualConversionResult, expectedValue, 0.01); + assertEqualsNear("test Conversion", expectedValue, actualConversionResult, 0.01); } } void UnitsTest::testSiPrefixes() { IcuTestErrorCode status(*this, "Units testSiPrefixes"); - // Test Cases - struct TestCase { - const StringPiece source; - const StringPiece target; - const double inputValue; - const double expectedValue; - } testCases[]{ + + UnitConversionTestCase testCases[]{ {"gram", "kilogram", 1.0, 0.001}, // {"milligram", "kilogram", 1.0, 0.000001}, // {"microgram", "kilogram", 1.0, 0.000000001}, // @@ -93,36 +109,14 @@ void UnitsTest::testSiPrefixes() { }; for (const auto &testCase : testCases) { - UErrorCode status; - - MeasureUnit sourceUnit = MeasureUnit::forIdentifier(testCase.source, status); - MeasureUnit targetUnit = MeasureUnit::forIdentifier(testCase.target, status); - - UnitConverter converter(sourceUnit, targetUnit, status); - - number::impl::DecNum inputValue; - inputValue.setTo(testCase.inputValue, status); - - number::impl::DecNum expectedValue; - expectedValue.setTo(testCase.expectedValue, status); - - number::impl::DecNum actualConversionResult; - converter.convert(inputValue, actualConversionResult, status); - - assertNearlyEquals("test Conversion", actualConversionResult, expectedValue, 0.01); + verifyTestCase(testCase); } } void UnitsTest::testMass() { IcuTestErrorCode status(*this, "Units testMass"); - // Test Cases - struct TestCase { - const StringPiece source; - const StringPiece target; - const double inputValue; - const double expectedValue; - } testCases[]{ + UnitConversionTestCase testCases[]{ {"gram", "kilogram", 1.0, 0.001}, // {"pound", "kilogram", 1.0, 0.453592}, // {"pound", "kilogram", 2.0, 0.907185}, // @@ -134,35 +128,14 @@ void UnitsTest::testMass() { }; for (const auto &testCase : testCases) { - UErrorCode status; - - MeasureUnit sourceUnit = MeasureUnit::forIdentifier(testCase.source, status); - MeasureUnit targetUnit = MeasureUnit::forIdentifier(testCase.target, status); - - UnitConverter converter(sourceUnit, targetUnit, status); - - number::impl::DecNum inputValue; - inputValue.setTo(testCase.inputValue, status); - - number::impl::DecNum expectedValue; - expectedValue.setTo(testCase.expectedValue, status); - - number::impl::DecNum actualConversionResult; - converter.convert(inputValue, actualConversionResult, status); - - assertNearlyEquals("test Conversion", actualConversionResult, expectedValue, 0.01); + verifyTestCase(testCase); } } void UnitsTest::testTemperature() { IcuTestErrorCode status(*this, "Units testTemperature"); - // Test Cases - struct TestCase { - const StringPiece source; - const StringPiece target; - const double inputValue; - const double expectedValue; - } testCases[]{ + + UnitConversionTestCase testCases[]{ {"celsius", "fahrenheit", 0.0, 32.0}, // {"celsius", "fahrenheit", 10.0, 50.0}, // {"fahrenheit", "celsius", 32.0, 0.0}, // @@ -174,36 +147,14 @@ void UnitsTest::testTemperature() { }; for (const auto &testCase : testCases) { - UErrorCode status; - - MeasureUnit sourceUnit = MeasureUnit::forIdentifier(testCase.source, status); - MeasureUnit targetUnit = MeasureUnit::forIdentifier(testCase.target, status); - - UnitConverter converter(sourceUnit, targetUnit, status); - - number::impl::DecNum inputValue; - inputValue.setTo(testCase.inputValue, status); - - number::impl::DecNum expectedValue; - expectedValue.setTo(testCase.expectedValue, status); - - number::impl::DecNum actualConversionResult; - converter.convert(inputValue, actualConversionResult, status); - - assertNearlyEquals("test Conversion", actualConversionResult, expectedValue, 0.01); + verifyTestCase(testCase); } } void UnitsTest::testArea() { IcuTestErrorCode status(*this, "Units Area"); - // Test Cases - struct TestCase { - const StringPiece source; - const StringPiece target; - const double inputValue; - const double expectedValue; - } testCases[]{ + UnitConversionTestCase testCases[]{ {"square-meter", "square-yard", 10.0, 11.9599} // , {"hectare", "square-yard", 1.0, 11959.9} // @@ -224,23 +175,7 @@ void UnitsTest::testArea() { }; for (const auto &testCase : testCases) { - UErrorCode status; - - MeasureUnit sourceUnit = MeasureUnit::forIdentifier(testCase.source, status); - MeasureUnit targetUnit = MeasureUnit::forIdentifier(testCase.target, status); - - UnitConverter converter(sourceUnit, targetUnit, status); - - number::impl::DecNum inputValue; - inputValue.setTo(testCase.inputValue, status); - - number::impl::DecNum expectedValue; - expectedValue.setTo(testCase.expectedValue, status); - - number::impl::DecNum actualConversionResult; - converter.convert(inputValue, actualConversionResult, status); - - assertNearlyEquals("test Conversion", actualConversionResult, expectedValue, 0.01); + verifyTestCase(testCase); } } -- 2.40.0