Optimize how we calculate the number of digits in the integer part and don't trim the value when used by the currency converter

This commit is contained in:
Rudy Huyn 2019-05-16 01:21:44 -07:00
commit ad7a9926a5
2 changed files with 49 additions and 38 deletions

View file

@ -848,7 +848,7 @@ void UnitConverter::Calculate()
} }
unordered_map<Unit, ConversionData, UnitHash> conversionTable = m_ratioMap[m_fromType]; unordered_map<Unit, ConversionData, UnitHash> conversionTable = m_ratioMap[m_fromType];
if (AnyUnitIsEmpty() || (conversionTable[m_toType].ratio == 1.0 && conversionTable[m_toType].offset == 0.0)) if (AnyUnitIsEmpty() || (conversionTable[m_toType].ratio == 1.0 && conversionTable[m_toType].offset == 0.0))
{ {
m_returnDisplay = m_currentDisplay; m_returnDisplay = m_currentDisplay;
m_returnHasDecimal = m_currentHasDecimal; m_returnHasDecimal = m_currentHasDecimal;
@ -858,50 +858,41 @@ void UnitConverter::Calculate()
{ {
double currentValue = stod(m_currentDisplay); double currentValue = stod(m_currentDisplay);
double returnValue = Convert(currentValue, conversionTable[m_toType]); double returnValue = Convert(currentValue, conversionTable[m_toType]);
m_returnDisplay = RoundSignificant(returnValue, MAXIMUMDIGITSALLOWED);
TrimString(m_returnDisplay);
int numPreDecimal = (int)m_returnDisplay.size();
if (m_returnDisplay.find(L'.') != m_returnDisplay.npos)
{
numPreDecimal = (int)m_returnDisplay.find(L'.');
}
if (returnValue < 0)
{
numPreDecimal--;
}
if (numPreDecimal > MAXIMUMDIGITSALLOWED || (returnValue != 0 && abs(returnValue) < MINIMUMDECIMALALLOWED)) auto isCurrencyConverter = m_currencyDataLoader != nullptr && m_currencyDataLoader->SupportsCategory(this->m_currentCategory);
if (isCurrencyConverter)
{ {
wstringstream out(wstringstream::out); // We don't need to trim the value when it's a currency.
out << scientific << returnValue; m_returnDisplay = RoundSignificant(returnValue, MAXIMUMDIGITSALLOWED);
m_returnDisplay = out.str(); TrimString(m_returnDisplay);
} }
else else
{ {
returnValue = stod(m_returnDisplay); int numPreDecimal = returnValue == 0 ? 0 : (1 + (int)log10(abs(returnValue)));
if (numPreDecimal > MAXIMUMDIGITSALLOWED || (returnValue != 0 && abs(returnValue) < MINIMUMDECIMALALLOWED))
auto currentDisplayTrimmed = m_currentDisplay;
TrimString(currentDisplayTrimmed);
int currentNumberSignificantDigits = static_cast<int>(currentDisplayTrimmed.size());
if (currentDisplayTrimmed.find(L'.') != currentDisplayTrimmed.npos)
--currentNumberSignificantDigits;
if (currentValue < 0)
--currentNumberSignificantDigits;
int precision = 0;
if (abs(returnValue) < OPTIMALDECIMALALLOWED)
{ {
precision = MAXIMUMDIGITSALLOWED; wstringstream out(wstringstream::out);
out << scientific << returnValue;
m_returnDisplay = out.str();
} }
else else
{ {
precision = max(0, max(OPTIMALDIGITSALLOWED, min(MAXIMUMDIGITSALLOWED, currentNumberSignificantDigits)) - numPreDecimal); int currentNumberSignificantDigits = GetNumberSignificantDigits(m_currentDisplay);
int precision = 0;
if (abs(returnValue) < OPTIMALDECIMALALLOWED)
{
precision = MAXIMUMDIGITSALLOWED;
}
else
{
precision = max(0, max(OPTIMALDIGITSALLOWED, min(MAXIMUMDIGITSALLOWED, currentNumberSignificantDigits)) - numPreDecimal);
}
m_returnDisplay = RoundSignificant(returnValue, precision);
TrimString(m_returnDisplay);
} }
m_returnHasDecimal = (m_returnDisplay.find(L'.') != m_returnDisplay.npos);
m_returnDisplay = RoundSignificant(returnValue, precision);
TrimString(m_returnDisplay);
} }
m_returnHasDecimal = (m_returnDisplay.find(L'.') != m_returnDisplay.npos);
} }
UpdateViewModel(); UpdateViewModel();
} }
@ -910,9 +901,9 @@ void UnitConverter::Calculate()
/// Trims out any trailing zeros or decimals in the given input string /// Trims out any trailing zeros or decimals in the given input string
/// </summary> /// </summary>
/// <param name="input">wstring to trim</param> /// <param name="input">wstring to trim</param>
void UnitConverter::TrimString(wstring& returnString) void UnitConverter::TrimString(_Inout_ wstring& returnString)
{ {
if (returnString.find(L'.') == m_returnDisplay.npos) if (returnString.find(L'.') == returnString.npos)
{ {
return; return;
} }
@ -932,6 +923,24 @@ void UnitConverter::TrimString(wstring& returnString)
} }
} }
/// <summary>
/// Get number of significant digits (integer part + fractional part) of a number</summary>
/// <param name="value">the number</param>
unsigned int UnitConverter::GetNumberSignificantDigits(std::wstring value)
{
TrimString(value);
int currentNumberSignificantDigits = value.size();
if (value.find(L'.') != value.npos)
{
--currentNumberSignificantDigits;
}
if (value.find(L'-') != value.npos)
{
--currentNumberSignificantDigits;
}
return currentNumberSignificantDigits;
}
/// <summary> /// <summary>
/// Rounds the given double to the given number of significant digits /// Rounds the given double to the given number of significant digits
/// </summary> /// </summary>

