Merge master into feature/GraphingCalculator branch (#585)

* Merge master into feature/GraphingCalculator branch
This commit is contained in:
Stephanie Anderl
2019-07-15 11:17:21 -07:00
committed by GitHub
parent 1475b49120
commit a418777f02
447 changed files with 18056 additions and 19323 deletions

View File

@@ -0,0 +1,14 @@
target_sources(CalcManager PRIVATE
calc.cpp
CalcInput.cpp
CalcUtils.cpp
History.cpp
Number.cpp
Rational.cpp
RationalMath.cpp
scicomm.cpp
scidisp.cpp
scifunc.cpp
scioper.cpp
sciset.cpp
)

View File

@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include <sstream>
#include "Header Files/CalcEngine.h"
using namespace std;
@@ -124,15 +124,15 @@ bool CalcInput::TryAddDigit(unsigned int value, uint32_t radix, bool isIntegerMo
else if (radix == 10)
{
// If value length is at least the max, we know we can't add another digit.
if(pNumSec->value.size() < maxNumStr.size())
if (pNumSec->value.size() < maxNumStr.size())
{
// Compare value to substring of maxNumStr of value.size() length.
// If cmpResult > 0:
// eg. max is "127", and the current number is "20". first digit itself says we are out.
// eg. max is "127", and the current number is "20". first digit itself says we are out.
// Additional digit is not possible
// If cmpResult < 0:
// Success case. eg. max is "127", and current number is say "11". The second digit '1' being <
// Success case. eg. max is "127", and current number is say "11". The second digit '1' being <
// corresponding digit '2', means all digits are possible to append, like 119 will still be < 127
// If cmpResult == 0:
@@ -151,7 +151,7 @@ bool CalcInput::TryAddDigit(unsigned int value, uint32_t radix, bool isIntegerMo
}
else if (pNumSec->IsNegative() && chDigit <= lastChar + 1)
{
// Negative value case, eg. max is "127", and current number is "-12". Then 8 is also valid, as the range
// Negative value case, eg. max is "127", and current number is "-12". Then 8 is also valid, as the range
// is always from -(max+1)...max in signed mode
allowExtraDigit = true;
}

View File

@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "Header Files/CalcEngine.h"
#include "Header Files/CalcUtils.h"
@@ -34,9 +33,7 @@ bool IsDigitOpCode(OpCode opCode)
// was never inout, we need to revert the state changes made as a result of this test
bool IsGuiSettingOpCode(OpCode opCode)
{
if (IsOpInRange(opCode, IDM_HEX, IDM_BIN) ||
IsOpInRange(opCode, IDM_QWORD, IDM_BYTE) ||
IsOpInRange(opCode, IDM_DEG, IDM_GRAD))
if (IsOpInRange(opCode, IDM_HEX, IDM_BIN) || IsOpInRange(opCode, IDM_QWORD, IDM_BYTE) || IsOpInRange(opCode, IDM_DEG, IDM_GRAD))
{
return true;
}

View File

@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "Header Files/CalcEngine.h"
#include "Command.h"
#include "CalculatorVector.h"
@@ -12,7 +11,8 @@ constexpr int ASCII_0 = 48;
using namespace std;
using namespace CalcEngine;
namespace {
namespace
{
void IFT(ResultCode hr)
{
if (FAILED(hr))
@@ -39,11 +39,11 @@ void CHistoryCollector::ReinitHistory()
// Constructor
// Can throw Out of memory error
CHistoryCollector::CHistoryCollector(ICalcDisplay *pCalcDisplay, std::shared_ptr<IHistoryDisplay> pHistoryDisplay, wchar_t decimalSymbol) :
m_pHistoryDisplay(pHistoryDisplay),
m_pCalcDisplay(pCalcDisplay),
m_iCurLineHistStart(-1),
m_decimalSymbol(decimalSymbol)
CHistoryCollector::CHistoryCollector(ICalcDisplay* pCalcDisplay, std::shared_ptr<IHistoryDisplay> pHistoryDisplay, wchar_t decimalSymbol)
: m_pHistoryDisplay(pHistoryDisplay)
, m_pCalcDisplay(pCalcDisplay)
, m_iCurLineHistStart(-1)
, m_decimalSymbol(decimalSymbol)
{
ReinitHistory();
}
@@ -303,7 +303,8 @@ void CHistoryCollector::CompleteHistoryLine(wstring_view numStr)
{
if (nullptr != m_pCalcDisplay)
{
m_pCalcDisplay->SetExpressionDisplay(std::make_shared<CalculatorVector<std::pair<std::wstring, int>>>(), std::make_shared<CalculatorVector<std::shared_ptr<IExpressionCommand>>>());
m_pCalcDisplay->SetExpressionDisplay(
std::make_shared<CalculatorVector<std::pair<std::wstring, int>>>(), std::make_shared<CalculatorVector<std::shared_ptr<IExpressionCommand>>>());
}
if (nullptr != m_pHistoryDisplay)
@@ -324,14 +325,14 @@ void CHistoryCollector::ClearHistoryLine(wstring_view errStr)
{
if (nullptr != m_pCalcDisplay)
{
m_pCalcDisplay->SetExpressionDisplay(std::make_shared<CalculatorVector<std::pair<std::wstring, int>>>(), std::make_shared<CalculatorVector<std::shared_ptr<IExpressionCommand>>>());
m_pCalcDisplay->SetExpressionDisplay(
std::make_shared<CalculatorVector<std::pair<std::wstring, int>>>(), std::make_shared<CalculatorVector<std::shared_ptr<IExpressionCommand>>>());
}
m_iCurLineHistStart = -1; // It will get recomputed at the first Opnd
ReinitHistory();
}
}
// Adds the given string psz to the globally maintained current equation string at the end.
// Also returns the 0 based index in the string just added. Can throw out of memory error
int CHistoryCollector::IchAddSzToEquationSz(wstring_view str, int icommandIndex)
@@ -393,14 +394,13 @@ void CHistoryCollector::SetExpressionDisplay()
{
m_pCalcDisplay->SetExpressionDisplay(m_spTokens, m_spCommands);
}
}
int CHistoryCollector::AddCommand(_In_ const std::shared_ptr<IExpressionCommand> & spCommand)
int CHistoryCollector::AddCommand(_In_ const std::shared_ptr<IExpressionCommand>& spCommand)
{
if (m_spCommands == nullptr)
{
m_spCommands = std::make_shared <CalculatorVector<std::shared_ptr<IExpressionCommand>>>();
m_spCommands = std::make_shared<CalculatorVector<std::shared_ptr<IExpressionCommand>>>();
}
if (FAILED(m_spCommands->Append(spCommand)))

View File

@@ -1,26 +1,28 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
#include "pch.h"
#include <algorithm>
#include "Header Files/Number.h"
using namespace std;
namespace CalcEngine
{
Number::Number() noexcept :
Number(1, 0, { 0 })
{}
Number::Number() noexcept
: Number(1, 0, { 0 })
{
}
Number::Number(int32_t sign, int32_t exp, vector<uint32_t> const& mantissa) noexcept :
m_sign{ sign },
m_exp{ exp },
m_mantissa{ mantissa }
{}
Number::Number(int32_t sign, int32_t exp, vector<uint32_t> const& mantissa) noexcept
: m_sign{ sign }
, m_exp{ exp }
, m_mantissa{ mantissa }
{
}
Number::Number(PNUMBER p) noexcept :
m_sign{ p->sign },
m_exp{ p->exp },
m_mantissa{}
Number::Number(PNUMBER p) noexcept
: m_sign{ p->sign }
, m_exp{ p->exp }
, m_mantissa{}
{
m_mantissa.reserve(p->cdigit);
copy(p->mant, p->mant + p->cdigit, back_inserter(m_mantissa));
@@ -33,7 +35,7 @@ namespace CalcEngine
ret->exp = this->Exp();
ret->cdigit = static_cast<int32_t>(this->Mantissa().size());
MANTTYPE *ptrRet = ret->mant;
MANTTYPE* ptrRet = ret->mant;
for (auto const& digit : this->Mantissa())
{
*ptrRet++ = digit;
@@ -59,6 +61,6 @@ namespace CalcEngine
bool Number::IsZero() const
{
return all_of(m_mantissa.begin(), m_mantissa.end(), [](auto &&i) { return i == 0; });
return all_of(m_mantissa.begin(), m_mantissa.end(), [](auto&& i) { return i == 0; });
}
}

View File

@@ -1,16 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
#include "pch.h"
#include "Header Files/Rational.h"
using namespace std;
namespace CalcEngine
{
Rational::Rational() noexcept :
m_p{},
m_q{ 1, 0, { 1 } }
{}
Rational::Rational() noexcept
: m_p{}
, m_q{ 1, 0, { 1 } }
{
}
Rational::Rational(Number const& n) noexcept
{
@@ -24,10 +24,11 @@ namespace CalcEngine
m_q = Number(1, qExp, { 1 });
}
Rational::Rational(Number const& p, Number const& q) noexcept :
m_p{ p },
m_q{ q }
{}
Rational::Rational(Number const& p, Number const& q) noexcept
: m_p{ p }
, m_q{ q }
{
}
Rational::Rational(int32_t i)
{
@@ -51,8 +52,8 @@ namespace CalcEngine
Rational::Rational(uint64_t ui)
{
uint32_t hi = HIDWORD(ui);
uint32_t lo = LODWORD(ui);
uint32_t hi = (uint32_t) (((ui) >> 32) & 0xffffffff);
uint32_t lo = (uint32_t) ui;
Rational temp = (Rational{ hi } << 32) | lo;
@@ -60,10 +61,11 @@ namespace CalcEngine
m_q = Number{ temp.Q() };
}
Rational::Rational(PRAT prat) noexcept :
m_p{ Number{prat->pp} },
m_q{ Number{prat->pq} }
{}
Rational::Rational(PRAT prat) noexcept
: m_p{ Number{ prat->pp } }
, m_q{ Number{ prat->pq } }
{
}
PRAT Rational::ToPRAT() const
{
@@ -182,6 +184,13 @@ namespace CalcEngine
return *this;
}
/// <summary>
/// Calculate the remainder after division, the sign of a result will match the sign of the current object.
/// </summary>
/// <remarks>
/// This function has the same behavior as the standard C/C++ operator '%'
/// to calculate the modulus after division instead, use <see cref="RationalMath::Mod"/> instead.
/// </remarks>
Rational& Rational::operator%=(Rational const& rhs)
{
PRAT lhsRat = this->ToPRAT();
@@ -189,7 +198,7 @@ namespace CalcEngine
try
{
modrat(&lhsRat, rhsRat);
remrat(&lhsRat, rhsRat);
destroyrat(rhsRat);
}
catch (uint32_t error)
@@ -342,6 +351,13 @@ namespace CalcEngine
return lhs;
}
/// <summary>
/// Calculate the remainder after division, the sign of a result will match the sign of lhs.
/// </summary>
/// <remarks>
/// This function has the same behavior as the standard C/C++ operator '%', to calculate the modulus after division instead, use <see
/// cref="Rational::operator%"/> instead.
/// </remarks>
Rational operator%(Rational lhs, Rational const& rhs)
{
lhs %= rhs;

View File

@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "Header Files/RationalMath.h"
using namespace std;
@@ -387,3 +386,33 @@ Rational RationalMath::ATanh(Rational const& rat)
return result;
}
/// <summary>
/// Calculate the modulus after division, the sign of the result will match the sign of b.
/// </summary>
/// <remarks>
/// When one of the operand is negative
/// the result will differ from the C/C++ operator '%'
/// use <see cref="Rational::operator%"/> instead to calculate the remainder after division.
/// </remarks>
Rational RationalMath::Mod(Rational const& a, Rational const& b)
{
PRAT prat = a.ToPRAT();
PRAT pn = b.ToPRAT();
try
{
modrat(&prat, pn);
destroyrat(pn);
}
catch (uint32_t error)
{
destroyrat(prat);
destroyrat(pn);
throw(error);
}
auto res = Rational{ prat };
destroyrat(prat);
return res;
}

View File

@@ -1,9 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include <cassert>
#include "Header Files/CalcEngine.h"
#include "CalculatorResource.h"
using namespace std;
@@ -25,13 +24,18 @@ static constexpr wstring_view DEFAULT_NUMBER_STR = L"0";
// Read strings for keys, errors, trig types, etc.
// These will be copied from the resources to local memory.
array<wstring, CSTRINGSENGMAX> CCalcEngine::s_engineStrings;
unordered_map<wstring, wstring> CCalcEngine::s_engineStrings;
void CCalcEngine::LoadEngineStrings(CalculationManager::IResourceProvider& resourceProvider)
{
for (size_t i = 0; i < s_engineStrings.size(); i++)
for (const auto& sid : g_sids)
{
s_engineStrings[i] = resourceProvider.GetCEngineString(g_sids[i]);
auto locKey = wstring{ sid };
auto locString = resourceProvider.GetCEngineString(locKey);
if (!locString.empty())
{
s_engineStrings[locKey] = locString;
}
}
}
@@ -54,42 +58,47 @@ void CCalcEngine::InitialOneTimeOnlySetup(CalculationManager::IResourceProvider&
// CCalcEngine::CCalcEngine
//
//////////////////////////////////////////////////
CCalcEngine::CCalcEngine(bool fPrecedence, bool fIntegerMode, CalculationManager::IResourceProvider* const pResourceProvider, __in_opt ICalcDisplay *pCalcDisplay, __in_opt shared_ptr<IHistoryDisplay> pHistoryDisplay) :
m_fPrecedence(fPrecedence),
m_fIntegerMode(fIntegerMode),
m_pCalcDisplay(pCalcDisplay),
m_resourceProvider(pResourceProvider),
m_nOpCode(0),
m_nPrevOpCode(0),
m_bChangeOp(false),
m_bRecord(false),
m_bSetCalcState(false),
m_input(DEFAULT_DEC_SEPARATOR),
m_nFE(FMT_FLOAT),
m_memoryValue{ make_unique<Rational>() },
m_holdVal{},
m_currentVal{},
m_lastVal{},
m_parenVals{},
m_precedenceVals{},
m_bError(false),
m_bInv(false),
m_bNoPrevEqu(true),
m_radix(DEFAULT_RADIX),
m_precision(DEFAULT_PRECISION),
m_cIntDigitsSav(DEFAULT_MAX_DIGITS),
m_decGrouping(),
m_numberString(DEFAULT_NUMBER_STR),
m_nTempCom(0),
m_openParenCount(0),
m_nOp(),
m_nPrecOp(),
m_precedenceOpCount(0),
m_nLastCom(0),
m_angletype(ANGLE_DEG),
m_numwidth(QWORD_WIDTH),
m_HistoryCollector(pCalcDisplay, pHistoryDisplay, DEFAULT_DEC_SEPARATOR),
m_groupSeparator(DEFAULT_GRP_SEPARATOR)
CCalcEngine::CCalcEngine(
bool fPrecedence,
bool fIntegerMode,
CalculationManager::IResourceProvider* const pResourceProvider,
__in_opt ICalcDisplay* pCalcDisplay,
__in_opt shared_ptr<IHistoryDisplay> pHistoryDisplay)
: m_fPrecedence(fPrecedence)
, m_fIntegerMode(fIntegerMode)
, m_pCalcDisplay(pCalcDisplay)
, m_resourceProvider(pResourceProvider)
, m_nOpCode(0)
, m_nPrevOpCode(0)
, m_bChangeOp(false)
, m_bRecord(false)
, m_bSetCalcState(false)
, m_input(DEFAULT_DEC_SEPARATOR)
, m_nFE(FMT_FLOAT)
, m_memoryValue{ make_unique<Rational>() }
, m_holdVal{}
, m_currentVal{}
, m_lastVal{}
, m_parenVals{}
, m_precedenceVals{}
, m_bError(false)
, m_bInv(false)
, m_bNoPrevEqu(true)
, m_radix(DEFAULT_RADIX)
, m_precision(DEFAULT_PRECISION)
, m_cIntDigitsSav(DEFAULT_MAX_DIGITS)
, m_decGrouping()
, m_numberString(DEFAULT_NUMBER_STR)
, m_nTempCom(0)
, m_openParenCount(0)
, m_nOp()
, m_nPrecOp()
, m_precedenceOpCount(0)
, m_nLastCom(0)
, m_angletype(ANGLE_DEG)
, m_numwidth(QWORD_WIDTH)
, m_HistoryCollector(pCalcDisplay, pHistoryDisplay, DEFAULT_DEC_SEPARATOR)
, m_groupSeparator(DEFAULT_GRP_SEPARATOR)
{
InitChopNumbers();
@@ -168,7 +177,7 @@ void CCalcEngine::SettingsChanged()
m_HistoryCollector.SetDecimalSymbol(m_decimalSeparator);
// put the new decimal symbol into the table used to draw the decimal key
s_engineStrings[IDS_DECIMAL] = m_decimalSeparator;
s_engineStrings[SIDS_DECIMAL_SEPARATOR] = m_decimalSeparator;
// we need to redraw to update the decimal point button
numChanged = true;

View File

@@ -12,30 +12,24 @@
*
* Author:
\****************************************************************************/
#include "pch.h"
#include <string>
#include "Header Files/CalcEngine.h"
#include "Header Files/CalcUtils.h"
#define IDC_RADSIN IDC_UNARYLAST+1
#define IDC_RADCOS IDC_UNARYLAST+2
#define IDC_RADTAN IDC_UNARYLAST+3
#define IDC_GRADSIN IDC_UNARYLAST+4
#define IDC_GRADCOS IDC_UNARYLAST+5
#define IDC_GRADTAN IDC_UNARYLAST+6
using namespace std;
using namespace CalcEngine;
namespace {
namespace
{
// NPrecedenceOfOp
//
// returns a virtual number for precedence for the operator. We expect binary operator only, otherwise the lowest number
// 0 is returned. Higher the number, higher the precedence of the operator.
int NPrecedenceOfOp(int nopCode)
{
static uint8_t rgbPrec[] = { 0,0, IDC_OR,0, IDC_XOR,0, IDC_AND,1,
IDC_ADD,2, IDC_SUB,2, IDC_RSHF,3, IDC_LSHF,3,
IDC_MOD,3, IDC_DIV,3, IDC_MUL,3, IDC_PWR,4, IDC_ROOT, 4 };
static uint8_t rgbPrec[] = { 0, 0, IDC_OR, 0, IDC_XOR, 0, IDC_AND, 1, IDC_ADD, 2, IDC_SUB, 2, IDC_RSHF,
3, IDC_LSHF, 3, IDC_MOD, 3, IDC_DIV, 3, IDC_MUL, 3, IDC_PWR, 4, IDC_ROOT, 4 };
unsigned int iPrec;
iPrec = 0;
@@ -48,7 +42,6 @@ namespace {
iPrec = 0;
}
return rgbPrec[iPrec + 1];
}
}
@@ -96,7 +89,7 @@ void CCalcEngine::ProcessCommand(OpCode wParam)
void CCalcEngine::ProcessCommandWorker(OpCode wParam)
{
int nx, ni;
int nx, ni;
// Save the last command. Some commands are not saved in this manor, these
// commands are:
@@ -131,18 +124,13 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
// Toggle Record/Display mode if appropriate.
if (m_bRecord)
{
if (IsOpInRange(wParam, IDC_AND, IDC_MMINUS) ||
IsOpInRange(wParam, IDC_OPENP, IDC_CLOSEP) ||
IsOpInRange(wParam, IDM_HEX, IDM_BIN) ||
IsOpInRange(wParam, IDM_QWORD, IDM_BYTE) ||
IsOpInRange(wParam, IDM_DEG, IDM_GRAD) ||
IsOpInRange(wParam, IDC_BINEDITSTART, IDC_BINEDITSTART + 63) ||
(IDC_INV == wParam) ||
(IDC_SIGN == wParam && 10 != m_radix))
if (IsOpInRange(wParam, IDC_AND, IDC_MMINUS) || IsOpInRange(wParam, IDC_OPENP, IDC_CLOSEP) || IsOpInRange(wParam, IDM_HEX, IDM_BIN)
|| IsOpInRange(wParam, IDM_QWORD, IDM_BYTE) || IsOpInRange(wParam, IDM_DEG, IDM_GRAD)
|| IsOpInRange(wParam, IDC_BINEDITSTART, IDC_BINEDITSTART + 63) || (IDC_INV == wParam) || (IDC_SIGN == wParam && 10 != m_radix))
{
m_bRecord = false;
m_currentVal = m_input.ToRational(m_radix, m_precision);
DisplayNum(); // Causes 3.000 to shrink to 3. on first op.
DisplayNum(); // Causes 3.000 to shrink to 3. on first op.
}
}
else
@@ -247,9 +235,9 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
else
{
/* do the last operation and then if the precedence array is not
* empty or the top is not the '(' demarcator then pop the top
* of the array and recheck precedence against the new operator
*/
* empty or the top is not the '(' demarcator then pop the top
* of the array and recheck precedence against the new operator
*/
m_currentVal = DoOperation(m_nOpCode, m_currentVal, m_lastVal);
m_nPrevOpCode = m_nOpCode;
@@ -278,7 +266,6 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
m_HistoryCollector.PopLastOpndStart();
goto DoPrecedenceCheckAgain;
}
}
}
@@ -343,11 +330,9 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
/* reset the m_bInv flag and indicators if it is set
and have been used */
if (m_bInv &&
((wParam == IDC_CHOP) ||
(wParam == IDC_SIN) || (wParam == IDC_COS) || (wParam == IDC_TAN) ||
(wParam == IDC_LN) || (wParam == IDC_DMS) || (wParam == IDC_DEGREES) ||
(wParam == IDC_SINH) || (wParam == IDC_COSH) || (wParam == IDC_TANH)))
if (m_bInv
&& ((wParam == IDC_CHOP) || (wParam == IDC_SIN) || (wParam == IDC_COS) || (wParam == IDC_TAN) || (wParam == IDC_LN) || (wParam == IDC_DMS)
|| (wParam == IDC_DEGREES) || (wParam == IDC_SINH) || (wParam == IDC_COSH) || (wParam == IDC_TANH)))
{
m_bInv = false;
}
@@ -381,24 +366,25 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
{
if (!m_bChangeOp)
{
// A special goody we are doing to preserve the history, if all was done was serious of unary operations last
// Preserve history, if everything done before was a series of unary operations.
CheckAndAddLastBinOpToHistory(false);
}
m_lastVal = 0;
m_bChangeOp = false;
m_precedenceOpCount = m_nTempCom = m_nLastCom = m_nOpCode = m_openParenCount = 0;
m_openParenCount = 0;
m_precedenceOpCount = m_nTempCom = m_nLastCom = m_nOpCode = 0;
m_nPrevOpCode = 0;
m_bNoPrevEqu = true;
/* clear the parenthesis status box indicator, this will not be
cleared for CENTR */
if (nullptr != m_pCalcDisplay)
{
m_pCalcDisplay->SetParenDisplayText(L"");
m_pCalcDisplay->SetExpressionDisplay(make_shared<CalculatorVector<pair<wstring, int>>>(), make_shared<CalculatorVector<shared_ptr<IExpressionCommand>>>());
m_pCalcDisplay->SetParenthesisNumber(0);
m_pCalcDisplay->SetExpressionDisplay(
make_shared<CalculatorVector<pair<wstring, int>>>(), make_shared<CalculatorVector<shared_ptr<IExpressionCommand>>>());
}
m_HistoryCollector.ClearHistoryLine(wstring());
@@ -441,7 +427,7 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
// automatic closing of all the parenthesis to get a meaningful result as well as ensure data integrity
m_nTempCom = m_nLastCom; // Put back this last saved command to the prev state so ) can be handled properly
ProcessCommand(IDC_CLOSEP);
m_nLastCom = m_nTempCom; // Actually this is IDC_CLOSEP
m_nLastCom = m_nTempCom; // Actually this is IDC_CLOSEP
m_nTempCom = (int)wParam; // put back in the state where last op seen was IDC_CLOSEP, and current op is IDC_EQU
}
@@ -491,7 +477,8 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
m_HistoryCollector.CompleteHistoryLine(groupedString);
if (nullptr != m_pCalcDisplay)
{
m_pCalcDisplay->SetExpressionDisplay(make_shared<CalculatorVector<pair<wstring, int>>>(), make_shared<CalculatorVector<shared_ptr<IExpressionCommand>>>());
m_pCalcDisplay->SetExpressionDisplay(
make_shared<CalculatorVector<pair<wstring, int>>>(), make_shared<CalculatorVector<shared_ptr<IExpressionCommand>>>());
}
}
@@ -601,7 +588,7 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
// Set the "(=xx" indicator.
if (nullptr != m_pCalcDisplay)
{
m_pCalcDisplay->SetParenDisplayText(m_openParenCount ? to_wstring(m_openParenCount) : L"");
m_pCalcDisplay->SetParenthesisNumber(m_openParenCount >= 0 ? static_cast<unsigned int>(m_openParenCount) : 0);
}
if (!m_bError)
@@ -755,7 +742,6 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
m_bInv = !m_bInv;
break;
}
}
// Helper function to resolve one item on the precedence stack.
@@ -764,8 +750,8 @@ void CCalcEngine::ResolveHighestPrecedenceOperation()
// Is there a valid operation around?
if (m_nOpCode)
{
// If this is the first EQU in a string, set m_holdVal=m_currentVal
// Otherwise let m_currentVal=m_holdVal. This keeps m_currentVal constant
// If this is the first EQU in a string, set m_holdVal=m_currentVal
// Otherwise let m_currentVal=m_holdVal. This keeps m_currentVal constant
// through all EQUs in a row.
if (m_bNoPrevEqu)
{
@@ -820,7 +806,6 @@ void CCalcEngine::CheckAndAddLastBinOpToHistory(bool addToHistory)
// So erase the last operand
m_HistoryCollector.RemoveLastOpndFromHistory();
}
}
else if (m_HistoryCollector.FOpndAddedToHistory() && !m_bError)
{
@@ -829,8 +814,7 @@ void CCalcEngine::CheckAndAddLastBinOpToHistory(bool addToHistory)
// Let us make a current value =. So in case of 4 SQRT (or a equation under braces) and then a new equation is started, we can just form
// a useful equation of sqrt(4) = 2 and continue a new equation from now on. But no point in doing this for things like
// MR, SUM etc. All you will get is 5 = 5 kind of no useful equation.
if ((IsUnaryOpCode(m_nLastCom) || IDC_SIGN == m_nLastCom || IDC_CLOSEP == m_nLastCom) &&
0 == m_openParenCount)
if ((IsUnaryOpCode(m_nLastCom) || IDC_SIGN == m_nLastCom || IDC_CLOSEP == m_nLastCom) && 0 == m_openParenCount)
{
if (addToHistory)
{
@@ -868,155 +852,93 @@ void CCalcEngine::DisplayAnnounceBinaryOperator()
// Unary operator Function Name table Element
// since unary operators button names aren't exactly friendly for history purpose,
// we have this separate table to get its localized name and for its Inv function if it exists.
typedef struct
struct FunctionNameElement
{
int idsFunc; // index of string for the unary op function. Can be NULL, in which case it same as button name
int idsFuncInv; // index of string for Inv of unary op. Can be NULL, in case it is same as idsFunc
bool fDontUseInExpEval; // true if this cant be used in reverse direction as well, ie. during expression evaluation
} UFNE;
wstring degreeString; // Used by default if there are no rad or grad specific strings.
wstring inverseDegreeString; // Will fall back to degreeString if empty
wstring radString;
wstring inverseRadString; // Will fall back to radString if empty
wstring gradString;
wstring inverseGradString; // Will fall back to gradString if empty
bool hasAngleStrings = ((!radString.empty()) || (!inverseRadString.empty()) || (!gradString.empty()) || (!inverseGradString.empty()));
};
// Table for each unary operator
static const UFNE rgUfne[] =
{
/* IDC_CHOP */{ 0, IDS_FRAC, false },
/* IDC_ROL */{ 0, 0, true },
/* IDC_ROR */{ 0, 0, true },
static const std::unordered_map<int, FunctionNameElement> unaryOperatorStringTable = {
{ IDC_CHOP, { L"", SIDS_FRAC } },
/* IDC_COM */{ 0, 0, true },
/* IDC_SIN */{ IDS_SIND, IDS_ASIND, false }, // default in this table is degrees for sin,cos & tan
/* IDC_COS */{ IDS_COSD, IDS_ACOSD, false },
/* IDC_TAN */{ IDS_TAND, IDS_ATAND, false },
{ IDC_SIN, { SIDS_SIND, SIDS_ASIND, SIDS_SINR, SIDS_ASINR, SIDS_SING, SIDS_ASING } },
{ IDC_COS, { SIDS_COSD, SIDS_ACOSD, SIDS_COSR, SIDS_ACOSR, SIDS_COSG, SIDS_ACOSG } },
{ IDC_TAN, { SIDS_TAND, SIDS_ATAND, SIDS_TANR, SIDS_ATANR, SIDS_TANG, SIDS_ATANG } },
/* IDC_SINH */{ 0, IDS_ASINH, false },
/* IDC_COSH */{ 0, IDS_ACOSH, false },
/* IDC_TANH */{ 0, IDS_ATANH, false },
{ IDC_SINH, { L"", SIDS_ASINH } },
{ IDC_COSH, { L"", SIDS_ACOSH } },
{ IDC_TANH, { L"", SIDS_ATANH } },
/* IDC_LN */{ 0, IDS_POWE, false },
/* IDC_LOG */{ 0, 0, false },
/* IDC_SQRT */{ 0, 0, false },
/* IDC_SQR */{ IDS_SQR, 0, false },
/* IDC_CUB */{ IDS_CUBE, 0, false },
/* IDC_FAC */{ IDS_FACT, 0, false },
/* IDC_REC */{ IDS_REC, 0, false },
/* IDC_DMS */{ 0, IDS_DEGREES, false },
/* IDC_CUBEROOT */{ 0, 0, false },
/* IDC_POW10 */{ 0, 0, false },
/* IDC_PERCENT */{ 0, 0, false },
/* IDC_RADSIN */{ IDS_SINR, IDS_ASINR, false },
/* IDC_RADCOS */{ IDS_COSR, IDS_ACOSR, false },
/* IDC_RADTAN */{ IDS_TANR, IDS_ATANR, false },
/* IDC_GRADCOS */{ IDS_SING, IDS_ASING, false },
/* IDC_GRADCOS */{ IDS_COSG, IDS_ACOSG, false },
/* IDC_GRADTAN */{ IDS_TANG, IDS_ATANG, false },
{ IDC_LN, { L"", SIDS_POWE } },
{ IDC_SQR, { SIDS_SQR } },
{ IDC_CUB, { SIDS_CUBE } },
{ IDC_FAC, { SIDS_FACT } },
{ IDC_REC, { SIDS_RECIPROC } },
{ IDC_DMS, { L"", SIDS_DEGREES } },
{ IDC_SIGN, { SIDS_NEGATE } },
{ IDC_DEGREES, { SIDS_DEGREES } }
};
wstring_view CCalcEngine::OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE angletype)
{
// Special cases for Sign and Degrees
if (IDC_SIGN == nOpCode)
{
return GetString(IDS_NEGATE);
}
if (IDC_DEGREES == nOpCode)
{
return GetString(IDS_DEGREES);
}
// Correct the trigonometric functions with type of angle argument they take
if (ANGLE_RAD == angletype)
{
switch (nOpCode)
{
case IDC_SIN:
nOpCode = IDC_RADSIN;
break;
case IDC_COS:
nOpCode = IDC_RADCOS;
break;
case IDC_TAN:
nOpCode = IDC_RADTAN;
break;
}
}
else if (ANGLE_GRAD == angletype)
{
switch (nOpCode)
{
case IDC_SIN:
nOpCode = IDC_GRADSIN;
break;
case IDC_COS:
nOpCode = IDC_GRADCOS;
break;
case IDC_TAN:
nOpCode = IDC_GRADTAN;
break;
}
}
// Try to lookup the ID in the UFNE table
int ids = 0;
int iufne = nOpCode - IDC_UNARYFIRST;
if (iufne >= 0 && (size_t)iufne < size(rgUfne))
wstring ids = L"";
if (auto pair = unaryOperatorStringTable.find(nOpCode); pair != unaryOperatorStringTable.end())
{
if (fInv)
const FunctionNameElement& element = pair->second;
if (!element.hasAngleStrings || ANGLE_DEG == angletype)
{
ids = rgUfne[iufne].idsFuncInv;
if (fInv)
{
ids = element.inverseDegreeString;
}
if (ids.empty())
{
ids = element.degreeString;
}
}
if (0 == ids)
else if (ANGLE_RAD == angletype)
{
ids = rgUfne[iufne].idsFunc;
if (fInv)
{
ids = element.inverseRadString;
}
if (ids.empty())
{
ids = element.radString;
}
}
else if (ANGLE_GRAD == angletype)
{
if (fInv)
{
ids = element.inverseGradString;
}
if (ids.empty())
{
ids = element.gradString;
}
}
}
if (!ids.empty())
{
return GetString(ids);
}
// If we didn't find an ID in the table, use the op code.
if (0 == ids)
{
ids = IdStrFromCmdId(nOpCode);
}
return GetString(ids);
}
//
// Sets the Angle Mode for special unary op IDC's which are used to index to the table rgUfne
// and returns the equivalent plain IDC for trigonometric function. If it isn't a trigonometric function
// returns the passed in idc itself.
int CCalcEngine::IdcSetAngleTypeDecMode(int idc)
{
int idcAngleCmd = IDM_DEG;
switch (idc)
{
case IDC_RADSIN:
idcAngleCmd = IDM_RAD;
idc = IDC_SIN;
break;
case IDC_RADCOS:
idcAngleCmd = IDM_RAD;
idc = IDC_COS;
break;
case IDC_RADTAN:
idcAngleCmd = IDM_RAD;
idc = IDC_TAN;
break;
case IDC_GRADSIN:
idcAngleCmd = IDM_GRAD;
idc = IDC_SIN;
break;
case IDC_GRADCOS:
idcAngleCmd = IDM_GRAD;
idc = IDC_COS;
break;
case IDC_GRADTAN:
idcAngleCmd = IDM_GRAD;
idc = IDC_TAN;
break;
}
ProcessCommand(idcAngleCmd);
return idc;
return OpCodeToString(nOpCode);
}
bool CCalcEngine::IsCurrentTooBigForTrig()

View File

@@ -12,7 +12,9 @@
*
* Author:
\****************************************************************************/
#include "pch.h"
#include <sstream>
#include <regex>
#include "Header Files/CalcEngine.h"
using namespace std;
@@ -23,7 +25,6 @@ constexpr uint32_t MAX_GROUPING_SIZE = 16;
constexpr wstring_view c_decPreSepStr = L"[+-]?(\\d*)[";
constexpr wstring_view c_decPostSepStr = L"]?(\\d*)(?:e[+-]?(\\d*))?$";
/****************************************************************************\
* void DisplayNum(void)
*
@@ -35,18 +36,19 @@ constexpr wstring_view c_decPostSepStr = L"]?(\\d*)(?:e[+-]?(\\d*))?$";
//
// State of calc last time DisplayNum was called
//
typedef struct {
typedef struct
{
Rational value;
int32_t precision;
uint32_t radix;
int nFE;
NUM_WIDTH numwidth;
bool fIntMath;
bool bRecord;
bool bUseSep;
int nFE;
NUM_WIDTH numwidth;
bool fIntMath;
bool bRecord;
bool bUseSep;
} LASTDISP;
LASTDISP gldPrevious = { 0, -1, 0, -1, (NUM_WIDTH)-1, false, false, false };
static LASTDISP gldPrevious = { 0, -1, 0, -1, (NUM_WIDTH)-1, false, false, false };
// Truncates if too big, makes it a non negative - the number in rat. Doesn't do anything if not in INT mode
CalcEngine::Rational CCalcEngine::TruncateNumForIntMath(CalcEngine::Rational const& rat)
@@ -64,7 +66,7 @@ CalcEngine::Rational CCalcEngine::TruncateNumForIntMath(CalcEngine::Rational con
if (result < 0)
{
// if negative make positive by doing a twos complement
result = -(result) - 1;
result = -(result)-1;
result ^= m_chopNumbers[m_numwidth];
}
@@ -82,15 +84,8 @@ void CCalcEngine::DisplayNum(void)
// something important has changed since the last time DisplayNum was
// called.
//
if (m_bRecord ||
gldPrevious.value != m_currentVal ||
gldPrevious.precision != m_precision ||
gldPrevious.radix != m_radix ||
gldPrevious.nFE != (int)m_nFE ||
gldPrevious.bUseSep != true ||
gldPrevious.numwidth != m_numwidth ||
gldPrevious.fIntMath != m_fIntegerMode ||
gldPrevious.bRecord != m_bRecord)
if (m_bRecord || gldPrevious.value != m_currentVal || gldPrevious.precision != m_precision || gldPrevious.radix != m_radix || gldPrevious.nFE != (int)m_nFE
|| gldPrevious.bUseSep != true || gldPrevious.numwidth != m_numwidth || gldPrevious.fIntMath != m_fIntegerMode || gldPrevious.bRecord != m_bRecord)
{
gldPrevious.precision = m_precision;
gldPrevious.radix = m_radix;

View File

@@ -16,7 +16,6 @@
/*** ***/
/*** ***/
/**************************************************************************/
#include "pch.h"
#include "Header Files/CalcEngine.h"
using namespace std;
@@ -55,7 +54,7 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r
uint64_t w64Bits = result.ToUInt64_t();
uint64_t msb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1;
w64Bits <<= 1; // LShift by 1
w64Bits <<= 1; // LShift by 1
w64Bits |= msb; // Set the prev Msb as the current Lsb
result = w64Bits;
@@ -169,9 +168,9 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r
case IDC_DEGREES:
ProcessCommand(IDC_INV);
// This case falls through to IDC_DMS case because in the old Win32 Calc,
// This case falls through to IDC_DMS case because in the old Win32 Calc,
// the degrees functionality was achieved as 'Inv' of 'dms' operation,
// so setting the IDC_INV command first and then performing 'dms' operation as global variables m_bInv, m_bRecord
// so setting the IDC_INV command first and then performing 'dms' operation as global variables m_bInv, m_bRecord
// are set properly through ProcessCommand(IDC_INV)
[[fallthrough]];
case IDC_DMS:
@@ -203,7 +202,7 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r
}
break;
}
} // end switch( op )
} // end switch( op )
}
catch (uint32_t nErrCode)
{
@@ -227,4 +226,3 @@ void CCalcEngine::DisplayError(uint32_t nError)
m_HistoryCollector.ClearHistoryLine(errorString);
}

View File

@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "Header Files/CalcEngine.h"
using namespace CalcEngine;
@@ -78,7 +77,7 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa
case IDC_DIV:
case IDC_MOD:
{
int iNumeratorSign = 1, iDenominatorSign = 1, iFinalSign = 1;
int iNumeratorSign = 1, iDenominatorSign = 1;
auto temp = result;
result = rhs;
@@ -107,20 +106,30 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa
if (operation == IDC_DIV)
{
iFinalSign = iNumeratorSign * iDenominatorSign;
result /= temp;
if (m_fIntegerMode && (iNumeratorSign * iDenominatorSign) == -1)
{
result = -(Integer(result));
}
}
else
{
iFinalSign = iNumeratorSign;
result %= temp;
}
if (m_fIntegerMode)
{
// Programmer mode, use remrat (remainder after division)
result %= temp;
if (m_fIntegerMode && iFinalSign == -1)
{
result = -(Integer(result));
if (iNumeratorSign == -1)
{
result = -(Integer(result));
}
}
else
{
// other modes, use modrat (modulus after division)
result = Mod(result, temp);
}
}
break;
}

View File

@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "Header Files/CalcEngine.h"
using namespace CalcEngine;
@@ -65,7 +64,7 @@ int32_t CCalcEngine::DwWordBitWidthFromeNumWidth(NUM_WIDTH /*numwidth*/)
uint32_t CCalcEngine::NRadixFromRadixType(RADIX_TYPE radixtype)
{
static constexpr uint32_t rgnRadish[4] = { 16, 10, 8, 2 }; /* Number bases in the same order as radixtype */
static constexpr uint32_t rgnRadish[4] = { 16, 10, 8, 2 }; /* Number bases in the same order as radixtype */
uint32_t radix = 10;
// convert special bases into symbolic values