diff --git a/src/CalcManager/CalcManager.vcxproj b/src/CalcManager/CalcManager.vcxproj
index 4d03a5c9..df999574 100644
--- a/src/CalcManager/CalcManager.vcxproj
+++ b/src/CalcManager/CalcManager.vcxproj
@@ -309,6 +309,7 @@
+
@@ -349,6 +350,7 @@
Create
Create
+
diff --git a/src/CalcManager/CalcManager.vcxproj.filters b/src/CalcManager/CalcManager.vcxproj.filters
index 2ca11666..53098917 100644
--- a/src/CalcManager/CalcManager.vcxproj.filters
+++ b/src/CalcManager/CalcManager.vcxproj.filters
@@ -89,6 +89,7 @@
CEngine
+
@@ -160,5 +161,6 @@
Header Files
+
-
+
\ No newline at end of file
diff --git a/src/CalcManager/NumberFormattingUtils.cpp b/src/CalcManager/NumberFormattingUtils.cpp
new file mode 100644
index 00000000..720335ad
--- /dev/null
+++ b/src/CalcManager/NumberFormattingUtils.cpp
@@ -0,0 +1,85 @@
+#include "pch.h"
+#include "NumberFormattingUtils.h"
+#include
+#include
+using namespace std;
+
+namespace CalculationManager::NumberFormattingUtils
+{
+ ///
+ /// Trims out any trailing zeros or decimals in the given input string
+ ///
+ /// number to trim
+ void TrimTrailingZeros(_Inout_ wstring& number)
+ {
+ if (number.find(L'.') == wstring::npos)
+ {
+ return;
+ }
+
+ wstring::iterator iter;
+ for (iter = number.end() - 1;; iter--)
+ {
+ if (*iter != L'0')
+ {
+ number.erase(iter + 1, number.end());
+ break;
+ }
+ }
+ if (*(number.end() - 1) == L'.')
+ {
+ number.erase(number.end() - 1, number.end());
+ }
+ }
+
+ ///
+ /// Get number of digits (whole number part + decinmal part)
+ /// the number
+ unsigned int GetNumberDigits(wstring value)
+ {
+ TrimTrailingZeros(value);
+ unsigned int numberSignificantDigits = static_cast(value.size());
+ if (value.find(L'.') != wstring::npos)
+ {
+ --numberSignificantDigits;
+ }
+ if (value.find(L'-') != wstring::npos)
+ {
+ --numberSignificantDigits;
+ }
+ return numberSignificantDigits;
+ }
+
+ ///
+ /// Get number of digits (whole number part only)
+ /// the number
+ unsigned int GetNumberDigitsWholeNumberPart(double value)
+ {
+ return value == 0 ? 1 : (1 + (int)log10(abs(value)));
+ }
+
+ ///
+ /// Rounds the given double to the given number of significant digits
+ ///
+ /// input double
+ /// int number of significant digits to round to
+ wstring RoundSignificantDigits(double num, int numSignificant)
+ {
+ wstringstream out(wstringstream::out);
+ out << fixed;
+ out.precision(numSignificant);
+ out << num;
+ return out.str();
+ }
+
+ ///
+ /// Convert a Number to Scientific Notation
+ ///
+ /// number to convert
+ wstring ToScientificNumber(double number)
+ {
+ wstringstream out(wstringstream::out);
+ out << scientific << number;
+ return out.str();
+ }
+}
diff --git a/src/CalcManager/NumberFormattingUtils.h b/src/CalcManager/NumberFormattingUtils.h
new file mode 100644
index 00000000..896ecd76
--- /dev/null
+++ b/src/CalcManager/NumberFormattingUtils.h
@@ -0,0 +1,15 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include
+
+namespace CalculationManager::NumberFormattingUtils
+{
+ void TrimTrailingZeros(_Inout_ std::wstring& input);
+ unsigned int GetNumberDigits(std::wstring value);
+ unsigned int GetNumberDigitsWholeNumberPart(double value);
+ std::wstring RoundSignificantDigits(double value, int numberSignificantDigits);
+ std::wstring ToScientificNumber(double number);
+}
diff --git a/src/CalcManager/UnitConverter.cpp b/src/CalcManager/UnitConverter.cpp
index 46b84ea3..3784d65e 100644
--- a/src/CalcManager/UnitConverter.cpp
+++ b/src/CalcManager/UnitConverter.cpp
@@ -6,10 +6,12 @@
#include // for std::sort
#include "Command.h"
#include "UnitConverter.h"
+#include "NumberFormattingUtils.h"
using namespace concurrency;
using namespace std;
using namespace UnitConversionManager;
+using namespace CalculationManager::NumberFormattingUtils;
static constexpr uint32_t EXPECTEDSERIALIZEDCATEGORYTOKENCOUNT = 3;
static constexpr uint32_t EXPECTEDSERIALIZEDUNITTOKENCOUNT = 6;
@@ -633,19 +635,19 @@ vector> UnitConverter::CalculateSuggested()
wstring roundedString;
if (abs(entry.value) < 100)
{
- roundedString = RoundSignificant(entry.value, 2);
+ roundedString = RoundSignificantDigits(entry.value, 2);
}
else if (abs(entry.value) < 1000)
{
- roundedString = RoundSignificant(entry.value, 1);
+ roundedString = RoundSignificantDigits(entry.value, 1);
}
else
{
- roundedString = RoundSignificant(entry.value, 0);
+ roundedString = RoundSignificantDigits(entry.value, 0);
}
if (stod(roundedString) != 0.0 || m_currentCategory.supportsNegative)
{
- TrimString(roundedString);
+ TrimTrailingZeros(roundedString);
returnVector.push_back(make_tuple(roundedString, entry.type));
}
}
@@ -671,21 +673,21 @@ vector> UnitConverter::CalculateSuggested()
wstring roundedString;
if (abs(entry.value) < 100)
{
- roundedString = RoundSignificant(entry.value, 2);
+ roundedString = RoundSignificantDigits(entry.value, 2);
}
else if (abs(entry.value) < 1000)
{
- roundedString = RoundSignificant(entry.value, 1);
+ roundedString = RoundSignificantDigits(entry.value, 1);
}
else
{
- roundedString = RoundSignificant(entry.value, 0);
+ roundedString = RoundSignificantDigits(entry.value, 0);
}
// How to work out which is the best whimsical value to add to the vector?
if (stod(roundedString) != 0.0)
{
- TrimString(roundedString);
+ TrimTrailingZeros(roundedString);
whimsicalReturnVector.push_back(make_tuple(roundedString, entry.type));
}
}
@@ -842,7 +844,7 @@ void UnitConverter::Calculate()
{
m_returnDisplay = m_currentDisplay;
m_returnHasDecimal = m_currentHasDecimal;
- TrimString(m_returnDisplay);
+ TrimTrailingZeros(m_returnDisplay);
UpdateViewModel();
return;
}
@@ -852,7 +854,7 @@ void UnitConverter::Calculate()
{
m_returnDisplay = m_currentDisplay;
m_returnHasDecimal = m_currentHasDecimal;
- TrimString(m_returnDisplay);
+ TrimTrailingZeros(m_returnDisplay);
}
else
{
@@ -863,21 +865,19 @@ void UnitConverter::Calculate()
if (isCurrencyConverter)
{
// We don't need to trim the value when it's a currency.
- m_returnDisplay = RoundSignificant(returnValue, MAXIMUMDIGITSALLOWED);
- TrimString(m_returnDisplay);
+ m_returnDisplay = RoundSignificantDigits(returnValue, MAXIMUMDIGITSALLOWED);
+ TrimTrailingZeros(m_returnDisplay);
}
else
{
- int numPreDecimal = returnValue == 0 ? 0 : (1 + (int)log10(abs(returnValue)));
+ int numPreDecimal = GetNumberDigitsWholeNumberPart(returnValue);
if (numPreDecimal > MAXIMUMDIGITSALLOWED || (returnValue != 0 && abs(returnValue) < MINIMUMDECIMALALLOWED))
{
- wstringstream out(wstringstream::out);
- out << scientific << returnValue;
- m_returnDisplay = out.str();
+ m_returnDisplay = ToScientificNumber(returnValue);
}
else
{
- int currentNumberSignificantDigits = GetNumberSignificantDigits(m_currentDisplay);
+ int currentNumberSignificantDigits = GetNumberDigits(m_currentDisplay);
int precision = 0;
if (abs(returnValue) < OPTIMALDECIMALALLOWED)
{
@@ -888,8 +888,8 @@ void UnitConverter::Calculate()
precision = max(0, max(OPTIMALDIGITSALLOWED, min(MAXIMUMDIGITSALLOWED, currentNumberSignificantDigits)) - numPreDecimal);
}
- m_returnDisplay = RoundSignificant(returnValue, precision);
- TrimString(m_returnDisplay);
+ m_returnDisplay = RoundSignificantDigits(returnValue, precision);
+ TrimTrailingZeros(m_returnDisplay);
}
m_returnHasDecimal = (m_returnDisplay.find(L'.') != wstring::npos);
}
@@ -897,64 +897,6 @@ void UnitConverter::Calculate()
UpdateViewModel();
}
-///
-/// Trims out any trailing zeros or decimals in the given input string
-///
-/// wstring to trim
-void UnitConverter::TrimString(_Inout_ wstring& returnString)
-{
- if (returnString.find(L'.') == returnString.npos)
- {
- return;
- }
-
- wstring::iterator iter;
- for (iter = returnString.end() - 1;; iter--)
- {
- if (*iter != L'0')
- {
- returnString.erase(iter + 1, returnString.end());
- break;
- }
- }
- if (*(returnString.end() - 1) == L'.')
- {
- returnString.erase(returnString.end() - 1, returnString.end());
- }
-}
-
-///
-/// Get number of significant digits (integer part + fractional part) of a number
-/// the number
-unsigned int UnitConverter::GetNumberSignificantDigits(std::wstring value)
-{
- TrimString(value);
- unsigned int numberSignificantDigits = static_cast(value.size());
- if (value.find(L'.') != wstring::npos)
- {
- --numberSignificantDigits;
- }
- if (value.find(L'-') != wstring::npos)
- {
- --numberSignificantDigits;
- }
- return numberSignificantDigits;
-}
-
-///
-/// Rounds the given double to the given number of significant digits
-///
-/// input double
-/// int number of significant digits to round to
-wstring UnitConverter::RoundSignificant(double num, int numSignificant)
-{
- wstringstream out(wstringstream::out);
- out << fixed;
- out.precision(numSignificant);
- out << num;
- return out.str();
-}
-
void UnitConverter::UpdateCurrencySymbols()
{
if (m_currencyDataLoader != nullptr && m_vmCurrencyCallback != nullptr)
diff --git a/src/CalcManager/UnitConverter.h b/src/CalcManager/UnitConverter.h
index 58712386..e8c26d38 100644
--- a/src/CalcManager/UnitConverter.h
+++ b/src/CalcManager/UnitConverter.h
@@ -290,10 +290,6 @@ namespace UnitConversionManager
std::shared_ptr GetDataLoaderForCategory(const Category& category);
std::shared_ptr GetCurrencyConverterDataLoader();
- static void TrimString(_Inout_ std::wstring& input);
- static unsigned int GetNumberSignificantDigits(std::wstring value);
- static std::wstring RoundSignificant(double num, int numSignificant);
-
private:
std::shared_ptr m_dataLoader;
std::shared_ptr m_currencyDataLoader;
diff --git a/src/CalculatorUnitTests/CalculatorManagerTest.cpp b/src/CalculatorUnitTests/CalculatorManagerTest.cpp
index a2ed8127..5f46258c 100644
--- a/src/CalculatorUnitTests/CalculatorManagerTest.cpp
+++ b/src/CalculatorUnitTests/CalculatorManagerTest.cpp
@@ -7,9 +7,11 @@
#include "CalcManager/CalculatorHistory.h"
#include "CalcViewModel/Common/EngineResourceProvider.h"
+#include "CalcManager/NumberFormattingUtils.h"
using namespace CalculatorApp;
using namespace CalculationManager;
+using namespace CalculationManager::NumberFormattingUtils;
using namespace Platform;
using namespace std;
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
@@ -185,6 +187,11 @@ namespace CalculatorManagerTest
TEST_METHOD(CalculatorManagerTestMaxDigitsReached_LeadingDecimal);
TEST_METHOD(CalculatorManagerTestMaxDigitsReached_TrailingDecimal);
+ TEST_METHOD(CalculatorManagerNumberFormattingUtils_TrimTrailingZeros);
+ TEST_METHOD(CalculatorManagerNumberFormattingUtils_GetNumberDigits);
+ TEST_METHOD(CalculatorManagerNumberFormattingUtils_GetNumberDigitsWholeNumberPart);
+ TEST_METHOD(CalculatorManagerNumberFormattingUtils_RoundSignificantDigits);
+ TEST_METHOD(CalculatorManagerNumberFormattingUtils_ToScientificNumber);
// TODO re-enable when cause of failure is determined. Bug 20226670
// TEST_METHOD(CalculatorManagerTestBinaryOperatorReceived);
// TEST_METHOD(CalculatorManagerTestBinaryOperatorReceived_Multiple);
@@ -807,6 +814,102 @@ namespace CalculatorManagerTest
TestMaxDigitsReachedScenario(L"123,456,789,101,112.13");
}
+ void CalculatorManagerTest::CalculatorManagerNumberFormattingUtils_TrimTrailingZeros()
+ {
+ wstring number = L"2.1032100000000";
+ TrimTrailingZeros(number);
+ VERIFY_ARE_EQUAL(number, L"2.10321");
+ number = L"-122.123200";
+ TrimTrailingZeros(number);
+ VERIFY_ARE_EQUAL(number, L"-122.1232");
+ number = L"0.0001200";
+ TrimTrailingZeros(number);
+ VERIFY_ARE_EQUAL(number, L"0.00012");
+ number = L"12.000";
+ TrimTrailingZeros(number);
+ VERIFY_ARE_EQUAL(number, L"12");
+ number = L"-12.00000";
+ TrimTrailingZeros(number);
+ VERIFY_ARE_EQUAL(number, L"-12");
+ number = L"0.000";
+ TrimTrailingZeros(number);
+ VERIFY_ARE_EQUAL(number, L"0");
+ number = L"322423";
+ TrimTrailingZeros(number);
+ VERIFY_ARE_EQUAL(number, L"322423");
+ }
+
+ void CalculatorManagerTest::CalculatorManagerNumberFormattingUtils_GetNumberDigits()
+ {
+ wstring number = L"2.10321";
+ unsigned int digitsCount = GetNumberDigits(number);
+ VERIFY_ARE_EQUAL(digitsCount, 6);
+ number = L"-122.1232";
+ digitsCount = GetNumberDigits(number);
+ VERIFY_ARE_EQUAL(digitsCount, 7);
+ number = L"-3432";
+ digitsCount = GetNumberDigits(number);
+ VERIFY_ARE_EQUAL(digitsCount, 4);
+ number = L"0";
+ digitsCount = GetNumberDigits(number);
+ VERIFY_ARE_EQUAL(digitsCount, 1);
+ number = L"0.0001223";
+ digitsCount = GetNumberDigits(number);
+ VERIFY_ARE_EQUAL(digitsCount, 8);
+ }
+
+ void CalculatorManagerTest::CalculatorManagerNumberFormattingUtils_GetNumberDigitsWholeNumberPart()
+ {
+ unsigned int digitsCount = GetNumberDigitsWholeNumberPart(2.10321);
+ VERIFY_ARE_EQUAL(digitsCount, 1);
+ digitsCount = GetNumberDigitsWholeNumberPart(-122.1232);
+ VERIFY_ARE_EQUAL(digitsCount, 3);
+ digitsCount = GetNumberDigitsWholeNumberPart(-3432);
+ VERIFY_ARE_EQUAL(digitsCount, 4);
+ digitsCount = GetNumberDigitsWholeNumberPart(0);
+ VERIFY_ARE_EQUAL(digitsCount, 1);
+ digitsCount = GetNumberDigitsWholeNumberPart(324328412837382);
+ VERIFY_ARE_EQUAL(digitsCount, 15);
+ digitsCount = GetNumberDigitsWholeNumberPart(324328412837382.232213214324234);
+ VERIFY_ARE_EQUAL(digitsCount, 15);
+ }
+
+ void CalculatorManagerTest::CalculatorManagerNumberFormattingUtils_RoundSignificantDigits()
+ {
+ wstring result = RoundSignificantDigits(12.342343242, 3);
+ VERIFY_ARE_EQUAL(result, L"12.342");
+ result = RoundSignificantDigits(12.3429999, 3);
+ VERIFY_ARE_EQUAL(result, L"12.343");
+ result = RoundSignificantDigits(12.342500001, 3);
+ VERIFY_ARE_EQUAL(result, L"12.343");
+ result = RoundSignificantDigits(-2312.1244243346454345, 5);
+ VERIFY_ARE_EQUAL(result, L"-2312.12442");
+ result = RoundSignificantDigits(0.3423432423, 5);
+ VERIFY_ARE_EQUAL(result, L"0.34234");
+ result = RoundSignificantDigits(0.3423, 7);
+ VERIFY_ARE_EQUAL(result, L"0.3423000");
+ }
+
+ void CalculatorManagerTest::CalculatorManagerNumberFormattingUtils_ToScientificNumber()
+ {
+ wstring result = ToScientificNumber(3423);
+ VERIFY_ARE_EQUAL(result, L"3.423000e+03");
+ result = ToScientificNumber(-21);
+ VERIFY_ARE_EQUAL(result, L"-2.100000e+01");
+ result = ToScientificNumber(0.0232);
+ VERIFY_ARE_EQUAL(result, L"2.320000e-02");
+ result = ToScientificNumber(-0.00921);
+ VERIFY_ARE_EQUAL(result, L"-9.210000e-03");
+ result = ToScientificNumber(2343243345677);
+ VERIFY_ARE_EQUAL(result, L"2.343243e+12");
+ result = ToScientificNumber(-3432474247332942);
+ VERIFY_ARE_EQUAL(result, L"-3.432474e+15");
+ result = ToScientificNumber(0.000000003432432);
+ VERIFY_ARE_EQUAL(result, L"3.432432e-09");
+ result = ToScientificNumber(-0.000000003432432);
+ VERIFY_ARE_EQUAL(result, L"-3.432432e-09");
+ }
+
// TODO re-enable when cause of failure is determined. Bug 20226670
// void CalculatorManagerTest::CalculatorManagerTestBinaryOperatorReceived()
// {