diff --git a/src/CalcViewModel/DataLoaders/CurrencyDataLoader.cpp b/src/CalcViewModel/DataLoaders/CurrencyDataLoader.cpp index 4bb4f727..6140b48d 100644 --- a/src/CalcViewModel/DataLoaders/CurrencyDataLoader.cpp +++ b/src/CalcViewModel/DataLoaders/CurrencyDataLoader.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" @@ -40,6 +40,8 @@ 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_MIN_DIGIT_COUNT = 4; +static constexpr int FORMATTER_RATE_MIN_MEANINGFULL_DIGITS = 2; static constexpr auto CACHE_TIMESTAMP_KEY = L"CURRENCY_CONVERTER_TIMESTAMP"; static constexpr auto CACHE_LANGCODE_KEY = L"CURRENCY_CONVERTER_LANGCODE"; @@ -203,7 +205,7 @@ void CurrencyDataLoader::LoadData() } } - co_return didLoad; + co_return didLoad; }).then([this](bool didLoad) { UpdateDisplayedTimestamp(); @@ -262,6 +264,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.000000003423 -> 0.0000000034, 0.000212 -> 0.00021 + int numberDecimals = FORMATTER_RATE_MIN_DIGIT_COUNT; + if (ratio < 1) + { + numberDecimals = max( + FORMATTER_RATE_MIN_DIGIT_COUNT, + (int)(-log10(ratio)) + FORMATTER_RATE_MIN_MEANINGFULL_DIGITS); + } + + 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 @@ -274,16 +293,10 @@ 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 roundedFormat = m_ratioFormatter->Format(rounded)->Data();; wstring digitSymbol = wstring{ LocalizationSettings::GetInstance().GetDigitSymbolFromEnUsDigit(L'1') }; - wstring roundedFormat = m_ratioFormatter->Format(rounded)->Data(); - wstring ratioString = LocalizationStringUtil::GetLocalizedString( m_ratioFormat.c_str(), digitSymbol.c_str(), @@ -329,7 +342,7 @@ task CurrencyDataLoader::TryLoadDataFromCacheAsync() { loadComplete = co_await TryLoadDataFromWebAsync(); } - + if (!loadComplete) { loadComplete = co_await TryFinishLoadFromCacheAsync(); @@ -578,7 +591,7 @@ bool CurrencyDataLoader::TryParseAllRatiosData(_In_ String^ rawJson, _Inout_ Cur relativeRatio, sourceCurrencyCode, targetCurrencyCode - }); + }); } return true; diff --git a/src/CalcViewModel/DataLoaders/CurrencyDataLoader.h b/src/CalcViewModel/DataLoaders/CurrencyDataLoader.h index cdb006bb..98f21e4f 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 @@ -71,6 +71,7 @@ namespace CalculatorApp std::pair GetCurrencySymbols(const UCM::Unit& unit1, const UCM::Unit& unit2) override; std::pair GetCurrencyRatioEquality(_In_ const UnitConversionManager::Unit& unit1, _In_ const UnitConversionManager::Unit& unit2) override; std::wstring GetCurrencyTimestamp() override; + static double RoundCurrencyRatio(double ratio); concurrency::task TryLoadDataFromCacheAsync() override; concurrency::task TryLoadDataFromWebAsync() override; @@ -87,7 +88,7 @@ namespace CalculatorApp bool TryParseWebResponses( _In_ Platform::String^ staticDataJson, - _In_ Platform::String^ allRatiosJson, + _In_ Platform::String^ allRatiosJson, _Inout_ std::vector& staticData, _Inout_ CurrencyRatioMap& allRatiosData); bool TryParseStaticData(_In_ Platform::String^ rawJson, _Inout_ std::vector& staticData); diff --git a/src/CalculatorUnitTests/CurrencyConverterUnitTests.cpp b/src/CalculatorUnitTests/CurrencyConverterUnitTests.cpp index 756e7085..34f705f6 100644 --- a/src/CalculatorUnitTests/CurrencyConverterUnitTests.cpp +++ b/src/CalculatorUnitTests/CurrencyConverterUnitTests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" @@ -597,5 +597,37 @@ namespace CalculatorUnitTests 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.0321); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.03219), 0.0322); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.003219), 0.0032); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.003269), 0.0033); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.000269), 0.00027); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.000069), 0.000069); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.000061), 0.000061); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.0000612), 0.000061); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.0000616), 0.000062); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.0000016), 0.0000016); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.0000016134324), 0.0000016); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.0000096134324), 0.0000096); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.00000169348392), 0.0000017); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.0000000034987218), 0.0000000035); + VERIFY_ARE_EQUAL(CurrencyDataLoader::RoundCurrencyRatio(0.0000000000000231445), 0.000000000000023); + } }; }