From 995f07712730a8b24ff90f58176d9cda61a6a608 Mon Sep 17 00:00:00 2001 From: Josh Koon <45607479+joshkoon@users.noreply.github.com> Date: Tue, 19 Feb 2019 07:46:17 -0800 Subject: [PATCH] CalcEngine: Convert NumObj* functions to use Rationals and move under CalcEngine::RationalMath namespace (#12) * Converts NumObj* functions to use Rationals. Places new functions under CalcEngine::RationalMath namespace * Moves functions that correspond to an operator to the Rational class with intent to convert to operators in the future * Consolidates use of RatPack's NUMBER and RAT data types to Number/Rational classes and RationalMath namespace. --- src/CalcManager/CEngine/Rational.cpp | 414 +++++++++++++++++++++ src/CalcManager/CEngine/calc.cpp | 46 +-- src/CalcManager/CEngine/scicomm.cpp | 285 +++++++-------- src/CalcManager/CEngine/scidisp.cpp | 63 ++-- src/CalcManager/CEngine/scifunc.cpp | 394 ++++++++------------ src/CalcManager/CEngine/scimath.cpp | 466 +++++++++++++++++------- src/CalcManager/CEngine/scioper.cpp | 183 ++++------ src/CalcManager/CEngine/sciset.cpp | 60 +-- src/CalcManager/ExpressionCommand.cpp | 4 +- src/CalcManager/Header Files/Rational.h | 25 ++ src/CalcManager/Header Files/scimath.h | 96 ++--- 11 files changed, 1191 insertions(+), 845 deletions(-) diff --git a/src/CalcManager/CEngine/Rational.cpp b/src/CalcManager/CEngine/Rational.cpp index eceace4..08d93a1 100644 --- a/src/CalcManager/CEngine/Rational.cpp +++ b/src/CalcManager/CEngine/Rational.cpp @@ -2,6 +2,7 @@ #include "pch.h" #include "Header Files/Rational.h" +#include "Header Files/scimath.h" using namespace std; @@ -29,6 +30,37 @@ namespace CalcEngine m_q{ q } {} + Rational::Rational(int32_t i) + { + PRAT pr = longtorat(static_cast(i)); + + m_p = Number{ pr->pp }; + m_q = Number{ pr->pq }; + + destroyrat(pr); + } + + Rational::Rational(uint32_t ui) + { + PRAT pr = Ulongtorat(static_cast(ui)); + + m_p = Number{ pr->pp }; + m_q = Number{ pr->pq }; + + destroyrat(pr); + } + + Rational::Rational(uint64_t ui, uint32_t radix, int32_t precision) + { + uint32_t hi = HIDWORD(ui); + uint32_t lo = LODWORD(ui); + + Rational temp = Rational{ hi }.Lsh(32, radix, precision).Or(lo, radix, precision); + + m_p = Number{ temp.P() }; + m_q = Number{ temp.Q() }; + } + Rational::Rational(PRAT prat) noexcept : m_p{ Number{prat->pp} }, m_q{ Number{prat->pq} } @@ -54,8 +86,390 @@ namespace CalcEngine return m_q; } + Rational Rational::Negate() const + { + return Rational{ Number{ -1 * m_p.Sign(), m_p.Exp(), m_p.Mantissa() }, m_q}; + } + + Rational Rational::Add(Rational const& rhs, int32_t precision) const + { + PRAT lhsRat = this->ToPRAT(); + PRAT rhsRat = rhs.ToPRAT(); + + try + { + addrat(&lhsRat, rhsRat, precision); + destroyrat(rhsRat); + } + catch (DWORD error) + { + destroyrat(lhsRat); + destroyrat(rhsRat); + throw(error); + } + + Rational result = Rational{ lhsRat }; + destroyrat(lhsRat); + + return result; + } + + Rational Rational::Sub(Rational const& rhs, int32_t precision) const + { + PRAT lhsRat = this->ToPRAT(); + PRAT rhsRat = rhs.ToPRAT(); + + try + { + subrat(&lhsRat, rhsRat, precision); + destroyrat(rhsRat); + } + catch (DWORD error) + { + destroyrat(lhsRat); + destroyrat(rhsRat); + throw(error); + } + + Rational result = Rational{ lhsRat }; + destroyrat(lhsRat); + + return result; + } + + Rational Rational::Mul(Rational const& rhs, int32_t precision) const + { + PRAT lhsRat = this->ToPRAT(); + PRAT rhsRat = rhs.ToPRAT(); + + try + { + mulrat(&lhsRat, rhsRat, precision); + destroyrat(rhsRat); + } + catch (DWORD error) + { + destroyrat(lhsRat); + destroyrat(rhsRat); + throw(error); + } + + Rational result = Rational{ lhsRat }; + destroyrat(lhsRat); + + return result; + } + + Rational Rational::Div(Rational const& rhs, int32_t precision) const + { + PRAT lhsRat = this->ToPRAT(); + PRAT rhsRat = rhs.ToPRAT(); + + try + { + divrat(&lhsRat, rhsRat, precision); + destroyrat(rhsRat); + } + catch (DWORD error) + { + destroyrat(lhsRat); + destroyrat(rhsRat); + throw(error); + } + + Rational result = Rational{ lhsRat }; + destroyrat(lhsRat); + + return result; + } + + Rational Rational::Mod(Rational const& rhs) const + { + PRAT lhsRat = this->ToPRAT(); + PRAT rhsRat = rhs.ToPRAT(); + + try + { + modrat(&lhsRat, rhsRat); + destroyrat(rhsRat); + } + catch (DWORD error) + { + destroyrat(lhsRat); + destroyrat(rhsRat); + throw(error); + } + + Rational result = Rational{ lhsRat }; + destroyrat(lhsRat); + + return result; + } + + Rational Rational::Lsh(Rational const& rhs, uint32_t radix, int32_t precision) const + { + PRAT lhsRat = this->ToPRAT(); + PRAT rhsRat = rhs.ToPRAT(); + + try + { + lshrat(&lhsRat, rhsRat, radix, precision); + destroyrat(rhsRat); + } + catch (DWORD error) + { + destroyrat(lhsRat); + destroyrat(rhsRat); + throw(error); + } + + Rational result = Rational{ lhsRat }; + destroyrat(lhsRat); + + return result; + } + + Rational Rational::Rsh(Rational const& rhs, uint32_t radix, int32_t precision) const + { + PRAT lhsRat = this->ToPRAT(); + PRAT rhsRat = rhs.ToPRAT(); + + try + { + rshrat(&lhsRat, rhsRat, radix, precision); + destroyrat(rhsRat); + } + catch (DWORD error) + { + destroyrat(lhsRat); + destroyrat(rhsRat); + throw(error); + } + + Rational result = Rational{ lhsRat }; + destroyrat(lhsRat); + + return result; + } + + Rational Rational::Not(bool isIntegerMode, Rational const& chopNum, uint32_t radix, int32_t precision) const + { + Rational result{}; + + if (radix == 10 && !isIntegerMode) + { + result = RationalMath::Integer(*this, radix, precision); + result = result.Add(1, precision); + result = result.Negate(); + } + else + { + result = this->Xor(chopNum, radix, precision); + } + + return result; + } + + Rational Rational::And(Rational const& rhs, uint32_t radix, int32_t precision) const + { + PRAT lhsRat = this->ToPRAT(); + PRAT rhsRat = rhs.ToPRAT(); + + try + { + andrat(&lhsRat, rhsRat, radix, precision); + destroyrat(rhsRat); + } + catch (DWORD error) + { + destroyrat(lhsRat); + destroyrat(rhsRat); + throw(error); + } + + Rational result = Rational{ lhsRat }; + destroyrat(lhsRat); + + return result; + } + + Rational Rational::Or(Rational const& rhs, uint32_t radix, int32_t precision) const + { + PRAT lhsRat = this->ToPRAT(); + PRAT rhsRat = rhs.ToPRAT(); + try + { + orrat(&lhsRat, rhsRat, radix, precision); + destroyrat(rhsRat); + } + catch (DWORD error) + { + destroyrat(lhsRat); + destroyrat(rhsRat); + throw(error); + } + + Rational result = Rational{ lhsRat }; + destroyrat(lhsRat); + + return result; + } + + Rational Rational::Xor(Rational const& rhs, uint32_t radix, int32_t precision) const + { + PRAT lhsRat = this->ToPRAT(); + PRAT rhsRat = rhs.ToPRAT(); + try + { + xorrat(&lhsRat, rhsRat, radix, precision); + destroyrat(rhsRat); + } + catch (DWORD error) + { + destroyrat(lhsRat); + destroyrat(rhsRat); + throw(error); + } + + Rational result = Rational{ lhsRat }; + destroyrat(lhsRat); + + return result; + } + bool Rational::IsZero() const { return this->P().IsZero(); } + + bool Rational::IsLess(Rational const& r, int32_t precision) const + { + PRAT thisRat = this->ToPRAT(); + PRAT rRat = r.ToPRAT(); + + bool result = false; + try + { + result = rat_lt(thisRat, rRat, precision); + } + catch (DWORD error) + { + destroyrat(thisRat); + destroyrat(rRat); + throw(error); + } + + destroyrat(thisRat); + destroyrat(rRat); + + return result; + } + + bool Rational::IsLessEq(Rational const& r, int32_t precision) const + { + PRAT thisRat = this->ToPRAT(); + PRAT rRat = r.ToPRAT(); + + bool result = false; + try + { + result = rat_le(thisRat, rRat, precision); + } + catch (DWORD error) + { + destroyrat(thisRat); + destroyrat(rRat); + throw(error); + } + + destroyrat(thisRat); + destroyrat(rRat); + + return result; + } + + bool Rational::IsGreaterEq(Rational const& r, int32_t precision) const + { + PRAT thisRat = this->ToPRAT(); + PRAT rRat = r.ToPRAT(); + + bool result = false; + try + { + result = rat_ge(thisRat, rRat, precision); + } + catch (DWORD error) + { + destroyrat(thisRat); + destroyrat(rRat); + throw(error); + } + + destroyrat(thisRat); + destroyrat(rRat); + + return result; + } + + bool Rational::IsEq(Rational const& r, int32_t precision) const + { + PRAT thisRat = this->ToPRAT(); + PRAT rRat = r.ToPRAT(); + + bool result = false; + try + { + result = rat_equ(thisRat, rRat, precision); + } + catch (DWORD error) + { + destroyrat(thisRat); + destroyrat(rRat); + throw(error); + } + + destroyrat(thisRat); + destroyrat(rRat); + + return result; + } + + wstring Rational::ToString(uint32_t radix, NUMOBJ_FMT fmt, int32_t precision) const + { + PRAT rat = this->ToPRAT(); + wstring result{}; + + try + { + result = RatToString(rat, fmt, radix, precision); + } + catch (DWORD error) + { + destroyrat(rat); + throw(error); + } + + destroyrat(rat); + + return result; + } + + uint64_t Rational::ToUInt64_t(uint32_t radix, int32_t precision) const + { + PRAT rat = this->ToPRAT(); + uint64_t result; + try + { + result = rattoUlonglong(rat, radix, precision); + } + catch (DWORD error) + { + destroyrat(rat); + throw(error); + } + + destroyrat(rat); + + return result; + } } diff --git a/src/CalcManager/CEngine/calc.cpp b/src/CalcManager/CEngine/calc.cpp index d35a74e..229f278 100644 --- a/src/CalcManager/CEngine/calc.cpp +++ b/src/CalcManager/CEngine/calc.cpp @@ -1,29 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -/**************************************************************************\ - *** SCICALC Scientific Calculator for Windows 3.00.12 - *** (c)1989 Microsoft Corporation. All Rights Reserved. - *** - *** scimain.c - *** - *** Definitions of all globals, WinMain procedure - *** - *** Last modification - *** Fri 22-Nov-1996 - *** - *** 22-Nov-1996 - *** Converted Calc from floating point to infinite precision. - *** The new math engine is in ..\ratpak - *** - *** - *** 05-Jan-1990 - *** Calc did not have a floating point exception signal handler. This - *** would cause CALC to be forced to exit on a FP exception as that's - *** the default. - *** The signal handler is defined in SCIFUNC.C, in WinMain we hook the - *** the signal. -\**************************************************************************/ #include "pch.h" #include "Header Files/CalcEngine.h" @@ -46,9 +23,7 @@ static constexpr wstring_view DEFAULT_GRP_STR = L"3;0"; 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. A larger -// than needed block is allocated first and then reallocated once we -// know how much is actually used. +// These will be copied from the resources to local memory. array CCalcEngine::s_engineStrings; @@ -111,7 +86,7 @@ CCalcEngine::CCalcEngine(bool fPrecedence, bool fIntegerMode, CalculationManager m_numberString(DEFAULT_NUMBER_STR), m_nOp(), m_nPrecOp(), - m_memoryValue{make_unique()}, + m_memoryValue{ make_unique() }, m_holdVal{}, m_currentVal{}, m_lastVal{} @@ -120,12 +95,7 @@ CCalcEngine::CCalcEngine(bool fPrecedence, bool fIntegerMode, CalculationManager m_dwWordBitWidth = DwWordBitWidthFromeNumWidth(m_numwidth); - PRAT maxTrig = longtorat(10L); - PRAT hundred = longtorat(100L); - powrat(&maxTrig, hundred, m_radix, m_precision); - m_maxTrigonometricNum = Rational{ maxTrig }; - destroyrat(maxTrig); - destroyrat(hundred); + m_maxTrigonometricNum = RationalMath::Pow(10, 100, m_radix, m_precision); SetRadixTypeAndNumWidth(DEC_RADIX, m_numwidth); SettingsChanged(); @@ -147,14 +117,10 @@ void CCalcEngine::InitChopNumbers() assert(m_chopNumbers.size() == m_maxDecimalValueStrings.size()); for (size_t i = 0; i < m_chopNumbers.size(); i++) { - PRAT hno = m_chopNumbers[i].ToPRAT(); + auto maxVal = m_chopNumbers[i].Div(2, m_precision); + maxVal = RationalMath::Integer(maxVal, m_radix, m_precision); - divrat(&hno, rat_two, m_precision); - intrat(&hno, m_radix, m_precision); - - m_maxDecimalValueStrings[i] = NumObjToString(hno, 10, FMT_FLOAT, m_precision); - - NumObjDestroy(&hno); + m_maxDecimalValueStrings[i] = maxVal.ToString(10, FMT_FLOAT, m_precision); } } diff --git a/src/CalcManager/CEngine/scicomm.cpp b/src/CalcManager/CEngine/scicomm.cpp index 7dbbf02..9ecbdcb 100644 --- a/src/CalcManager/CEngine/scicomm.cpp +++ b/src/CalcManager/CEngine/scicomm.cpp @@ -32,21 +32,21 @@ using namespace CalcEngine; // 0 is returned. Higher the number, higher the precendence of the operator. INT NPrecedenceOfOp(int nopCode) { - static BYTE rgbPrec[]={ 0,0, IDC_OR,0, IDC_XOR,0, IDC_AND,1, + static BYTE 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}; + IDC_MOD,3, IDC_DIV,3, IDC_MUL,3, IDC_PWR,4, IDC_ROOT, 4 }; int iPrec; iPrec = 0; while ((iPrec < ARRAYSIZE(rgbPrec)) && (nopCode != rgbPrec[iPrec])) { iPrec += 2; - } + } if (iPrec >= ARRAYSIZE(rgbPrec)) { iPrec = 0; } - return rgbPrec[iPrec+1]; + return rgbPrec[iPrec + 1]; } @@ -77,13 +77,13 @@ void CCalcEngine::ClearTemporaryValues() m_input.Clear(); m_bRecord = true; CheckAndAddLastBinOpToHistory(); - DisplayNum (); - m_bError=false; + DisplayNum(); + m_bError = false; } void CCalcEngine::ProcessCommand(WPARAM wParam) { - if(wParam == IDC_SET_RESULT) + if (wParam == IDC_SET_RESULT) { wParam = IDC_RECALL; m_bSetCalcState = true; @@ -104,13 +104,13 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam) if (!IsGuiSettingOpCode(wParam)) { - m_nLastCom=m_nTempCom; - m_nTempCom=(INT)wParam; + m_nLastCom = m_nTempCom; + m_nTempCom = (INT)wParam; } if (m_bError) { - if(wParam == IDC_CLEAR) + if (wParam == IDC_CLEAR) { // handle "C" normally } @@ -129,23 +129,23 @@ void CCalcEngine::ProcessCommandWorker(WPARAM 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) || + 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. } - } + } else { - if ( IsDigitOpCode(wParam)|| wParam == IDC_PNT) + if (IsDigitOpCode(wParam) || wParam == IDC_PNT) { m_bRecord = true; m_input.Clear(); @@ -156,7 +156,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam) // Interpret digit keys. if (IsDigitOpCode(wParam)) { - unsigned int iValue = static_cast(wParam-IDC_0); + unsigned int iValue = static_cast(wParam - IDC_0); // this is redundant, illegal keys are disabled if (iValue >= static_cast(m_radix)) @@ -179,14 +179,14 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam) // BINARY OPERATORS: if (IsBinOpCode(wParam)) - { + { /* Change the operation if last input was operation. */ if (IsBinOpCode(m_nLastCom)) { INT nPrev; bool fPrecInvToHigher = false; // Is Precedence Invertion from lower to higher precedence happenning ?? - m_nOpCode =(INT)wParam; + m_nOpCode = (INT)wParam; // Check to see if by changing this binop, a Precedence invertion is happenning. // Eg. 1 * 2 + and + is getting changed to ^. The previous precedence rules would have already computed @@ -221,9 +221,9 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam) /* Scientific mode. */ if (m_bChangeOp) { -DoPrecedenceCheckAgain: + DoPrecedenceCheckAgain: - nx = NPrecedenceOfOp((int) wParam); + nx = NPrecedenceOfOp((int)wParam); ni = NPrecedenceOfOp(m_nOpCode); if ((nx > ni) && m_fPrecedence) @@ -237,7 +237,7 @@ DoPrecedenceCheckAgain: } else { - m_nPrecNum = MAXPRECDEPTH-1; + m_nPrecNum = MAXPRECDEPTH - 1; HandleErrorCommand(wParam); } m_nPrecNum++; @@ -253,13 +253,13 @@ DoPrecedenceCheckAgain: if (!m_bError) { - DisplayNum (); + DisplayNum(); } - if ((m_nPrecNum !=0) && (m_nPrecOp[m_nPrecNum-1])) + if ((m_nPrecNum != 0) && (m_nPrecOp[m_nPrecNum - 1])) { m_nPrecNum--; - m_nOpCode=m_nPrecOp[m_nPrecNum] ; + m_nOpCode = m_nPrecOp[m_nPrecNum]; m_lastVal = m_precedenceVals[m_nPrecNum]; @@ -274,7 +274,7 @@ DoPrecedenceCheckAgain: m_HistoryCollector.EnclosePrecInvertionBrackets(); } m_HistoryCollector.PopLastOpndStart(); - goto DoPrecedenceCheckAgain ; + goto DoPrecedenceCheckAgain; } } @@ -283,7 +283,7 @@ DoPrecedenceCheckAgain: DisplayAnnounceBinaryOperator(); m_lastVal = m_currentVal; - m_nOpCode=(INT)wParam; + m_nOpCode = (INT)wParam; m_HistoryCollector.AddBinOpToHistory(m_nOpCode); m_bNoPrevEqu = m_bChangeOp = true; return; @@ -292,7 +292,7 @@ DoPrecedenceCheckAgain: // UNARY OPERATORS: if (IsUnaryOpCode(wParam) || (wParam == IDC_DEGREES)) { - /* Functions are unary operations. */ + /* Functions are unary operations. */ /* If the last thing done was an operator, m_currentVal was cleared. */ /* In that case we better use the number before the operator */ /* was entered, otherwise, things like 5+ 1/x give Divide By */ @@ -304,7 +304,7 @@ DoPrecedenceCheckAgain: // we do not add percent sign to history or to two line display. // instead, we add the result of applying %. - if(wParam != IDC_PERCENT) + if (wParam != IDC_PERCENT) { if (!m_HistoryCollector.FOpndAddedToHistory()) { @@ -329,9 +329,9 @@ DoPrecedenceCheckAgain: return; /* Display the result, reset flags, and reset indicators. */ - DisplayNum (); + DisplayNum(); - if(wParam == IDC_PERCENT) + if (wParam == IDC_PERCENT) { CheckAndAddLastBinOpToHistory(); m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal, true /* Add to primary and secondary display */); @@ -343,8 +343,8 @@ DoPrecedenceCheckAgain: 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))) + (wParam == IDC_LN) || (wParam == IDC_DMS) || (wParam == IDC_DEGREES) || + (wParam == IDC_SINH) || (wParam == IDC_COSH) || (wParam == IDC_TANH))) { m_bInv = false; } @@ -353,7 +353,7 @@ DoPrecedenceCheckAgain: } // Tiny binary edit windows clicked. Toggle that bit and update display - if (IsOpInRange(wParam, IDC_BINEDITSTART, IDC_BINEDITSTART+63)) + if (IsOpInRange(wParam, IDC_BINEDITSTART, IDC_BINEDITSTART + 63)) { // Same reasoning as for unary operators. We need to seed it previous number if (m_nLastCom >= IDC_AND && m_nLastCom <= IDC_PWR) @@ -372,46 +372,46 @@ DoPrecedenceCheckAgain: } /* Now branch off to do other commands and functions. */ - switch(wParam) + switch (wParam) { case IDC_CLEAR: /* Total clear. */ - { - if (!m_bChangeOp) - { - // A special goody we are doing to preserve the history, if all was done was serious of unary operations last - CheckAndAddLastBinOpToHistory(false); - } - - m_lastVal = Rational{}; - - m_bChangeOp=false; - m_nPrecNum=m_nTempCom=m_nLastCom=m_nOpCode= m_openParenCount =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>>(), make_shared>>()); - } - - m_HistoryCollector.ClearHistoryLine(wstring()); - ClearTemporaryValues(); - } - break; - - case IDC_CENTR: /* Clear only temporary values. */ + { + if (!m_bChangeOp) { - // Clear the INV & leave (=xx indicator active - ClearTemporaryValues(); - } + // A special goody we are doing to preserve the history, if all was done was serious of unary operations last + CheckAndAddLastBinOpToHistory(false); + } - break; + m_lastVal = Rational{}; - case IDC_BACK: + m_bChangeOp = false; + m_nPrecNum = m_nTempCom = m_nLastCom = m_nOpCode = m_openParenCount = 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>>(), make_shared>>()); + } + + m_HistoryCollector.ClearHistoryLine(wstring()); + ClearTemporaryValues(); + } + break; + + case IDC_CENTR: /* Clear only temporary values. */ + { + // Clear the INV & leave (=xx indicator active + ClearTemporaryValues(); + } + + break; + + case IDC_BACK: // Divide number by the current radix and truncate. // Only allow backspace if we're recording. if (m_bRecord) @@ -427,7 +427,7 @@ DoPrecedenceCheckAgain: /* EQU enables the user to press it multiple times after and */ /* operation to enable repeats of the last operation. */ - case IDC_EQU: + case IDC_EQU: while (m_openParenCount > 0) { // when m_bError is set and m_ParNum is non-zero it goes into infinite loop @@ -487,15 +487,15 @@ DoPrecedenceCheckAgain: /* Check for errors. If this wasn't done, DisplayNum */ /* would immediately overwrite any error message. */ if (!m_bError) - DisplayNum (); + DisplayNum(); /* No longer the first EQU. */ - m_bNoPrevEqu= false; + m_bNoPrevEqu = false; } else if (!m_bError) DisplayNum(); - if (m_nPrecNum==0 || !m_fPrecedence) + if (m_nPrecNum == 0 || !m_fPrecedence) break; m_nOpCode = m_nPrecOp[--m_nPrecNum]; @@ -510,7 +510,7 @@ DoPrecedenceCheckAgain: } m_HistoryCollector.PopLastOpndStart(); - m_bNoPrevEqu= true; + m_bNoPrevEqu = true; } while (m_nPrecNum >= 0); if (!m_bError) @@ -523,17 +523,17 @@ DoPrecedenceCheckAgain: } } - m_bChangeOp=false; + m_bChangeOp = false; m_nPrevOpCode = 0; break; case IDC_OPENP: case IDC_CLOSEP: - nx=0; - if (wParam==IDC_OPENP) + nx = 0; + if (wParam == IDC_OPENP) { - nx=1; + nx = 1; } // -IF- the Paren holding array is full and we try to add a paren @@ -541,7 +541,7 @@ DoPrecedenceCheckAgain: // paren // -OR- the the precidence holding array is full if ((m_openParenCount >= MAXPRECDEPTH && nx) || (!m_openParenCount && !nx) - || ( (m_nPrecNum >= MAXPRECDEPTH && m_nPrecOp[m_nPrecNum-1]!=0) ) ) + || ((m_nPrecNum >= MAXPRECDEPTH && m_nPrecOp[m_nPrecNum - 1] != 0))) { HandleErrorCommand(wParam); break; @@ -570,9 +570,9 @@ DoPrecedenceCheckAgain: // treated as 1 + (3 m_currentVal = Rational{}; } - m_nTempCom=0; - m_nOpCode=0; - m_bChangeOp= false; // a ( is like starting a fresh sub equation + m_nTempCom = 0; + m_nOpCode = 0; + m_bChangeOp = false; // a ( is like starting a fresh sub equation } else { @@ -649,7 +649,7 @@ DoPrecedenceCheckAgain: case IDM_DWORD: case IDM_WORD: case IDM_BYTE: - if ( m_bRecord ) + if (m_bRecord) { m_currentVal = m_input.ToRational(m_radix, m_precision); m_bRecord = false; @@ -666,44 +666,41 @@ DoPrecedenceCheckAgain: break; case IDC_SIGN: + { + if (m_bRecord) { - if (m_bRecord) + if (m_input.TryToggleSign(m_fIntegerMode, m_maxDecimalValueStrings[m_numwidth])) { - if (m_input.TryToggleSign(m_fIntegerMode, m_maxDecimalValueStrings[m_numwidth])) - { - DisplayNum(); - } - else - { - HandleErrorCommand(wParam); - } - break; + DisplayNum(); } - - // Doing +/- while in Record mode is not a unary operation - if (IsBinOpCode(m_nLastCom)) + else { - m_currentVal = m_lastVal; + HandleErrorCommand(wParam); } - - if (!m_HistoryCollector.FOpndAddedToHistory()) - { - m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal); - } - - PRAT curRat = m_currentVal.ToPRAT(); - NumObjNegate(&curRat); - m_currentVal = Rational{ curRat }; - destroyrat(curRat); - - DisplayNum(); - m_HistoryCollector.AddUnaryOpToHistory(IDC_SIGN, m_bInv, m_angletype); + break; } - break; + + // Doing +/- while in Record mode is not a unary operation + if (IsBinOpCode(m_nLastCom)) + { + m_currentVal = m_lastVal; + } + + if (!m_HistoryCollector.FOpndAddedToHistory()) + { + m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal); + } + + m_currentVal = m_currentVal.Negate(); + + DisplayNum(); + m_HistoryCollector.AddUnaryOpToHistory(IDC_SIGN, m_bInv, m_angletype); + } + break; case IDC_RECALL: - if(m_bSetCalcState) + if (m_bSetCalcState) { // Not a Memory recall. set the result m_bSetCalcState = false; @@ -714,31 +711,25 @@ DoPrecedenceCheckAgain: m_currentVal = Rational{ *m_memoryValue }; } CheckAndAddLastBinOpToHistory(); - DisplayNum (); + DisplayNum(); break; case IDC_MPLUS: { /* MPLUS adds m_currentVal to immediate memory and kills the "mem" */ /* indicator if the result is zero. */ - PRAT memRat = m_memoryValue->ToPRAT(); - PRAT curRat = m_currentVal.ToPRAT(); - addrat(&memRat, curRat, m_precision); - m_memoryValue = make_unique(TruncateNumForIntMath(Rational{ memRat })); // Memory should follow the current int mode - destroyrat(curRat); - destroyrat(memRat); + Rational result = m_memoryValue->Add(m_currentVal, m_precision); + m_memoryValue = make_unique(TruncateNumForIntMath(result)); // Memory should follow the current int mode + break; } case IDC_MMINUS: { /* MMINUS subtracts m_currentVal to immediate memory and kills the "mem" */ /* indicator if the result is zero. */ - PRAT memRat = m_memoryValue->ToPRAT(); - PRAT curRat = m_currentVal.ToPRAT(); - subrat(&memRat, curRat, m_precision); - m_memoryValue = make_unique(TruncateNumForIntMath(Rational{ memRat })); - destroyrat(curRat); - destroyrat(memRat); + Rational result = m_memoryValue->Sub(m_currentVal, m_precision); + m_memoryValue = make_unique(TruncateNumForIntMath(result)); + break; } case IDC_STORE: @@ -784,7 +775,7 @@ DoPrecedenceCheckAgain: break; case IDC_INV: - m_bInv=!m_bInv; + m_bInv = !m_bInv; break; } @@ -1011,18 +1002,13 @@ int CCalcEngine::IdcSetAngleTypeDecMode(int idc) bool CCalcEngine::IsCurrentTooBigForTrig() { - bool result = false; - PRAT maxTrigRat = m_maxTrigonometricNum.ToPRAT(); - PRAT curRat = m_currentVal.ToPRAT(); - if (NumObjIsGreaterEq(curRat, maxTrigRat, m_precision)) + if (m_currentVal.IsGreaterEq(m_maxTrigonometricNum, m_precision)) { m_currentVal = Rational{}; - result = true; + return true; } - destroyrat(curRat); - destroyrat(maxTrigRat); - return result; + return false; } int CCalcEngine::GetCurrentRadix() @@ -1052,39 +1038,30 @@ wstring CCalcEngine::GetStringForDisplay(Rational const& rat, uint32_t radix) // Check for standard\scientific mode if (!m_fIntegerMode) { - PRAT prat = rat.ToPRAT(); - result = NumObjToString(prat, radix, m_nFE, m_precision); - destroyrat(prat); + result = rat.ToString(radix, m_nFE, m_precision); } else { // Programmer mode // Find most significant bit to determine if number is negative - PRAT hnoNumCopy = TruncateNumForIntMath(rat).ToPRAT(); + auto tempRat = TruncateNumForIntMath(rat); try { - ULONGLONG w64Bits = NumObjGetUlValue(hnoNumCopy, m_radix, m_precision); + uint64_t w64Bits = tempRat.ToUInt64_t(m_radix, m_precision); bool fMsb = ((w64Bits >> (m_dwWordBitWidth - 1)) & 1); if ((radix == 10) && fMsb) { - // If high bit is set, then get the decimal number in -ve 2'scompl form. - PRAT chopRat = m_chopNumbers[m_numwidth].ToPRAT(); - NumObjNot(&hnoNumCopy, true, chopRat, m_radix, m_precision); - destroyrat(chopRat); - addrat(&hnoNumCopy, rat_one, m_precision); - NumObjNegate(&hnoNumCopy); + // If high bit is set, then get the decimal number in negative 2's compl form. + tempRat = tempRat.Not(true, m_chopNumbers[m_numwidth], m_radix, m_precision); + tempRat = tempRat.Add(1, m_precision); + tempRat = tempRat.Negate(); } - result = NumObjToString(hnoNumCopy, radix, m_nFE, m_precision); - NumObjDestroy(&hnoNumCopy); + result = tempRat.ToString(radix, m_nFE, m_precision); } catch (DWORD) { - if (hnoNumCopy != nullptr) - { - NumObjDestroy(&hnoNumCopy); - } } } diff --git a/src/CalcManager/CEngine/scidisp.cpp b/src/CalcManager/CEngine/scidisp.cpp index 088ad75..b1f26e3 100644 --- a/src/CalcManager/CEngine/scidisp.cpp +++ b/src/CalcManager/CEngine/scidisp.cpp @@ -36,7 +36,7 @@ constexpr wstring_view c_decPostSepStr = L"]?(\\d*)(?:e[+-]?(\\d*))?$"; // State of calc last time DisplayNum was called // typedef struct { - PRAT hnoNum; + Rational value; int32_t precision; uint32_t radix; INT nFE; @@ -46,7 +46,7 @@ typedef struct { bool bUseSep; } LASTDISP; -LASTDISP gldPrevious = { nullptr, -1, 0, -1, (NUM_WIDTH)-1, false, false, false }; +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) @@ -56,27 +56,20 @@ CalcEngine::Rational CCalcEngine::TruncateNumForIntMath(CalcEngine::Rational con return rat; } - PRAT tempRat = rat.ToPRAT(); - // Truncate to an integer. Do not round here. - intrat(&tempRat, m_radix, m_precision); + auto result = RationalMath::Integer(rat, m_radix, m_precision); - PRAT chopRat = m_chopNumbers[m_numwidth].ToPRAT(); - // Can be converting a dec -ve number to Hex/Oct/Bin rep. Use 2's completement form + // Can be converting a dec negative number to Hex/Oct/Bin rep. Use 2's complement form // Check the range. - if (NumObjIsLess(tempRat, rat_zero, m_precision)) + if (result.IsLess(0, m_precision)) { // if negative make positive by doing a twos complement - NumObjNegate(&tempRat); - subrat(&tempRat, rat_one, m_precision); - NumObjNot(&tempRat, true, chopRat, m_radix, m_precision); + result = result.Negate(); + result = result.Sub(1, m_precision); + result = result.Not(true /* IntegerMode */, m_chopNumbers[m_numwidth], m_radix, m_precision); } - andrat(&tempRat, chopRat, m_radix, m_precision); - destroyrat(chopRat); - - Rational result{ tempRat }; - destroyrat(tempRat); + result = result.And(m_chopNumbers[m_numwidth], m_radix, m_precision); return result; } @@ -90,27 +83,24 @@ void CCalcEngine::DisplayNum(void) // something important has changed since the last time DisplayNum was // called. // - PRAT curRat = m_currentVal.ToPRAT(); - bool hasValChanged = !gldPrevious.hnoNum || !NumObjIsEq(gldPrevious.hnoNum, curRat, m_precision); - destroyrat(curRat); - if ( m_bRecord || gldPrevious.hnoNum == nullptr || - hasValChanged || - 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.IsEq(m_currentVal, m_precision) || + 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; - gldPrevious.nFE = (int)m_nFE; - gldPrevious.numwidth = m_numwidth; + gldPrevious.nFE = (int)m_nFE; + gldPrevious.numwidth = m_numwidth; - gldPrevious.fIntMath = m_fIntegerMode; - gldPrevious.bRecord = m_bRecord; - gldPrevious.bUseSep = true; + gldPrevious.fIntMath = m_fIntegerMode; + gldPrevious.bRecord = m_bRecord; + gldPrevious.bUseSep = true; if (m_bRecord) { @@ -128,10 +118,9 @@ void CCalcEngine::DisplayNum(void) } // Displayed number can go thru transformation. So copy it after transformation - destroyrat(gldPrevious.hnoNum); - gldPrevious.hnoNum = m_currentVal.ToPRAT(); + gldPrevious.value = m_currentVal; - if((m_radix == 10) && IsNumberInvalid(m_numberString, MAX_EXPONENT, m_precision, m_radix)) + if ((m_radix == 10) && IsNumberInvalid(m_numberString, MAX_EXPONENT, m_precision, m_radix)) { DisplayError(CALC_E_OVERFLOW); } @@ -268,7 +257,7 @@ wstring CCalcEngine::GroupDigitsPerRadix(wstring_view numberString, uint32_t rad switch (radix) { case 10: - return GroupDigits(wstring{ m_groupSeparator }, m_decGrouping, numberString, (L'-' == numberString[0])); + return GroupDigits(wstring{ m_groupSeparator }, m_decGrouping, numberString, (L'-' == numberString[0])); case 8: return GroupDigits(L" ", { 3, 0 }, numberString); case 2: diff --git a/src/CalcManager/CEngine/scifunc.cpp b/src/CalcManager/CEngine/scifunc.cpp index f459757..26daf23 100644 --- a/src/CalcManager/CEngine/scifunc.cpp +++ b/src/CalcManager/CEngine/scifunc.cpp @@ -21,273 +21,193 @@ using namespace std; using namespace CalcEngine; +using namespace CalcEngine::RationalMath; /* Routines for more complex mathematical functions/error checking. */ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& rat, DWORD op) { - PRAT tempRat = rat.ToPRAT(); + Rational result{}; try { switch (op) { - case IDC_CHOP: - m_bInv ? fracrat(&tempRat , m_radix, m_precision) : intrat(&tempRat, m_radix, m_precision); - break; + case IDC_CHOP: + result = m_bInv ? Frac(rat, m_radix, m_precision) : Integer(rat, m_radix, m_precision); + break; /* Return complement. */ - case IDC_COM: - { - PRAT chopRat = m_chopNumbers[m_numwidth].ToPRAT(); - NumObjNot(&tempRat, m_fIntegerMode, chopRat, m_radix, m_precision); - destroyrat(chopRat); - break; - } + case IDC_COM: + result = rat.Not(m_fIntegerMode, m_chopNumbers[m_numwidth], m_radix, m_precision); + break; // Rotate Left with hi bit wrapped over to lo bit - case IDC_ROL: - if (m_fIntegerMode) - { - intrat(&tempRat, m_radix, m_precision); + case IDC_ROL: + if (m_fIntegerMode) + { + result = Integer(rat, m_radix, m_precision); - PRAT curRat = m_currentVal.ToPRAT(); - ULONGLONG w64Bits = NumObjGetUlValue(curRat, m_radix, m_precision); - ULONGLONG msb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1; + uint64_t w64Bits = result.ToUInt64_t(m_radix, m_precision); + uint64_t msb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1; + w64Bits <<= 1; // LShift by 1 + w64Bits |= msb; // Set the prev Msb as the current Lsb - w64Bits <<= 1; // LShift by 1 - w64Bits |= msb; // Set the prev Msb as the current Lsb - NumObjSetUlonglongValue(&curRat, w64Bits, m_radix, m_precision); - m_currentVal = Rational{ curRat }; - destroyrat(curRat); - } - break; + result = Rational{ w64Bits, m_radix, m_precision }; + } + break; // Rotate right with lo bit wrapped over to hi bit - case IDC_ROR: - if (m_fIntegerMode) - { - intrat(&tempRat, m_radix, m_precision); - PRAT curRat = m_currentVal.ToPRAT(); - ULONGLONG w64Bits = NumObjGetUlValue(curRat, m_radix, m_precision); - - ULONGLONG lsb = ((w64Bits & 0x01) == 1) ? 1 : 0; - w64Bits >>= 1; //RShift by 1 - w64Bits |= (lsb << (m_dwWordBitWidth - 1)); - NumObjSetUlonglongValue(&curRat, w64Bits, m_radix, m_precision); - m_currentVal = Rational{ curRat }; - destroyrat(curRat); - } - break; - - case IDC_PERCENT: + case IDC_ROR: + if (m_fIntegerMode) { - PRAT hno = nullptr; - PRAT hno100 = nullptr; + result = Integer(rat, m_radix, m_precision); - try - { - // If the operator is multiply/divide, we evaluate this as "X [op] (Y%)" - // Otherwise, we evaluate it as "X [op] (X * Y%)" - if (m_nOpCode == IDC_MUL || m_nOpCode == IDC_DIV) - { - NumObjSetIntValue(&hno100, 100); + uint64_t w64Bits = result.ToUInt64_t(m_radix, m_precision); + uint64_t lsb = ((w64Bits & 0x01) == 1) ? 1 : 0; + w64Bits >>= 1; //RShift by 1 + w64Bits |= (lsb << (m_dwWordBitWidth - 1)); - divrat(&tempRat, hno100, m_precision); - destroyrat(hno100); - } - else - { - hno = m_lastVal.ToPRAT(); - NumObjSetIntValue(&hno100, 100); - - divrat(&hno, hno100, m_precision); - destroyrat(hno100); - - mulrat(&tempRat, hno, m_precision); - destroyrat(hno); - } - } - catch ( DWORD nErrCode ) - { - destroyrat(hno); - destroyrat(hno100); - destroyrat(tempRat); - throw nErrCode; - } - break; + result = Rational{ w64Bits, m_radix, m_precision }; } + break; - case IDC_SIN: /* Sine; normal and arc */ - if (!m_fIntegerMode) - { - m_bInv ? asinanglerat(&tempRat, m_angletype, m_radix, m_precision) : NumObjSin(&tempRat, m_angletype, m_radix, m_precision); - } - break; - - case IDC_SINH: /* Sine- hyperbolic and archyperbolic */ - if (!m_fIntegerMode) - { - m_bInv ? asinhrat(&tempRat, m_radix, m_precision) : sinhrat(&tempRat, m_radix, m_precision); - } - break; - - case IDC_COS: /* Cosine, follows convention of sine function. */ - if (!m_fIntegerMode) - { - m_bInv ? acosanglerat(&tempRat, m_angletype, m_radix, m_precision) : NumObjCos(&tempRat, m_angletype, m_radix, m_precision); - } - break; - - case IDC_COSH: /* Cosine hyperbolic, follows convention of sine h function. */ - if (!m_fIntegerMode) - { - m_bInv ? acoshrat(&tempRat, m_radix, m_precision) : coshrat(&tempRat, m_radix, m_precision); - } - break; - - case IDC_TAN: /* Same as sine and cosine. */ - if (!m_fIntegerMode) - { - m_bInv ? atananglerat(&tempRat, m_angletype, m_radix, m_precision) : NumObjTan(&tempRat, m_angletype, m_radix, m_precision); - } - break; - - case IDC_TANH: /* Same as sine h and cosine h. */ - if (!m_fIntegerMode) - { - m_bInv ? atanhrat(&tempRat, m_precision) : tanhrat(&tempRat, m_radix, m_precision); - } - break; - - case IDC_REC: /* Reciprocal. */ - NumObjInvert(&tempRat, m_precision); - break; - - case IDC_SQR: /* Square */ - powrat(&tempRat, rat_two, m_radix, m_precision); - break; - - case IDC_SQRT: /* Sqrt only in Std mode */ - rootrat(&tempRat, rat_two, m_radix, m_precision); - break; - - case IDC_CUBEROOT: - case IDC_CUB: /* Cubing and cube root functions. */ + case IDC_PERCENT: + { + // If the operator is multiply/divide, we evaluate this as "X [op] (Y%)" + // Otherwise, we evaluate it as "X [op] (X * Y%)" + if (m_nOpCode == IDC_MUL || m_nOpCode == IDC_DIV) { - PRAT hno = nullptr; - - try - { - NumObjAssign(&hno, rat_one); - addrat(&hno, rat_two, m_precision); - - if (IDC_CUBEROOT == op) - { - rootrat(&tempRat, hno, m_radix, m_precision); - } - else - { - powrat(&tempRat, hno, m_radix, m_precision); - } - - destroyrat(hno); - } - catch (DWORD nErrCode) - { - destroyrat(hno); - destroyrat(tempRat); - throw nErrCode; - } - break; + result = rat.Div(100, m_precision); } - - case IDC_LOG: /* Functions for common log. */ - log10rat(&tempRat, m_precision); - break; - case IDC_POW10: - NumObjAntiLog10(&tempRat, m_radix, m_precision); - break; - case IDC_LN: /* Functions for natural log. */ - if (m_bInv) - { - exprat(&tempRat, m_radix, m_precision); // e^x. - } - else - { - lograt(&tempRat, m_precision); - } - break; - - case IDC_FAC: /* Calculate factorial. Inverse is ineffective. */ - factrat(&tempRat, m_radix, m_precision); - break; - - case IDC_DEGREES: - ProcessCommand(IDC_INV); - // 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 - // are set properly through ProcessCommand(IDC_INV) - case IDC_DMS: + else { - if (!m_fIntegerMode) - { - PRAT hnoMin = nullptr; - PRAT hnoSec = nullptr; - PRAT hnoShft = nullptr; - - try - { - NumObjSetIntValue(&hnoShft, m_bInv ? 100 : 60); - - NumObjAssign(&hnoMin, tempRat); - intrat(&tempRat, m_radix, m_precision); - - subrat(&hnoMin, tempRat, m_precision); - mulrat(&hnoMin, hnoShft, m_precision); - NumObjAssign(&hnoSec, hnoMin ); - intrat(&hnoMin, m_radix, m_precision); - - subrat(&hnoSec, hnoMin, m_precision); - mulrat(&hnoSec, hnoShft, m_precision); - - // - // tempRat == degrees, hnoMin == minutes, hnoSec == seconds - // - - NumObjSetIntValue(&hnoShft, m_bInv ? 60 : 100); - divrat(&hnoSec, hnoShft, m_precision); - addrat(&hnoMin, hnoSec, m_precision); - - divrat(&hnoMin, hnoShft, m_precision); - addrat(&tempRat, hnoMin, m_precision); - - destroyrat(hnoShft); - destroyrat(hnoMin); - destroyrat(hnoSec); - } - catch (DWORD nErrCode) - { - destroyrat(hnoShft); - destroyrat(hnoMin); - destroyrat(hnoSec); - destroyrat(tempRat); - throw nErrCode; - } - } - break; + result = m_lastVal.Div(100, m_precision); + result = rat.Mul(result, m_precision); } + break; + } + + case IDC_SIN: /* Sine; normal and arc */ + if (!m_fIntegerMode) + { + result = m_bInv ? ASin(rat, m_angletype, m_radix, m_precision) : Sin(rat, m_angletype, m_radix, m_precision); + } + break; + + case IDC_SINH: /* Sine- hyperbolic and archyperbolic */ + if (!m_fIntegerMode) + { + result = m_bInv ? ASinh(rat, m_radix, m_precision) : Sinh(rat, m_radix, m_precision); + } + break; + + case IDC_COS: /* Cosine, follows convention of sine function. */ + if (!m_fIntegerMode) + { + result = m_bInv ? ACos(rat, m_angletype, m_radix, m_precision) : Cos(rat, m_angletype, m_radix, m_precision); + } + break; + + case IDC_COSH: /* Cosine hyperbolic, follows convention of sine h function. */ + if (!m_fIntegerMode) + { + result = m_bInv ? ACosh(rat, m_radix, m_precision) : Cosh(rat, m_radix, m_precision); + } + break; + + case IDC_TAN: /* Same as sine and cosine. */ + if (!m_fIntegerMode) + { + result = m_bInv ? ATan(rat, m_angletype, m_radix, m_precision) : Tan(rat, m_angletype, m_radix, m_precision); + } + break; + + case IDC_TANH: /* Same as sine h and cosine h. */ + if (!m_fIntegerMode) + { + result = m_bInv ? ATanh(rat, m_precision) : Tanh(rat, m_radix, m_precision); + } + break; + + case IDC_REC: /* Reciprocal. */ + result = Invert(rat, m_precision); + break; + + case IDC_SQR: /* Square */ + result = Pow(rat, 2, m_radix, m_precision); + break; + + case IDC_SQRT: /* Square Root */ + result = Root(rat, 2, m_radix, m_precision); + break; + + case IDC_CUBEROOT: + case IDC_CUB: /* Cubing and cube root functions. */ + result = IDC_CUBEROOT == op ? Root(rat, 3, m_radix, m_precision) : Pow(rat, 3, m_radix, m_precision); + break; + + case IDC_LOG: /* Functions for common log. */ + result = Log10(rat, m_precision); + break; + + case IDC_POW10: + result = Pow(10, rat, m_radix, m_precision); + break; + + case IDC_LN: /* Functions for natural log. */ + result = m_bInv ? Exp(rat, m_radix, m_precision) : Log(rat, m_precision); + break; + + case IDC_FAC: /* Calculate factorial. Inverse is ineffective. */ + result = Fact(rat, m_radix, m_precision); + break; + + case IDC_DEGREES: + ProcessCommand(IDC_INV); + // 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 + // are set properly through ProcessCommand(IDC_INV) + case IDC_DMS: + { + if (!m_fIntegerMode) + { + Rational shftRat{ m_bInv ? 100 : 60 }; + + Rational degreeRat = Integer(rat, m_radix, m_precision); + + Rational minuteRat = rat.Sub(degreeRat, m_precision); + minuteRat = minuteRat.Mul(shftRat, m_precision); + + Rational secondRat = minuteRat; + + minuteRat = Integer(minuteRat, m_radix, m_precision); + + secondRat = secondRat.Sub(minuteRat, m_precision); + secondRat = secondRat.Mul(shftRat, m_precision); + + // + // degreeRat == degrees, minuteRat == minutes, secondRat == seconds + // + + shftRat = Rational{ m_bInv ? 60 : 100 }; + secondRat = secondRat.Div(shftRat, m_precision); + + minuteRat = minuteRat.Add(secondRat, m_precision); + minuteRat = minuteRat.Div(shftRat, m_precision); + + result = degreeRat.Add(minuteRat, m_precision); + } + break; + } } // end switch( op ) - - Rational result{ tempRat }; - destroyrat(tempRat); - return result; } - catch(DWORD nErrCode) + catch (DWORD nErrCode) { DisplayError(nErrCode); - destroyrat(tempRat); - return rat; + result = rat; } + + return result; } /* Routine to display error messages and set m_bError flag. Errors are */ diff --git a/src/CalcManager/CEngine/scimath.cpp b/src/CalcManager/CEngine/scimath.cpp index 1a8b0ea..b1fc77a 100644 --- a/src/CalcManager/CEngine/scimath.cpp +++ b/src/CalcManager/CEngine/scimath.cpp @@ -3,204 +3,388 @@ #include "pch.h" #include "Header Files/CalcEngine.h" +#include "Ratpack/ratpak.h" using namespace std; +using namespace CalcEngine; -/**************************************************************************\ -* * -* * -* * -* # # ##### * -* # # # # # * -* # # # # # # # * -* # ### ### # # * -* # # ### # # # ### # # ### ##### # ### ### ### * -* # ## # # # ## # # # # # # ## # # # * -* # # # # # # # # # ##### # # ##### # * -* # # # # # # # # # # # # # # ## * -* # # # # # # # # # ### # # ### ### ## * -* * -* * -* Infinte Precision Production Version * -* * -\**************************************************************************/ -// -// RETAIL version of NUMOBJ math that uses Infinite Precision -// -// History -// -// 16-Nov-1996 Wrote it -// whenever-97 Rewrote it using improved ratpak model -// - -/*****************************************************************\ -* -* Generic Math Package support routines and variables -* -* History: -* 01-Dec-1996 Wrote them -* whenever-97 Rewrote them -* -\*****************************************************************/ - -/*****************************************************************\ -* -* Unary functions -* -* History: -* 01-Dec-1996 Wrote them -* whenever-97 Rewrote them -* -\*****************************************************************/ - -void NumObjInvert(PRAT * phno, int32_t precision) +Rational RationalMath::Frac(Rational const& rat, uint32_t radix, int32_t precision) { - PRAT hno = nullptr; - - NumObjAssign( &hno, rat_one); - divrat( &hno, *phno, precision); - NumObjAssign( phno, hno ); - NumObjDestroy( &hno ); -} - -void NumObjNegate(PRAT *phno) -{ - (*phno)->pp->sign = -(*phno)->pp->sign; -} - -void NumObjAbs(PRAT *phno) -{ - (*phno)->pp->sign = 1; - (*phno)->pq->sign = 1; -} - -void NumObjAntiLog10(PRAT *phno, uint32_t radix, int32_t precision) -{ - PRAT hno = nullptr; - - NumObjSetIntValue( &hno, 10 ); - powrat( &hno, *phno, radix, precision); - NumObjAssign( phno, hno ); - NumObjDestroy( &hno ); -} - -void NumObjNot(PRAT *phno, bool fIntegerMode, PRAT chopNum, uint32_t radix, int32_t precision) -{ - if (radix == 10 && !fIntegerMode) + PRAT prat = rat.ToPRAT(); + try { - intrat( phno, radix, precision); - addrat( phno, rat_one, precision); - NumObjNegate( phno ); + fracrat(&prat, radix, precision); } - else + catch (DWORD error) { - - xorrat( phno, chopNum, radix, precision); + destroyrat(prat); + throw(error); } + + Rational result{ prat }; + destroyrat(prat); + + return result; } -void NumObjSin(PRAT *phno, ANGLE_TYPE angletype, uint32_t radix, int32_t precision ) +Rational RationalMath::Integer(Rational const& rat, uint32_t radix, int32_t precision) { - sinanglerat(phno, angletype, radix, precision); + PRAT prat = rat.ToPRAT(); + try + { + intrat(&prat, radix, precision); + } + catch (DWORD error) + { + destroyrat(prat); + throw(error); + } + + Rational result{ prat }; + destroyrat(prat); + + return result; } -void NumObjCos(PRAT *phno, ANGLE_TYPE angletype, uint32_t radix, int32_t precision) +Rational RationalMath::Pow(Rational const& base, Rational const& pow, uint32_t radix, int32_t precision) { - cosanglerat(phno, angletype, radix, precision); + PRAT baseRat = base.ToPRAT(); + PRAT powRat = pow.ToPRAT(); + + try + { + powrat(&baseRat, powRat, radix, precision); + destroyrat(powRat); + } + catch (DWORD error) + { + destroyrat(baseRat); + destroyrat(powRat); + throw(error); + } + + Rational result{ baseRat }; + destroyrat(baseRat); + + return result; } -void NumObjTan(PRAT *phno, ANGLE_TYPE angletype, uint32_t radix, int32_t precision) +Rational RationalMath::Root(Rational const& base, Rational const& root, uint32_t radix, int32_t precision) { - tananglerat(phno, angletype, radix, precision); + return Pow(base, Invert(root, precision), radix, precision); } -/******************************************************************\ -* -* Number format conversion routines -* -* History: -* 06-Dec-1996 wrote them -\******************************************************************/ -void NumObjSetIntValue(PRAT *phnol, LONG i ) +Rational RationalMath::Fact(Rational const& rat, uint32_t radix, int32_t precision) { - PRAT pr = nullptr; + PRAT prat = rat.ToPRAT(); - pr = longtorat( i ); - NumObjAssign( phnol, pr ); - destroyrat(pr); + try + { + factrat(&prat, radix, precision); + } + catch (DWORD error) + { + destroyrat(prat); + throw(error); + } + + Rational result{ prat }; + destroyrat(prat); + + return result; } -void NumObjSetIUlongValue(PRAT *phnol, ULONG ul ) +Rational RationalMath::Exp(Rational const& rat, uint32_t radix, int32_t precision) { - PRAT pr = nullptr; + PRAT prat = rat.ToPRAT(); - pr = Ulongtorat( ul ); - NumObjAssign( phnol, pr ); - destroyrat(pr); + try + { + exprat(&prat, radix, precision); + } + catch (DWORD error) + { + destroyrat(prat); + throw(error); + } + + Rational result{ prat }; + destroyrat(prat); + + return result; } -// A Set with 64 bit number -void NumObjSetUlonglongValue(PRAT *phnol, ULONGLONG ul, uint32_t radix, int32_t precision) +Rational RationalMath::Log(Rational const& rat, int32_t precision) { - ULONG hi, lo; - PRAT hno = nullptr; + PRAT prat = rat.ToPRAT(); - hi = HIDWORD(ul); - lo = LODWORD(ul); - NumObjSetIUlongValue(phnol, hi); - NumObjSetIntValue(&hno, 32); - lshrat(phnol, hno, radix, precision); - NumObjSetIUlongValue(&hno, lo); - orrat(phnol, hno, radix, precision); - NumObjDestroy(&hno); + try + { + lograt(&prat, precision); + } + catch (DWORD error) + { + destroyrat(prat); + throw(error); + } + + Rational result{ prat }; + destroyrat(prat); + + return result; } -ULONGLONG NumObjGetUlValue( PRAT hnol, uint32_t radix, int32_t precision) +Rational RationalMath::Log10(Rational const& rat, int32_t precision) { - return rattoUlonglong(hnol, radix, precision); + return Log(rat, precision).Div(10, precision); } -wstring NumObjToString(PRAT hnoNum, uint32_t radix, NUMOBJ_FMT fmt, int32_t precision) +Rational RationalMath::Invert(Rational const& rat, int32_t precision) { - return RatToString(hnoNum, fmt, radix, precision); + return Rational{ 1 }.Div(rat, precision); } -bool NumObjIsZero(PRAT hno) +Rational RationalMath::Abs(Rational const& rat) { - return zerrat(hno); + return Rational{ Number{ 1, rat.P().Exp(), rat.P().Mantissa() }, Number{ 1, rat.Q().Exp(), rat.Q().Mantissa() } }; } -bool NumObjIsLess(PRAT hno1, PRAT hno2, int32_t precision) +Rational RationalMath::Sin(Rational const& rat, ANGLE_TYPE angletype, uint32_t radix, int32_t precision) { - return rat_lt(hno1, hno2, precision); + PRAT prat = rat.ToPRAT(); + + try + { + sinanglerat(&prat, angletype, radix, precision); + } + catch (DWORD error) + { + destroyrat(prat); + throw(error); + } + + Rational result{ prat }; + destroyrat(prat); + + return result; } -bool NumObjIsLessEq(PRAT hno1, PRAT hno2, int32_t precision) +Rational RationalMath::Cos(Rational const& rat, ANGLE_TYPE angletype, uint32_t radix, int32_t precision) { - return rat_le(hno1, hno2, precision); + PRAT prat = rat.ToPRAT(); + + try + { + cosanglerat(&prat, angletype, radix, precision); + } + catch (DWORD error) + { + destroyrat(prat); + throw(error); + } + + Rational result{ prat }; + destroyrat(prat); + + return result; } -bool NumObjIsGreaterEq(PRAT hno1, PRAT hno2, int32_t precision) +Rational RationalMath::Tan(Rational const& rat, ANGLE_TYPE angletype, uint32_t radix, int32_t precision) { - return rat_ge(hno1, hno2, precision); + PRAT prat = rat.ToPRAT(); + + try + { + tananglerat(&prat, angletype, radix, precision); + } + catch (DWORD error) + { + destroyrat(prat); + throw(error); + } + + Rational result{ prat }; + destroyrat(prat); + + return result; } -bool NumObjIsEq(PRAT hno1, PRAT hno2, int32_t precision) +Rational RationalMath::ASin(Rational const& rat, ANGLE_TYPE angletype, uint32_t radix, int32_t precision) { - return rat_equ(hno1, hno2, precision); + PRAT prat = rat.ToPRAT(); + + try + { + asinanglerat(&prat, angletype, radix, precision); + } + catch (DWORD error) + { + destroyrat(prat); + throw(error); + } + + Rational result{ prat }; + destroyrat(prat); + + return result; } -void NumObjAssign(PRAT *phnol, PRAT hnor) +Rational RationalMath::ACos(Rational const& rat, ANGLE_TYPE angletype, uint32_t radix, int32_t precision) { - DUPRAT(*phnol, hnor); + PRAT prat = rat.ToPRAT(); + + try + { + acosanglerat(&prat, angletype, radix, precision); + } + catch (DWORD error) + { + destroyrat(prat); + throw(error); + } + + Rational result{ prat }; + destroyrat(prat); + + return result; } -int32_t NumObjGetExp(PRAT hno) +Rational RationalMath::ATan(Rational const& rat, ANGLE_TYPE angletype, uint32_t radix, int32_t precision) { - return LOGRATRADIX(hno); + PRAT prat = rat.ToPRAT(); + + try + { + atananglerat(&prat, angletype, radix, precision); + } + catch (DWORD error) + { + destroyrat(prat); + throw(error); + } + + Rational result{ prat }; + destroyrat(prat); + + return result; } -void NumObjDestroy(PRAT *phno) +Rational RationalMath::Sinh(Rational const& rat, uint32_t radix, int32_t precision) { - destroyrat(*phno); + PRAT prat = rat.ToPRAT(); + + try + { + sinhrat(&prat, radix, precision); + } + catch (DWORD error) + { + destroyrat(prat); + throw(error); + } + + Rational result{ prat }; + destroyrat(prat); + + return result; +} + +Rational RationalMath::Cosh(Rational const& rat, uint32_t radix, int32_t precision) +{ + PRAT prat = rat.ToPRAT(); + + try + { + coshrat(&prat, radix, precision); + } + catch (DWORD error) + { + destroyrat(prat); + throw(error); + } + + Rational result{ prat }; + destroyrat(prat); + + return result; +} + +Rational RationalMath::Tanh(Rational const& rat, uint32_t radix, int32_t precision) +{ + PRAT prat = rat.ToPRAT(); + + try + { + tanhrat(&prat, radix, precision); + } + catch (DWORD error) + { + destroyrat(prat); + throw(error); + } + + Rational result{ prat }; + destroyrat(prat); + + return result; +} + +Rational RationalMath::ASinh(Rational const& rat, uint32_t radix, int32_t precision) +{ + PRAT prat = rat.ToPRAT(); + + try + { + asinhrat(&prat, radix, precision); + } + catch (DWORD error) + { + destroyrat(prat); + throw(error); + } + + Rational result{ prat }; + destroyrat(prat); + + return result; +} + +Rational RationalMath::ACosh(Rational const& rat, uint32_t radix, int32_t precision) +{ + PRAT prat = rat.ToPRAT(); + + try + { + acoshrat(&prat, radix, precision); + } + catch (DWORD error) + { + destroyrat(prat); + throw(error); + } + + Rational result{ prat }; + destroyrat(prat); + + return result; +} + +Rational RationalMath::ATanh(Rational const& rat, int32_t precision) +{ + PRAT prat = rat.ToPRAT(); + + try + { + atanhrat(&prat, precision); + } + catch (DWORD error) + { + destroyrat(prat); + throw(error); + } + + Rational result{ prat }; + destroyrat(prat); + + return result; } diff --git a/src/CalcManager/CEngine/scioper.cpp b/src/CalcManager/CEngine/scioper.cpp index 5e78bd8..fae2f15 100644 --- a/src/CalcManager/CEngine/scioper.cpp +++ b/src/CalcManager/CEngine/scioper.cpp @@ -5,181 +5,135 @@ #include "Header Files/CalcEngine.h" using namespace CalcEngine; +using namespace CalcEngine::RationalMath; // Routines to perform standard operations &|^~<<>>+-/*% and pwr. CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rational const& lhs, CalcEngine::Rational const& rhs) { - PRAT rhsRat = rhs.ToPRAT(); - PRAT hno = nullptr; - // Remove any variance in how 0 could be represented in rat e.g. -0, 0/n, etc. - PRAT resultRat = nullptr; - if (lhs.IsZero()) - { - NumObjAssign(&resultRat, rat_zero); - } - else - { - resultRat = lhs.ToPRAT(); - } + auto result = (!lhs.IsZero() ? lhs : Rational{}); try { switch (operation) { case IDC_AND: - andrat(&resultRat, rhsRat, m_radix, m_precision); + result = result.And(rhs, m_radix, m_precision); break; case IDC_OR: - orrat(&resultRat, rhsRat, m_radix, m_precision); + result = result.Or(rhs, m_radix, m_precision); break; case IDC_XOR: - xorrat(&resultRat, rhsRat, m_radix, m_precision); + result = result.Xor(rhs, m_radix, m_precision); break; case IDC_RSHF: { - if (m_fIntegerMode) + if (m_fIntegerMode && result.IsGreaterEq(Rational{ m_dwWordBitWidth }, m_precision)) // Lsh/Rsh >= than current word size is always 0 { - NumObjSetIntValue(&hno, m_dwWordBitWidth); - if (NumObjIsGreaterEq(resultRat, hno, m_precision)) // Lsh/Rsh >= than current word size is always 0 - { - throw CALC_E_NORESULT; - } + throw CALC_E_NORESULT; } - NumObjAssign(&hno, resultRat); - NumObjAssign(&resultRat, rhsRat); - - uint64_t w64Bits = NumObjGetUlValue(resultRat, m_radix, m_precision); + uint64_t w64Bits = rhs.ToUInt64_t(m_radix, m_precision); bool fMsb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1; - rshrat(&resultRat, hno, m_radix, m_precision); + Rational holdVal = result; + result = rhs.Rsh(holdVal, m_radix, m_precision); if (fMsb) { - intrat(&resultRat, m_radix, m_precision); - PRAT temp = m_chopNumbers[m_numwidth].ToPRAT(); - PRAT chopRat = m_chopNumbers[m_numwidth].ToPRAT(); - rshrat(&temp, hno, m_radix, m_precision); - intrat(&temp, m_radix, m_precision); - xorrat(&temp, chopRat, m_radix, m_precision); - orrat(&resultRat, temp, m_radix, m_precision); - destroyrat(temp); - destroyrat(chopRat); + result = Integer(result, m_radix, m_precision); + + auto tempRat = m_chopNumbers[m_numwidth].Rsh(holdVal, m_radix, m_precision); + tempRat = Integer(tempRat, m_radix, m_precision); + + tempRat = tempRat.Xor(m_chopNumbers[m_numwidth], m_radix, m_precision); + result = result.Or(tempRat, m_radix, m_precision); } break; } case IDC_LSHF: - if (m_fIntegerMode) + if (m_fIntegerMode && result.IsGreaterEq(Rational{ m_dwWordBitWidth }, m_precision)) // Lsh/Rsh >= than current word size is always 0 { - NumObjSetIntValue(&hno, m_dwWordBitWidth); - if (NumObjIsGreaterEq(resultRat, hno, m_precision)) - { - throw CALC_E_NORESULT; - } + throw CALC_E_NORESULT; } - NumObjAssign(&hno, resultRat); - NumObjAssign(&resultRat, rhsRat); - - lshrat(&resultRat, hno, m_radix, m_precision); + result = rhs.Lsh(result, m_radix, m_precision); break; case IDC_ADD: - addrat(&resultRat, rhsRat, m_precision); + result = result.Add(rhs, m_precision); break; case IDC_SUB: - // in order to do ( rhsRat - resultRat ) we actually do -(resultRat - rhsRat ) because it's quicker - subrat(&resultRat, rhsRat, m_precision); - NumObjNegate(&resultRat); + result = rhs.Sub(result, m_precision); break; case IDC_MUL: - mulrat(&resultRat, rhsRat, m_precision); + result = result.Mul(rhs, m_precision); break; case IDC_DIV: case IDC_MOD: + { + int iNumeratorSign = 1, iDenominatorSign = 1, iFinalSign = 1; + auto temp = result; + result = rhs; + + if (m_fIntegerMode) { - int iNumeratorSign = 1, iDenominatorSign = 1, iFinalSign = 1; - // REVIEW: These lengthly number assignments can be replaced with some quick pointer swaps. - // the swaps cannot change the value of pratX unless we also modify the code that calls - // the DoOperation function. - NumObjAssign(&hno, resultRat); - NumObjAssign(&resultRat, rhsRat); + uint64_t w64Bits = rhs.ToUInt64_t(m_radix, m_precision); + bool fMsb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1; - if(m_fIntegerMode) + if (fMsb) { - uint64_t w64Bits = NumObjGetUlValue(resultRat, m_radix, m_precision); - bool fMsb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1; + result = rhs.Not(true /* IntegerMode */, m_chopNumbers[m_numwidth], m_radix, m_precision); + result = result.Add(1, m_precision); - if (fMsb) - { - PRAT chopRat = m_chopNumbers[m_numwidth].ToPRAT(); - NumObjNot(&resultRat, true, chopRat, m_radix, m_precision); - destroyrat(chopRat); - addrat(&resultRat, rat_one, m_precision); - - iNumeratorSign = -1; - } - - w64Bits = NumObjGetUlValue(hno, m_radix, m_precision); - fMsb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1; - - if (fMsb) - { - PRAT chopRat = m_chopNumbers[m_numwidth].ToPRAT(); - NumObjNot( &hno, true, chopRat, m_radix, m_precision); - destroyrat(chopRat); - addrat( &hno, rat_one, m_precision); - - iDenominatorSign = -1; - } + iNumeratorSign = -1; } - if (operation == IDC_DIV) - { - iFinalSign = iNumeratorSign * iDenominatorSign; - divrat(&resultRat, hno, m_precision); - } - else - { - iFinalSign = iNumeratorSign; - modrat(&resultRat, hno ); - } + w64Bits = temp.ToUInt64_t(m_radix, m_precision); + fMsb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1; - if (m_fIntegerMode && iFinalSign == -1) + if (fMsb) { - intrat(&resultRat, m_radix, m_precision); - NumObjNegate(&resultRat); - } + temp = temp.Not(true /* IntegerMode */, m_chopNumbers[m_numwidth], m_radix, m_precision); + temp = temp.Add(1, m_precision); - break; + iDenominatorSign = -1; + } } - case IDC_PWR: // Calculates rhsRat to the resultRat(th) power. + if (operation == IDC_DIV) { - NumObjAssign(&hno, resultRat); - NumObjAssign(&resultRat, rhsRat); - - powrat(&resultRat, hno , m_radix, m_precision); - - break; + iFinalSign = iNumeratorSign * iDenominatorSign; + result = result.Div(temp, m_precision); } - case IDC_ROOT: // Calculates rhsRat to the resultRat(th) root. + else { - NumObjAssign(&hno, resultRat); - NumObjAssign(&resultRat, rhsRat); - - rootrat(&resultRat, hno, m_radix, m_precision); - - break; + iFinalSign = iNumeratorSign; + result = result.Mod(temp); } + + if (m_fIntegerMode && iFinalSign == -1) + { + result = Integer(result, m_radix, m_precision).Negate(); + } + + break; + } + + case IDC_PWR: // Calculates rhs to the result(th) power. + result = Pow(rhs, result, m_radix, m_precision); + break; + + case IDC_ROOT: // Calculates rhs to the result(th) root. + result = Root(rhs, result, m_radix, m_precision); + break; } } catch (DWORD dwErrCode) @@ -187,15 +141,8 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa DisplayError(dwErrCode); // On error, return the original value - destroyrat(resultRat); - resultRat = lhs.ToPRAT(); + result = lhs; } - destroyrat(hno); - destroyrat(rhsRat); - - Rational result{ resultRat }; - destroyrat(resultRat); - return result; } diff --git a/src/CalcManager/CEngine/sciset.cpp b/src/CalcManager/CEngine/sciset.cpp index e303b00..319a2a4 100644 --- a/src/CalcManager/CEngine/sciset.cpp +++ b/src/CalcManager/CEngine/sciset.cpp @@ -1,29 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -/**************************************************************************/ -/*** SCICALC Scientific Calculator for Windows 3.00.12 ***/ -/*** (c)1989 Microsoft Corporation. All Rights Reserved. ***/ -/*** ***/ -/*** sciset.c ***/ -/*** ***/ -/*** Functions contained: ***/ -/*** ***/ -/*** Functions called: ***/ -/*** none ***/ -/*** ***/ -/*** History: ***/ -/*** 12-Dec-1996 Added SetMaxIntDigits ***/ -/*** Whenever-97 Removed SetMaxIntDigits ***/ -/*** ***/ -/**************************************************************************/ #include "pch.h" #include "Header Files/CalcEngine.h" using namespace CalcEngine; +using namespace CalcEngine::RationalMath; -// -// To be called when either the radix or num width changes. You can use -1 in either of these values to mean +// To be called when either the radix or num width changes. You can use -1 in either of these values to mean // dont change that. void CCalcEngine::SetRadixTypeAndNumWidth(RADIX_TYPE radixtype, NUM_WIDTH numwidth) { @@ -34,22 +18,17 @@ void CCalcEngine::SetRadixTypeAndNumWidth(RADIX_TYPE radixtype, NUM_WIDTH numwid // back to 1111,1111,1000,0001 when in Word mode. if (m_fIntegerMode) { - PRAT curRat = m_currentVal.ToPRAT(); - ULONGLONG w64Bits = NumObjGetUlValue(curRat, m_radix, m_precision); + uint64_t w64Bits = m_currentVal.ToUInt64_t(m_radix, m_precision); bool fMsb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1; // make sure you use the old width if (fMsb) { // If high bit is set, then get the decimal number in -ve 2'scompl form. - PRAT chopRat = m_chopNumbers[m_numwidth].ToPRAT(); - NumObjNot(&curRat, true, chopRat, m_radix, m_precision); - destroyrat(chopRat); - addrat(&curRat, rat_one, m_precision); - NumObjNegate(&curRat); - m_currentVal = Rational{ curRat }; - } + auto tempResult = m_currentVal.Not(true /* IntegerMode */, m_chopNumbers[m_numwidth], m_radix, m_precision); + tempResult = tempResult.Add(1, m_precision); - destroyrat(curRat); + m_currentVal = tempResult.Negate(); + } } if (radixtype >= HEX_RADIX && radixtype <= BIN_RADIX) @@ -84,9 +63,9 @@ LONG CCalcEngine::DwWordBitWidthFromeNumWidth(NUM_WIDTH /*numwidth*/) return wmax; } -uint32_t CCalcEngine::NRadixFromRadixType( RADIX_TYPE radixtype) +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 @@ -106,25 +85,16 @@ bool CCalcEngine::TryToggleBit(CalcEngine::Rational& rat, DWORD wbitno) return false; // ignore error cant happen } - PRAT hnumPow = nullptr; - NumObjAssign(&hnumPow, rat_two); - PRAT hnum = longtorat(wbitno); - powrat(&hnumPow, hnum, m_radix, m_precision); - - PRAT resultRat = rat.ToPRAT(); - intrat(&resultRat, m_radix, m_precision); - if (NumObjIsZero(resultRat)) + Rational result = Integer(rat, m_radix, m_precision); + if (result.IsZero()) { // This is the same work around happenning in SciCalcFunctions. Ought to move to intrat function itself. - // Basic bug is there which doesn treat 0/ n as 0, or -0 as 0 etc. - NumObjAssign(&resultRat, rat_zero); + // Basic bug is there which doesn't treat 0/ n as 0, or -0 as 0 etc. + result = Rational{}; } - xorrat(&resultRat, hnumPow, m_radix, m_precision); - rat = Rational{ resultRat }; - destroyrat(resultRat); - NumObjDestroy(&hnumPow); - NumObjDestroy(&hnum); + auto pow = Pow(2, static_cast(wbitno), m_radix, m_precision); + rat = result.Xor(pow, m_radix, m_precision); return true; } diff --git a/src/CalcManager/ExpressionCommand.cpp b/src/CalcManager/ExpressionCommand.cpp index e671182..393a471 100644 --- a/src/CalcManager/ExpressionCommand.cpp +++ b/src/CalcManager/ExpressionCommand.cpp @@ -293,9 +293,7 @@ wstring COpndCommand::GetString(uint32_t radix, int32_t precision, wchar_t decim if (m_fInitialized) { - PRAT valRat = m_value.ToPRAT(); - result = NumObjToString(valRat, radix, eNUMOBJ_FMT::FMT_FLOAT, precision); - destroyrat(valRat); + result = m_value.ToString(radix, eNUMOBJ_FMT::FMT_FLOAT, precision); } return result; diff --git a/src/CalcManager/Header Files/Rational.h b/src/CalcManager/Header Files/Rational.h index b447aae..ac8bfca 100644 --- a/src/CalcManager/Header Files/Rational.h +++ b/src/CalcManager/Header Files/Rational.h @@ -12,6 +12,9 @@ namespace CalcEngine Rational() noexcept; Rational(Number const& n) noexcept; Rational(Number const& p, Number const& q) noexcept; + Rational(int32_t i); + Rational(uint32_t ui); + Rational(uint64_t ui, uint32_t radix, int32_t precision); explicit Rational(PRAT prat) noexcept; PRAT ToPRAT() const; @@ -19,7 +22,29 @@ namespace CalcEngine Number const& P() const; Number const& Q() const; + Rational Negate() const; + Rational Add(Rational const& rhs, int32_t precision) const; + Rational Sub(Rational const& rhs, int32_t precision) const; + Rational Mul(Rational const& rhs, int32_t precision) const; + Rational Div(Rational const& rhs, int32_t precision) const; + Rational Mod(Rational const& rhs) const; + + Rational Lsh(Rational const& r, uint32_t radix, int32_t precision) const; + Rational Rsh(Rational const& r, uint32_t radix, int32_t precision) const; + + Rational Not(bool isIntegerMode, Rational const& chopNum, uint32_t radix, int32_t precision) const; + Rational And(Rational const& r, uint32_t radix, int32_t precision) const; + Rational Or(Rational const& r, uint32_t radix, int32_t precision) const; + Rational Xor(Rational const& r, uint32_t radix, int32_t precision) const; + bool IsZero() const; + bool IsLess(Rational const& r, int32_t precision) const; + bool IsLessEq(Rational const& r, int32_t precision) const; + bool IsGreaterEq(Rational const& r, int32_t precision) const; + bool IsEq(Rational const& r, int32_t precision) const; + + std::wstring ToString(uint32_t radix, NUMOBJ_FMT format, int32_t precision) const; + uint64_t ToUInt64_t(uint32_t radix, int32_t precision) const; private: Number m_p; diff --git a/src/CalcManager/Header Files/scimath.h b/src/CalcManager/Header Files/scimath.h index 673b050..8f0d164 100644 --- a/src/CalcManager/Header Files/scimath.h +++ b/src/CalcManager/Header Files/scimath.h @@ -1,79 +1,35 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -/**************************************************************************\ -* * -* * -* * -* # # ##### * -* # # # # # * -* # # # # # # # * -* # ### ### # # * -* # # ### # # # ### # # ### ##### # ### ### ### * -* # ## # # # ## # # # # # # ## # # # * -* # # # # # # # # # ##### # # ##### # * -* # # # # # # # # # # # # # # ## * -* # # # # # # # # # ### # # ### ### ## * -* * -* * -* Infinte Precision Production Version * -* * -\**************************************************************************/ -// -// RETAIL version of NUMOBJ math that uses Infinite Precision -// -#include "../Ratpack/ratpak.h" +#include "Rational.h" -// -// Unary functions -// -void NumObjInvert(PRAT *phno, int32_t precision); -void NumObjNegate(PRAT *phno); -void NumObjAbs(PRAT *phno); +namespace CalcEngine::RationalMath +{ + Rational Frac(Rational const& rat, uint32_t radix, int32_t precision); + Rational Integer(Rational const& rat, uint32_t radix, int32_t precision); -void NumObjSin(PRAT *phno, ANGLE_TYPE angletype, uint32_t radix, int32_t precision); -void NumObjCos(PRAT *phno, ANGLE_TYPE angletype, uint32_t radix, int32_t precision); -void NumObjTan(PRAT *phno, ANGLE_TYPE angletype, uint32_t radix, int32_t precision); -void NumObjAntiLog10(PRAT *phno, uint32_t radix, int32_t precision); + Rational Pow(Rational const& base, Rational const& pow, uint32_t radix, int32_t precision); + Rational Root(Rational const& base, Rational const& root, uint32_t radix, int32_t precision); + Rational Fact(Rational const& rat, uint32_t radix, int32_t precision); -void NumObjNot(PRAT *phno, bool fIntegerMode, PRAT chopNum, uint32_t radix, int32_t precision); + Rational Exp(Rational const& rat, uint32_t radix, int32_t precision); + Rational Log(Rational const& rat, int32_t precision); + Rational Log10(Rational const& rat, int32_t precision); -// -// Comparison functions -// -bool NumObjIsZero(PRAT hno); -bool NumObjIsLess(PRAT hno1, PRAT hno2, int32_t precision); -bool NumObjIsLessEq(PRAT hno1, PRAT hno2, int32_t precision); -bool NumObjIsGreaterEq(PRAT hno1, PRAT hno2, int32_t precision); -bool NumObjIsEq(PRAT hno1, PRAT hno2, int32_t precision); + Rational Invert(Rational const& rat, int32_t precision); + Rational Abs(Rational const& rat); -// -// Assignment operator. ('=' in C language) -// -void NumObjAssign(PRAT *phnol, PRAT hnor); + Rational Sin(Rational const& rat, ANGLE_TYPE angletype, uint32_t radix, int32_t precision); + Rational Cos(Rational const& rat, ANGLE_TYPE angletype, uint32_t radix, int32_t precision); + Rational Tan(Rational const& rat, ANGLE_TYPE angletype, uint32_t radix, int32_t precision); + Rational ASin(Rational const& rat, ANGLE_TYPE angletype, uint32_t radix, int32_t precision); + Rational ACos(Rational const& rat, ANGLE_TYPE angletype, uint32_t radix, int32_t precision); + Rational ATan(Rational const& rat, ANGLE_TYPE angletype, uint32_t radix, int32_t precision); -// -// Data type conversion functions -// -void NumObjSetIntValue(PRAT *phnol, LONG i ); -void NumObjSetUlonglongValue(PRAT *phnol, ULONGLONG ul, uint32_t radix, int32_t precision); - -ULONGLONG NumObjGetUlValue( PRAT hnol, uint32_t radix, int32_t precision); - -// Returns a string representation of hnoNum -std::wstring NumObjToString(PRAT hnoNum, uint32_t radix, NUMOBJ_FMT fmt, int32_t precision); - -// -// NumObjGetExp -// -// returns an int that equals the exponent of the NumObj -// -int32_t NumObjGetExp(PRAT hno); - -// -// NumObjDestroy( hno ) -// -// call this when you nolonger need the NumObj. Failure to do so -// will result in memory leaks. -// -void NumObjDestroy(PRAT *phno); + Rational Sinh(Rational const& rat, uint32_t radix, int32_t precision); + Rational Cosh(Rational const& rat, uint32_t radix, int32_t precision); + Rational Tanh(Rational const& rat, uint32_t radix, int32_t precision); + Rational ASinh(Rational const& rat, uint32_t radix, int32_t precision); + Rational ACosh(Rational const& rat, uint32_t radix, int32_t precision); + Rational ATanh(Rational const& rat, int32_t precision); +} \ No newline at end of file