diff --git a/src/CalcViewModel/DataLoaders/CurrencyDataLoader.cpp b/src/CalcViewModel/DataLoaders/CurrencyDataLoader.cpp index 1e83736..5180de4 100644 --- a/src/CalcViewModel/DataLoaders/CurrencyDataLoader.cpp +++ b/src/CalcViewModel/DataLoaders/CurrencyDataLoader.cpp @@ -39,7 +39,9 @@ static constexpr auto CURRENCY_UNIT_TO_KEY = L"CURRENCY_UNIT_TO_KEY"; static constexpr long long DAY_DURATION = 1LL * 60 * 60 * 24 * 10000000; static constexpr long long WEEK_DURATION = DAY_DURATION * 7; -static constexpr int FORMATTER_DIGIT_COUNT = 4; +static constexpr int FORMATTER_RATE_FRACTION_PADDING = 2; +static constexpr int FORMATTER_RATE_MIN_DECIMALS = 4; +static constexpr int FORMATTER_RATE_MIN_SIGNIFICANT_DECIMALS = 4; static constexpr auto CACHE_TIMESTAMP_KEY = L"CURRENCY_CONVERTER_TIMESTAMP"; static constexpr auto CACHE_LANGCODE_KEY = L"CURRENCY_CONVERTER_LANGCODE"; @@ -128,7 +130,7 @@ CurrencyDataLoader::CurrencyDataLoader(_In_ unique_ptr clie m_ratioFormatter = localizationService->GetRegionalSettingsAwareDecimalFormatter(); m_ratioFormatter->IsGrouped = true; m_ratioFormatter->IsDecimalPointAlwaysDisplayed = true; - m_ratioFormatter->FractionDigits = FORMATTER_DIGIT_COUNT; + m_ratioFormatter->FractionDigits = FORMATTER_RATE_FRACTION_PADDING; m_ratioFormat = AppResourceProvider::GetInstance().GetResourceString(L"CurrencyFromToRatioFormat")->Data(); m_timestampFormat = AppResourceProvider::GetInstance().GetResourceString(L"CurrencyTimestampFormat")->Data(); @@ -267,6 +269,23 @@ pair CurrencyDataLoader::GetCurrencySymbols(const UCM::Unit& u return make_pair(symbol1, symbol2); } +double CurrencyDataLoader::RoundCurrencyRatio(double ratio) +{ + // Compute how many decimals we need to display two meaningful digits at minimum + // For example: 0.00000000342334 -> 0.000000003423, 0.000212 -> 0.000212 + int numberDecimals = FORMATTER_RATE_MIN_DECIMALS; + if (ratio < 1) + { + numberDecimals = max( + FORMATTER_RATE_MIN_DECIMALS, + (int)(-log10(ratio)) + FORMATTER_RATE_MIN_SIGNIFICANT_DECIMALS); + } + + unsigned long long scale = (unsigned long long)powl(10l, numberDecimals); + + return (double)(round(ratio * scale) / scale); +} + pair CurrencyDataLoader::GetCurrencyRatioEquality(_In_ const UCM::Unit& unit1, _In_ const UCM::Unit& unit2) { try @@ -279,12 +298,7 @@ pair CurrencyDataLoader::GetCurrencyRatioEquality(_In_ const U if (iter2 != ratioMap.end()) { double ratio = (iter2->second).ratio; - - // Round the ratio to FORMATTER_DIGIT_COUNT digits using int math. - // Ex: to round 1.23456 to three digits, use - // ((int) 1.23456 * (10^3)) / (10^3) - double scale = pow(10, FORMATTER_DIGIT_COUNT); - double rounded = static_cast(ratio * static_cast(scale)) / scale; + double rounded = RoundCurrencyRatio(ratio); wstring digitSymbol = wstring{ LocalizationSettings::GetInstance().GetDigitSymbolFromEnUsDigit(L'1') }; wstring roundedFormat = m_ratioFormatter->Format(rounded)->Data(); diff --git a/src/CalcViewModel/DataLoaders/CurrencyDataLoader.h b/src/CalcViewModel/DataLoaders/CurrencyDataLoader.h index a4be2d0..7a28c6c 100644 --- a/src/CalcViewModel/DataLoaders/CurrencyDataLoader.h +++ b/src/CalcViewModel/DataLoaders/CurrencyDataLoader.h @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #pragma once @@ -75,6 +75,7 @@ namespace CalculatorApp std::pair GetCurrencyRatioEquality(_In_ const UnitConversionManager::Unit& unit1, _In_ const UnitConversionManager::Unit& unit2) override; std::wstring GetCurrencyTimestamp() override; + static double RoundCurrencyRatio(double ratio); std::future TryLoadDataFromCacheAsync() override; std::future TryLoadDataFromWebAsync() override; diff --git a/src/CalculatorUnitTests/CurrencyConverterUnitTests.cpp b/src/CalculatorUnitTests/CurrencyConverterUnitTests.cpp index 9b20184..8c6f5e2 100644 --- a/src/CalculatorUnitTests/CurrencyConverterUnitTests.cpp +++ b/src/CalculatorUnitTests/CurrencyConverterUnitTests.cpp @@ -590,6 +590,38 @@ TEST_METHOD(Loaded_GetCurrencyRatioEquality_Invalid) VERIFY_ARE_EQUAL(wstring(L""), ratio.first); VERIFY_ARE_EQUAL(wstring(L""), ratio.second); } + +TEST_METHOD(Test_RoundCurrencyRatio) +{ + CurrencyDataLoader loader{ nullptr }; + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(1234567), 1234567); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0), 0); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(9999.999), 9999.999); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(8765.4321), 8765.4321); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(4815.162342), 4815.1623); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(4815.162358), 4815.1624); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(4815.162388934723), 4815.1624); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.12), 0.12); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.123), 0.123); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.1234), 0.1234); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.12343), 0.1234); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.0321), 0.0321); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.03211), 0.03211); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.032119), 0.03212); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.00322119), 0.003221); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.00123269), 0.001233); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.00076269), 0.0007627); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.000069), 0.000069); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.000061), 0.000061); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.000054612), 0.00005461); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.000054616), 0.00005462); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.000005416), 0.000005416); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.0000016134324), 0.000001613); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.0000096134324), 0.000009613); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.0000032169348392), 0.000003217); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.000000002134987218), 0.000000002135); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.000000000000087231445), 0.00000000000008723); +} } ; }