View file

@ -279,9 +279,7 @@ namespace UnitConversionManager
double Convert(double value, ConversionData conversionData); double Convert(double value, ConversionData conversionData);
std::vector<std::tuple<std::wstring, Unit>> CalculateSuggested(); std::vector<std::tuple<std::wstring, Unit>> CalculateSuggested();
void ClearValues(); void ClearValues();
void TrimString(std::wstring& input);
void InitializeSelectedUnits(); void InitializeSelectedUnits();
std::wstring RoundSignificant(double num, int numSignificant);
Category StringToCategory(const std::wstring& w); Category StringToCategory(const std::wstring& w);
std::wstring CategoryToString(const Category& c, const wchar_t* delimiter); std::wstring CategoryToString(const Category& c, const wchar_t* delimiter);
std::wstring UnitToString(const Unit& u, const wchar_t* delimiter); std::wstring UnitToString(const Unit& u, const wchar_t* delimiter);
@ -292,6 +290,10 @@ namespace UnitConversionManager
std::shared_ptr<IConverterDataLoader> GetDataLoaderForCategory(const Category& category); std::shared_ptr<IConverterDataLoader> GetDataLoaderForCategory(const Category& category);
std::shared_ptr<ICurrencyConverterDataLoader> GetCurrencyConverterDataLoader(); std::shared_ptr<ICurrencyConverterDataLoader> GetCurrencyConverterDataLoader();
static void TrimString(_Inout_ std::wstring& input);
static unsigned int GetNumberSignificantDigits(std::wstring value);
static std::wstring RoundSignificant(double num, int numSignificant);
private: private:
std::shared_ptr<IConverterDataLoader> m_dataLoader; std::shared_ptr<IConverterDataLoader> m_dataLoader;
std::shared_ptr<IConverterDataLoader> m_currencyDataLoader; std::shared_ptr<IConverterDataLoader> m_currencyDataLoader;