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.
This commit is contained in:
Josh Koon 2019-02-19 07:46:17 -08:00 committed by GitHub
parent 3e093155b1
commit 995f077127
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1191 additions and 845 deletions

View File

@ -2,6 +2,7 @@
#include "pch.h" #include "pch.h"
#include "Header Files/Rational.h" #include "Header Files/Rational.h"
#include "Header Files/scimath.h"
using namespace std; using namespace std;
@ -29,6 +30,37 @@ namespace CalcEngine
m_q{ q } m_q{ q }
{} {}
Rational::Rational(int32_t i)
{
PRAT pr = longtorat(static_cast<long>(i));
m_p = Number{ pr->pp };
m_q = Number{ pr->pq };
destroyrat(pr);
}
Rational::Rational(uint32_t ui)
{
PRAT pr = Ulongtorat(static_cast<unsigned long>(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 : Rational::Rational(PRAT prat) noexcept :
m_p{ Number{prat->pp} }, m_p{ Number{prat->pp} },
m_q{ Number{prat->pq} } m_q{ Number{prat->pq} }
@ -54,8 +86,390 @@ namespace CalcEngine
return m_q; 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 bool Rational::IsZero() const
{ {
return this->P().IsZero(); 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;
}
} }

View File

@ -1,29 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // 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 "pch.h"
#include "Header Files/CalcEngine.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"; static constexpr wstring_view DEFAULT_NUMBER_STR = L"0";
// Read strings for keys, errors, trig types, etc. // Read strings for keys, errors, trig types, etc.
// These will be copied from the resources to local memory. A larger // These will be copied from the resources to local memory.
// than needed block is allocated first and then reallocated once we
// know how much is actually used.
array<wstring, CSTRINGSENGMAX> CCalcEngine::s_engineStrings; array<wstring, CSTRINGSENGMAX> CCalcEngine::s_engineStrings;
@ -111,7 +86,7 @@ CCalcEngine::CCalcEngine(bool fPrecedence, bool fIntegerMode, CalculationManager
m_numberString(DEFAULT_NUMBER_STR), m_numberString(DEFAULT_NUMBER_STR),
m_nOp(), m_nOp(),
m_nPrecOp(), m_nPrecOp(),
m_memoryValue{make_unique<Rational>()}, m_memoryValue{ make_unique<Rational>() },
m_holdVal{}, m_holdVal{},
m_currentVal{}, m_currentVal{},
m_lastVal{} m_lastVal{}
@ -120,12 +95,7 @@ CCalcEngine::CCalcEngine(bool fPrecedence, bool fIntegerMode, CalculationManager
m_dwWordBitWidth = DwWordBitWidthFromeNumWidth(m_numwidth); m_dwWordBitWidth = DwWordBitWidthFromeNumWidth(m_numwidth);
PRAT maxTrig = longtorat(10L); m_maxTrigonometricNum = RationalMath::Pow(10, 100, m_radix, m_precision);
PRAT hundred = longtorat(100L);
powrat(&maxTrig, hundred, m_radix, m_precision);
m_maxTrigonometricNum = Rational{ maxTrig };
destroyrat(maxTrig);
destroyrat(hundred);
SetRadixTypeAndNumWidth(DEC_RADIX, m_numwidth); SetRadixTypeAndNumWidth(DEC_RADIX, m_numwidth);
SettingsChanged(); SettingsChanged();
@ -147,14 +117,10 @@ void CCalcEngine::InitChopNumbers()
assert(m_chopNumbers.size() == m_maxDecimalValueStrings.size()); assert(m_chopNumbers.size() == m_maxDecimalValueStrings.size());
for (size_t i = 0; i < m_chopNumbers.size(); i++) 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); m_maxDecimalValueStrings[i] = maxVal.ToString(10, FMT_FLOAT, m_precision);
intrat(&hno, m_radix, m_precision);
m_maxDecimalValueStrings[i] = NumObjToString(hno, 10, FMT_FLOAT, m_precision);
NumObjDestroy(&hno);
} }
} }

View File

@ -32,21 +32,21 @@ using namespace CalcEngine;
// 0 is returned. Higher the number, higher the precendence of the operator. // 0 is returned. Higher the number, higher the precendence of the operator.
INT NPrecedenceOfOp(int nopCode) 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_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; int iPrec;
iPrec = 0; iPrec = 0;
while ((iPrec < ARRAYSIZE(rgbPrec)) && (nopCode != rgbPrec[iPrec])) while ((iPrec < ARRAYSIZE(rgbPrec)) && (nopCode != rgbPrec[iPrec]))
{ {
iPrec += 2; iPrec += 2;
} }
if (iPrec >= ARRAYSIZE(rgbPrec)) if (iPrec >= ARRAYSIZE(rgbPrec))
{ {
iPrec = 0; iPrec = 0;
} }
return rgbPrec[iPrec+1]; return rgbPrec[iPrec + 1];
} }
@ -77,13 +77,13 @@ void CCalcEngine::ClearTemporaryValues()
m_input.Clear(); m_input.Clear();
m_bRecord = true; m_bRecord = true;
CheckAndAddLastBinOpToHistory(); CheckAndAddLastBinOpToHistory();
DisplayNum (); DisplayNum();
m_bError=false; m_bError = false;
} }
void CCalcEngine::ProcessCommand(WPARAM wParam) void CCalcEngine::ProcessCommand(WPARAM wParam)
{ {
if(wParam == IDC_SET_RESULT) if (wParam == IDC_SET_RESULT)
{ {
wParam = IDC_RECALL; wParam = IDC_RECALL;
m_bSetCalcState = true; m_bSetCalcState = true;
@ -104,13 +104,13 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
if (!IsGuiSettingOpCode(wParam)) if (!IsGuiSettingOpCode(wParam))
{ {
m_nLastCom=m_nTempCom; m_nLastCom = m_nTempCom;
m_nTempCom=(INT)wParam; m_nTempCom = (INT)wParam;
} }
if (m_bError) if (m_bError)
{ {
if(wParam == IDC_CLEAR) if (wParam == IDC_CLEAR)
{ {
// handle "C" normally // handle "C" normally
} }
@ -129,23 +129,23 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
// Toggle Record/Display mode if appropriate. // Toggle Record/Display mode if appropriate.
if (m_bRecord) if (m_bRecord)
{ {
if (IsOpInRange(wParam, IDC_AND, IDC_MMINUS) || if (IsOpInRange(wParam, IDC_AND, IDC_MMINUS) ||
IsOpInRange(wParam, IDC_OPENP, IDC_CLOSEP) || IsOpInRange(wParam, IDC_OPENP, IDC_CLOSEP) ||
IsOpInRange(wParam, IDM_HEX, IDM_BIN) || IsOpInRange(wParam, IDM_HEX, IDM_BIN) ||
IsOpInRange(wParam, IDM_QWORD, IDM_BYTE) || IsOpInRange(wParam, IDM_QWORD, IDM_BYTE) ||
IsOpInRange(wParam, IDM_DEG, IDM_GRAD) || IsOpInRange(wParam, IDM_DEG, IDM_GRAD) ||
IsOpInRange(wParam, IDC_BINEDITSTART, IDC_BINEDITSTART+63) || IsOpInRange(wParam, IDC_BINEDITSTART, IDC_BINEDITSTART + 63) ||
(IDC_INV == wParam) || (IDC_INV == wParam) ||
(IDC_SIGN == wParam && 10 != m_radix)) (IDC_SIGN == wParam && 10 != m_radix))
{ {
m_bRecord = false; m_bRecord = false;
m_currentVal = m_input.ToRational(m_radix, m_precision); 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 else
{ {
if ( IsDigitOpCode(wParam)|| wParam == IDC_PNT) if (IsDigitOpCode(wParam) || wParam == IDC_PNT)
{ {
m_bRecord = true; m_bRecord = true;
m_input.Clear(); m_input.Clear();
@ -156,7 +156,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
// Interpret digit keys. // Interpret digit keys.
if (IsDigitOpCode(wParam)) if (IsDigitOpCode(wParam))
{ {
unsigned int iValue = static_cast<unsigned int>(wParam-IDC_0); unsigned int iValue = static_cast<unsigned int>(wParam - IDC_0);
// this is redundant, illegal keys are disabled // this is redundant, illegal keys are disabled
if (iValue >= static_cast<unsigned int>(m_radix)) if (iValue >= static_cast<unsigned int>(m_radix))
@ -179,14 +179,14 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
// BINARY OPERATORS: // BINARY OPERATORS:
if (IsBinOpCode(wParam)) if (IsBinOpCode(wParam))
{ {
/* Change the operation if last input was operation. */ /* Change the operation if last input was operation. */
if (IsBinOpCode(m_nLastCom)) if (IsBinOpCode(m_nLastCom))
{ {
INT nPrev; INT nPrev;
bool fPrecInvToHigher = false; // Is Precedence Invertion from lower to higher precedence happenning ?? 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. // 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 // 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. */ /* Scientific mode. */
if (m_bChangeOp) if (m_bChangeOp)
{ {
DoPrecedenceCheckAgain: DoPrecedenceCheckAgain:
nx = NPrecedenceOfOp((int) wParam); nx = NPrecedenceOfOp((int)wParam);
ni = NPrecedenceOfOp(m_nOpCode); ni = NPrecedenceOfOp(m_nOpCode);
if ((nx > ni) && m_fPrecedence) if ((nx > ni) && m_fPrecedence)
@ -237,7 +237,7 @@ DoPrecedenceCheckAgain:
} }
else else
{ {
m_nPrecNum = MAXPRECDEPTH-1; m_nPrecNum = MAXPRECDEPTH - 1;
HandleErrorCommand(wParam); HandleErrorCommand(wParam);
} }
m_nPrecNum++; m_nPrecNum++;
@ -253,13 +253,13 @@ DoPrecedenceCheckAgain:
if (!m_bError) 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_nPrecNum--;
m_nOpCode=m_nPrecOp[m_nPrecNum] ; m_nOpCode = m_nPrecOp[m_nPrecNum];
m_lastVal = m_precedenceVals[m_nPrecNum]; m_lastVal = m_precedenceVals[m_nPrecNum];
@ -274,7 +274,7 @@ DoPrecedenceCheckAgain:
m_HistoryCollector.EnclosePrecInvertionBrackets(); m_HistoryCollector.EnclosePrecInvertionBrackets();
} }
m_HistoryCollector.PopLastOpndStart(); m_HistoryCollector.PopLastOpndStart();
goto DoPrecedenceCheckAgain ; goto DoPrecedenceCheckAgain;
} }
} }
@ -283,7 +283,7 @@ DoPrecedenceCheckAgain:
DisplayAnnounceBinaryOperator(); DisplayAnnounceBinaryOperator();
m_lastVal = m_currentVal; m_lastVal = m_currentVal;
m_nOpCode=(INT)wParam; m_nOpCode = (INT)wParam;
m_HistoryCollector.AddBinOpToHistory(m_nOpCode); m_HistoryCollector.AddBinOpToHistory(m_nOpCode);
m_bNoPrevEqu = m_bChangeOp = true; m_bNoPrevEqu = m_bChangeOp = true;
return; return;
@ -292,7 +292,7 @@ DoPrecedenceCheckAgain:
// UNARY OPERATORS: // UNARY OPERATORS:
if (IsUnaryOpCode(wParam) || (wParam == IDC_DEGREES)) 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. */ /* If the last thing done was an operator, m_currentVal was cleared. */
/* In that case we better use the number before the operator */ /* In that case we better use the number before the operator */
/* was entered, otherwise, things like 5+ 1/x give Divide By */ /* 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. // we do not add percent sign to history or to two line display.
// instead, we add the result of applying %. // instead, we add the result of applying %.
if(wParam != IDC_PERCENT) if (wParam != IDC_PERCENT)
{ {
if (!m_HistoryCollector.FOpndAddedToHistory()) if (!m_HistoryCollector.FOpndAddedToHistory())
{ {
@ -329,9 +329,9 @@ DoPrecedenceCheckAgain:
return; return;
/* Display the result, reset flags, and reset indicators. */ /* Display the result, reset flags, and reset indicators. */
DisplayNum (); DisplayNum();
if(wParam == IDC_PERCENT) if (wParam == IDC_PERCENT)
{ {
CheckAndAddLastBinOpToHistory(); CheckAndAddLastBinOpToHistory();
m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal, true /* Add to primary and secondary display */); m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal, true /* Add to primary and secondary display */);
@ -343,8 +343,8 @@ DoPrecedenceCheckAgain:
if (m_bInv && if (m_bInv &&
((wParam == IDC_CHOP) || ((wParam == IDC_CHOP) ||
(wParam == IDC_SIN) || (wParam == IDC_COS) || (wParam == IDC_TAN) || (wParam == IDC_SIN) || (wParam == IDC_COS) || (wParam == IDC_TAN) ||
(wParam == IDC_LN) || (wParam == IDC_DMS) || (wParam == IDC_DEGREES) || (wParam == IDC_LN) || (wParam == IDC_DMS) || (wParam == IDC_DEGREES) ||
(wParam == IDC_SINH) || (wParam == IDC_COSH) || (wParam == IDC_TANH))) (wParam == IDC_SINH) || (wParam == IDC_COSH) || (wParam == IDC_TANH)))
{ {
m_bInv = false; m_bInv = false;
} }
@ -353,7 +353,7 @@ DoPrecedenceCheckAgain:
} }
// Tiny binary edit windows clicked. Toggle that bit and update display // 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 // Same reasoning as for unary operators. We need to seed it previous number
if (m_nLastCom >= IDC_AND && m_nLastCom <= IDC_PWR) if (m_nLastCom >= IDC_AND && m_nLastCom <= IDC_PWR)
@ -372,46 +372,46 @@ DoPrecedenceCheckAgain:
} }
/* Now branch off to do other commands and functions. */ /* Now branch off to do other commands and functions. */
switch(wParam) switch (wParam)
{ {
case IDC_CLEAR: /* Total clear. */ case IDC_CLEAR: /* Total clear. */
{ {
if (!m_bChangeOp) 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<CalculatorVector<pair<wstring, int>>>(), make_shared<CalculatorVector<shared_ptr<IExpressionCommand>>>());
}
m_HistoryCollector.ClearHistoryLine(wstring());
ClearTemporaryValues();
}
break;
case IDC_CENTR: /* Clear only temporary values. */
{ {
// Clear the INV & leave (=xx indicator active // A special goody we are doing to preserve the history, if all was done was serious of unary operations last
ClearTemporaryValues(); 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<CalculatorVector<pair<wstring, int>>>(), make_shared<CalculatorVector<shared_ptr<IExpressionCommand>>>());
}
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. // Divide number by the current radix and truncate.
// Only allow backspace if we're recording. // Only allow backspace if we're recording.
if (m_bRecord) if (m_bRecord)
@ -427,7 +427,7 @@ DoPrecedenceCheckAgain:
/* EQU enables the user to press it multiple times after and */ /* EQU enables the user to press it multiple times after and */
/* operation to enable repeats of the last operation. */ /* operation to enable repeats of the last operation. */
case IDC_EQU: case IDC_EQU:
while (m_openParenCount > 0) while (m_openParenCount > 0)
{ {
// when m_bError is set and m_ParNum is non-zero it goes into infinite loop // 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 */ /* Check for errors. If this wasn't done, DisplayNum */
/* would immediately overwrite any error message. */ /* would immediately overwrite any error message. */
if (!m_bError) if (!m_bError)
DisplayNum (); DisplayNum();
/* No longer the first EQU. */ /* No longer the first EQU. */
m_bNoPrevEqu= false; m_bNoPrevEqu = false;
} }
else if (!m_bError) else if (!m_bError)
DisplayNum(); DisplayNum();
if (m_nPrecNum==0 || !m_fPrecedence) if (m_nPrecNum == 0 || !m_fPrecedence)
break; break;
m_nOpCode = m_nPrecOp[--m_nPrecNum]; m_nOpCode = m_nPrecOp[--m_nPrecNum];
@ -510,7 +510,7 @@ DoPrecedenceCheckAgain:
} }
m_HistoryCollector.PopLastOpndStart(); m_HistoryCollector.PopLastOpndStart();
m_bNoPrevEqu= true; m_bNoPrevEqu = true;
} while (m_nPrecNum >= 0); } while (m_nPrecNum >= 0);
if (!m_bError) if (!m_bError)
@ -523,17 +523,17 @@ DoPrecedenceCheckAgain:
} }
} }
m_bChangeOp=false; m_bChangeOp = false;
m_nPrevOpCode = 0; m_nPrevOpCode = 0;
break; break;
case IDC_OPENP: case IDC_OPENP:
case IDC_CLOSEP: case IDC_CLOSEP:
nx=0; nx = 0;
if (wParam==IDC_OPENP) if (wParam == IDC_OPENP)
{ {
nx=1; nx = 1;
} }
// -IF- the Paren holding array is full and we try to add a paren // -IF- the Paren holding array is full and we try to add a paren
@ -541,7 +541,7 @@ DoPrecedenceCheckAgain:
// paren // paren
// -OR- the the precidence holding array is full // -OR- the the precidence holding array is full
if ((m_openParenCount >= MAXPRECDEPTH && nx) || (!m_openParenCount && !nx) 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); HandleErrorCommand(wParam);
break; break;
@ -570,9 +570,9 @@ DoPrecedenceCheckAgain:
// treated as 1 + (3 // treated as 1 + (3
m_currentVal = Rational{}; m_currentVal = Rational{};
} }
m_nTempCom=0; m_nTempCom = 0;
m_nOpCode=0; m_nOpCode = 0;
m_bChangeOp= false; // a ( is like starting a fresh sub equation m_bChangeOp = false; // a ( is like starting a fresh sub equation
} }
else else
{ {
@ -649,7 +649,7 @@ DoPrecedenceCheckAgain:
case IDM_DWORD: case IDM_DWORD:
case IDM_WORD: case IDM_WORD:
case IDM_BYTE: case IDM_BYTE:
if ( m_bRecord ) if (m_bRecord)
{ {
m_currentVal = m_input.ToRational(m_radix, m_precision); m_currentVal = m_input.ToRational(m_radix, m_precision);
m_bRecord = false; m_bRecord = false;
@ -666,44 +666,41 @@ DoPrecedenceCheckAgain:
break; break;
case IDC_SIGN: 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();
{
DisplayNum();
}
else
{
HandleErrorCommand(wParam);
}
break;
} }
else
// Doing +/- while in Record mode is not a unary operation
if (IsBinOpCode(m_nLastCom))
{ {
m_currentVal = m_lastVal; HandleErrorCommand(wParam);
} }
break;
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;
// 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: case IDC_RECALL:
if(m_bSetCalcState) if (m_bSetCalcState)
{ {
// Not a Memory recall. set the result // Not a Memory recall. set the result
m_bSetCalcState = false; m_bSetCalcState = false;
@ -714,31 +711,25 @@ DoPrecedenceCheckAgain:
m_currentVal = Rational{ *m_memoryValue }; m_currentVal = Rational{ *m_memoryValue };
} }
CheckAndAddLastBinOpToHistory(); CheckAndAddLastBinOpToHistory();
DisplayNum (); DisplayNum();
break; break;
case IDC_MPLUS: case IDC_MPLUS:
{ {
/* MPLUS adds m_currentVal to immediate memory and kills the "mem" */ /* MPLUS adds m_currentVal to immediate memory and kills the "mem" */
/* indicator if the result is zero. */ /* indicator if the result is zero. */
PRAT memRat = m_memoryValue->ToPRAT(); Rational result = m_memoryValue->Add(m_currentVal, m_precision);
PRAT curRat = m_currentVal.ToPRAT(); m_memoryValue = make_unique<Rational>(TruncateNumForIntMath(result)); // Memory should follow the current int mode
addrat(&memRat, curRat, m_precision);
m_memoryValue = make_unique<Rational>(TruncateNumForIntMath(Rational{ memRat })); // Memory should follow the current int mode
destroyrat(curRat);
destroyrat(memRat);
break; break;
} }
case IDC_MMINUS: case IDC_MMINUS:
{ {
/* MMINUS subtracts m_currentVal to immediate memory and kills the "mem" */ /* MMINUS subtracts m_currentVal to immediate memory and kills the "mem" */
/* indicator if the result is zero. */ /* indicator if the result is zero. */
PRAT memRat = m_memoryValue->ToPRAT(); Rational result = m_memoryValue->Sub(m_currentVal, m_precision);
PRAT curRat = m_currentVal.ToPRAT(); m_memoryValue = make_unique<Rational>(TruncateNumForIntMath(result));
subrat(&memRat, curRat, m_precision);
m_memoryValue = make_unique<Rational>(TruncateNumForIntMath(Rational{ memRat }));
destroyrat(curRat);
destroyrat(memRat);
break; break;
} }
case IDC_STORE: case IDC_STORE:
@ -784,7 +775,7 @@ DoPrecedenceCheckAgain:
break; break;
case IDC_INV: case IDC_INV:
m_bInv=!m_bInv; m_bInv = !m_bInv;
break; break;
} }
@ -1011,18 +1002,13 @@ int CCalcEngine::IdcSetAngleTypeDecMode(int idc)
bool CCalcEngine::IsCurrentTooBigForTrig() bool CCalcEngine::IsCurrentTooBigForTrig()
{ {
bool result = false; if (m_currentVal.IsGreaterEq(m_maxTrigonometricNum, m_precision))
PRAT maxTrigRat = m_maxTrigonometricNum.ToPRAT();
PRAT curRat = m_currentVal.ToPRAT();
if (NumObjIsGreaterEq(curRat, maxTrigRat, m_precision))
{ {
m_currentVal = Rational{}; m_currentVal = Rational{};
result = true; return true;
} }
destroyrat(curRat);
destroyrat(maxTrigRat);
return result; return false;
} }
int CCalcEngine::GetCurrentRadix() int CCalcEngine::GetCurrentRadix()
@ -1052,39 +1038,30 @@ wstring CCalcEngine::GetStringForDisplay(Rational const& rat, uint32_t radix)
// Check for standard\scientific mode // Check for standard\scientific mode
if (!m_fIntegerMode) if (!m_fIntegerMode)
{ {
PRAT prat = rat.ToPRAT(); result = rat.ToString(radix, m_nFE, m_precision);
result = NumObjToString(prat, radix, m_nFE, m_precision);
destroyrat(prat);
} }
else else
{ {
// Programmer mode // Programmer mode
// Find most significant bit to determine if number is negative // Find most significant bit to determine if number is negative
PRAT hnoNumCopy = TruncateNumForIntMath(rat).ToPRAT(); auto tempRat = TruncateNumForIntMath(rat);
try 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); bool fMsb = ((w64Bits >> (m_dwWordBitWidth - 1)) & 1);
if ((radix == 10) && fMsb) if ((radix == 10) && fMsb)
{ {
// If high bit is set, then get the decimal number in -ve 2'scompl form. // If high bit is set, then get the decimal number in negative 2's compl form.
PRAT chopRat = m_chopNumbers[m_numwidth].ToPRAT(); tempRat = tempRat.Not(true, m_chopNumbers[m_numwidth], m_radix, m_precision);
NumObjNot(&hnoNumCopy, true, chopRat, m_radix, m_precision); tempRat = tempRat.Add(1, m_precision);
destroyrat(chopRat); tempRat = tempRat.Negate();
addrat(&hnoNumCopy, rat_one, m_precision);
NumObjNegate(&hnoNumCopy);
} }
result = NumObjToString(hnoNumCopy, radix, m_nFE, m_precision); result = tempRat.ToString(radix, m_nFE, m_precision);
NumObjDestroy(&hnoNumCopy);
} }
catch (DWORD) catch (DWORD)
{ {
if (hnoNumCopy != nullptr)
{
NumObjDestroy(&hnoNumCopy);
}
} }
} }

View File

@ -36,7 +36,7 @@ constexpr wstring_view c_decPostSepStr = L"]?(\\d*)(?:e[+-]?(\\d*))?$";
// State of calc last time DisplayNum was called // State of calc last time DisplayNum was called
// //
typedef struct { typedef struct {
PRAT hnoNum; Rational value;
int32_t precision; int32_t precision;
uint32_t radix; uint32_t radix;
INT nFE; INT nFE;
@ -46,7 +46,7 @@ typedef struct {
bool bUseSep; bool bUseSep;
} LASTDISP; } 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 // 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) CalcEngine::Rational CCalcEngine::TruncateNumForIntMath(CalcEngine::Rational const& rat)
@ -56,27 +56,20 @@ CalcEngine::Rational CCalcEngine::TruncateNumForIntMath(CalcEngine::Rational con
return rat; return rat;
} }
PRAT tempRat = rat.ToPRAT();
// Truncate to an integer. Do not round here. // 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 negative number to Hex/Oct/Bin rep. Use 2's complement form
// Can be converting a dec -ve number to Hex/Oct/Bin rep. Use 2's completement form
// Check the range. // 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 // if negative make positive by doing a twos complement
NumObjNegate(&tempRat); result = result.Negate();
subrat(&tempRat, rat_one, m_precision); result = result.Sub(1, m_precision);
NumObjNot(&tempRat, true, chopRat, m_radix, m_precision); result = result.Not(true /* IntegerMode */, m_chopNumbers[m_numwidth], m_radix, m_precision);
} }
andrat(&tempRat, chopRat, m_radix, m_precision); result = result.And(m_chopNumbers[m_numwidth], m_radix, m_precision);
destroyrat(chopRat);
Rational result{ tempRat };
destroyrat(tempRat);
return result; return result;
} }
@ -90,27 +83,24 @@ void CCalcEngine::DisplayNum(void)
// something important has changed since the last time DisplayNum was // something important has changed since the last time DisplayNum was
// called. // called.
// //
PRAT curRat = m_currentVal.ToPRAT(); if (m_bRecord ||
bool hasValChanged = !gldPrevious.hnoNum || !NumObjIsEq(gldPrevious.hnoNum, curRat, m_precision); !gldPrevious.value.IsEq(m_currentVal, m_precision) ||
destroyrat(curRat); gldPrevious.precision != m_precision ||
if ( m_bRecord || gldPrevious.hnoNum == nullptr || gldPrevious.radix != m_radix ||
hasValChanged || gldPrevious.nFE != (int)m_nFE ||
gldPrevious.precision != m_precision || gldPrevious.bUseSep != true ||
gldPrevious.radix != m_radix || gldPrevious.numwidth != m_numwidth ||
gldPrevious.nFE != (int)m_nFE || gldPrevious.fIntMath != m_fIntegerMode ||
gldPrevious.bUseSep != true || gldPrevious.bRecord != m_bRecord)
gldPrevious.numwidth != m_numwidth ||
gldPrevious.fIntMath != m_fIntegerMode ||
gldPrevious.bRecord != m_bRecord )
{ {
gldPrevious.precision = m_precision; gldPrevious.precision = m_precision;
gldPrevious.radix = m_radix; gldPrevious.radix = m_radix;
gldPrevious.nFE = (int)m_nFE; gldPrevious.nFE = (int)m_nFE;
gldPrevious.numwidth = m_numwidth; gldPrevious.numwidth = m_numwidth;
gldPrevious.fIntMath = m_fIntegerMode; gldPrevious.fIntMath = m_fIntegerMode;
gldPrevious.bRecord = m_bRecord; gldPrevious.bRecord = m_bRecord;
gldPrevious.bUseSep = true; gldPrevious.bUseSep = true;
if (m_bRecord) if (m_bRecord)
{ {
@ -128,10 +118,9 @@ void CCalcEngine::DisplayNum(void)
} }
// Displayed number can go thru transformation. So copy it after transformation // Displayed number can go thru transformation. So copy it after transformation
destroyrat(gldPrevious.hnoNum); gldPrevious.value = m_currentVal;
gldPrevious.hnoNum = m_currentVal.ToPRAT();
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); DisplayError(CALC_E_OVERFLOW);
} }
@ -268,7 +257,7 @@ wstring CCalcEngine::GroupDigitsPerRadix(wstring_view numberString, uint32_t rad
switch (radix) switch (radix)
{ {
case 10: 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: case 8:
return GroupDigits(L" ", { 3, 0 }, numberString); return GroupDigits(L" ", { 3, 0 }, numberString);
case 2: case 2:

View File

@ -21,273 +21,193 @@
using namespace std; using namespace std;
using namespace CalcEngine; using namespace CalcEngine;
using namespace CalcEngine::RationalMath;
/* Routines for more complex mathematical functions/error checking. */ /* Routines for more complex mathematical functions/error checking. */
CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& rat, DWORD op) CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& rat, DWORD op)
{ {
PRAT tempRat = rat.ToPRAT(); Rational result{};
try try
{ {
switch (op) switch (op)
{ {
case IDC_CHOP: case IDC_CHOP:
m_bInv ? fracrat(&tempRat , m_radix, m_precision) : intrat(&tempRat, m_radix, m_precision); result = m_bInv ? Frac(rat, m_radix, m_precision) : Integer(rat, m_radix, m_precision);
break; break;
/* Return complement. */ /* Return complement. */
case IDC_COM: case IDC_COM:
{ result = rat.Not(m_fIntegerMode, m_chopNumbers[m_numwidth], m_radix, m_precision);
PRAT chopRat = m_chopNumbers[m_numwidth].ToPRAT(); break;
NumObjNot(&tempRat, m_fIntegerMode, chopRat, m_radix, m_precision);
destroyrat(chopRat);
break;
}
// Rotate Left with hi bit wrapped over to lo bit // Rotate Left with hi bit wrapped over to lo bit
case IDC_ROL: case IDC_ROL:
if (m_fIntegerMode) if (m_fIntegerMode)
{ {
intrat(&tempRat, m_radix, m_precision); result = Integer(rat, m_radix, m_precision);
PRAT curRat = m_currentVal.ToPRAT(); uint64_t w64Bits = result.ToUInt64_t(m_radix, m_precision);
ULONGLONG w64Bits = NumObjGetUlValue(curRat, m_radix, m_precision); uint64_t msb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1;
ULONGLONG 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 result = Rational{ w64Bits, m_radix, m_precision };
w64Bits |= msb; // Set the prev Msb as the current Lsb }
NumObjSetUlonglongValue(&curRat, w64Bits, m_radix, m_precision); break;
m_currentVal = Rational{ curRat };
destroyrat(curRat);
}
break;
// Rotate right with lo bit wrapped over to hi bit // Rotate right with lo bit wrapped over to hi bit
case IDC_ROR: case IDC_ROR:
if (m_fIntegerMode) 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:
{ {
PRAT hno = nullptr; result = Integer(rat, m_radix, m_precision);
PRAT hno100 = nullptr;
try uint64_t w64Bits = result.ToUInt64_t(m_radix, m_precision);
{ uint64_t lsb = ((w64Bits & 0x01) == 1) ? 1 : 0;
// If the operator is multiply/divide, we evaluate this as "X [op] (Y%)" w64Bits >>= 1; //RShift by 1
// Otherwise, we evaluate it as "X [op] (X * Y%)" w64Bits |= (lsb << (m_dwWordBitWidth - 1));
if (m_nOpCode == IDC_MUL || m_nOpCode == IDC_DIV)
{
NumObjSetIntValue(&hno100, 100);
divrat(&tempRat, hno100, m_precision); result = Rational{ w64Bits, m_radix, 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;
} }
break;
case IDC_SIN: /* Sine; normal and arc */ case IDC_PERCENT:
if (!m_fIntegerMode) {
{ // If the operator is multiply/divide, we evaluate this as "X [op] (Y%)"
m_bInv ? asinanglerat(&tempRat, m_angletype, m_radix, m_precision) : NumObjSin(&tempRat, m_angletype, m_radix, m_precision); // Otherwise, we evaluate it as "X [op] (X * Y%)"
} if (m_nOpCode == IDC_MUL || m_nOpCode == IDC_DIV)
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. */
{ {
PRAT hno = nullptr; result = rat.Div(100, m_precision);
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;
} }
else
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:
{ {
if (!m_fIntegerMode) result = m_lastVal.Div(100, m_precision);
{ result = rat.Mul(result, m_precision);
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;
} }
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 ) } // end switch( op )
Rational result{ tempRat };
destroyrat(tempRat);
return result;
} }
catch(DWORD nErrCode) catch (DWORD nErrCode)
{ {
DisplayError(nErrCode); DisplayError(nErrCode);
destroyrat(tempRat); result = rat;
return rat;
} }
return result;
} }
/* Routine to display error messages and set m_bError flag. Errors are */ /* Routine to display error messages and set m_bError flag. Errors are */

View File

@ -3,204 +3,388 @@
#include "pch.h" #include "pch.h"
#include "Header Files/CalcEngine.h" #include "Header Files/CalcEngine.h"
#include "Ratpack/ratpak.h"
using namespace std; using namespace std;
using namespace CalcEngine;
/**************************************************************************\ Rational RationalMath::Frac(Rational const& rat, uint32_t radix, int32_t precision)
* *
* *
* *
* # # ##### *
* # # # # # *
* # # # # # # # *
* # ### ### # # *
* # # ### # # # ### # # ### ##### # ### ### ### *
* # ## # # # ## # # # # # # ## # # # *
* # # # # # # # # # ##### # # ##### # *
* # # # # # # # # # # # # # # ## *
* # # # # # # # # # ### # # ### ### ## *
* *
* *
* 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)
{ {
PRAT hno = nullptr; PRAT prat = rat.ToPRAT();
try
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)
{ {
intrat( phno, radix, precision); fracrat(&prat, radix, precision);
addrat( phno, rat_one, precision);
NumObjNegate( phno );
} }
else catch (DWORD error)
{ {
destroyrat(prat);
xorrat( phno, chopNum, radix, precision); 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);
} }
/******************************************************************\ Rational RationalMath::Fact(Rational const& rat, uint32_t radix, int32_t precision)
*
* Number format conversion routines
*
* History:
* 06-Dec-1996 wrote them
\******************************************************************/
void NumObjSetIntValue(PRAT *phnol, LONG i )
{ {
PRAT pr = nullptr; PRAT prat = rat.ToPRAT();
pr = longtorat( i ); try
NumObjAssign( phnol, pr ); {
destroyrat(pr); 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 ); try
NumObjAssign( phnol, pr ); {
destroyrat(pr); exprat(&prat, radix, precision);
}
catch (DWORD error)
{
destroyrat(prat);
throw(error);
}
Rational result{ prat };
destroyrat(prat);
return result;
} }
// A Set with 64 bit number Rational RationalMath::Log(Rational const& rat, int32_t precision)
void NumObjSetUlonglongValue(PRAT *phnol, ULONGLONG ul, uint32_t radix, int32_t precision)
{ {
ULONG hi, lo; PRAT prat = rat.ToPRAT();
PRAT hno = nullptr;
hi = HIDWORD(ul); try
lo = LODWORD(ul); {
NumObjSetIUlongValue(phnol, hi); lograt(&prat, precision);
NumObjSetIntValue(&hno, 32); }
lshrat(phnol, hno, radix, precision); catch (DWORD error)
NumObjSetIUlongValue(&hno, lo); {
orrat(phnol, hno, radix, precision); destroyrat(prat);
NumObjDestroy(&hno); 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;
} }

View File

@ -5,181 +5,135 @@
#include "Header Files/CalcEngine.h" #include "Header Files/CalcEngine.h"
using namespace CalcEngine; using namespace CalcEngine;
using namespace CalcEngine::RationalMath;
// Routines to perform standard operations &|^~<<>>+-/*% and pwr. // Routines to perform standard operations &|^~<<>>+-/*% and pwr.
CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rational const& lhs, CalcEngine::Rational const& rhs) 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. // Remove any variance in how 0 could be represented in rat e.g. -0, 0/n, etc.
PRAT resultRat = nullptr; auto result = (!lhs.IsZero() ? lhs : Rational{});
if (lhs.IsZero())
{
NumObjAssign(&resultRat, rat_zero);
}
else
{
resultRat = lhs.ToPRAT();
}
try try
{ {
switch (operation) switch (operation)
{ {
case IDC_AND: case IDC_AND:
andrat(&resultRat, rhsRat, m_radix, m_precision); result = result.And(rhs, m_radix, m_precision);
break; break;
case IDC_OR: case IDC_OR:
orrat(&resultRat, rhsRat, m_radix, m_precision); result = result.Or(rhs, m_radix, m_precision);
break; break;
case IDC_XOR: case IDC_XOR:
xorrat(&resultRat, rhsRat, m_radix, m_precision); result = result.Xor(rhs, m_radix, m_precision);
break; break;
case IDC_RSHF: 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); throw CALC_E_NORESULT;
if (NumObjIsGreaterEq(resultRat, hno, m_precision)) // Lsh/Rsh >= than current word size is always 0
{
throw CALC_E_NORESULT;
}
} }
NumObjAssign(&hno, resultRat); uint64_t w64Bits = rhs.ToUInt64_t(m_radix, m_precision);
NumObjAssign(&resultRat, rhsRat);
uint64_t w64Bits = NumObjGetUlValue(resultRat, m_radix, m_precision);
bool fMsb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1; 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) if (fMsb)
{ {
intrat(&resultRat, m_radix, m_precision); result = Integer(result, m_radix, m_precision);
PRAT temp = m_chopNumbers[m_numwidth].ToPRAT();
PRAT chopRat = m_chopNumbers[m_numwidth].ToPRAT(); auto tempRat = m_chopNumbers[m_numwidth].Rsh(holdVal, m_radix, m_precision);
rshrat(&temp, hno, m_radix, m_precision); tempRat = Integer(tempRat, m_radix, m_precision);
intrat(&temp, m_radix, m_precision);
xorrat(&temp, chopRat, m_radix, m_precision); tempRat = tempRat.Xor(m_chopNumbers[m_numwidth], m_radix, m_precision);
orrat(&resultRat, temp, m_radix, m_precision); result = result.Or(tempRat, m_radix, m_precision);
destroyrat(temp);
destroyrat(chopRat);
} }
break; break;
} }
case IDC_LSHF: 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); throw CALC_E_NORESULT;
if (NumObjIsGreaterEq(resultRat, hno, m_precision))
{
throw CALC_E_NORESULT;
}
} }
NumObjAssign(&hno, resultRat); result = rhs.Lsh(result, m_radix, m_precision);
NumObjAssign(&resultRat, rhsRat);
lshrat(&resultRat, hno, m_radix, m_precision);
break; break;
case IDC_ADD: case IDC_ADD:
addrat(&resultRat, rhsRat, m_precision); result = result.Add(rhs, m_precision);
break; break;
case IDC_SUB: case IDC_SUB:
// in order to do ( rhsRat - resultRat ) we actually do -(resultRat - rhsRat ) because it's quicker result = rhs.Sub(result, m_precision);
subrat(&resultRat, rhsRat, m_precision);
NumObjNegate(&resultRat);
break; break;
case IDC_MUL: case IDC_MUL:
mulrat(&resultRat, rhsRat, m_precision); result = result.Mul(rhs, m_precision);
break; break;
case IDC_DIV: case IDC_DIV:
case IDC_MOD: 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; uint64_t w64Bits = rhs.ToUInt64_t(m_radix, m_precision);
// REVIEW: These lengthly number assignments can be replaced with some quick pointer swaps. bool fMsb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1;
// 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);
if(m_fIntegerMode) if (fMsb)
{ {
uint64_t w64Bits = NumObjGetUlValue(resultRat, m_radix, m_precision); result = rhs.Not(true /* IntegerMode */, m_chopNumbers[m_numwidth], m_radix, m_precision);
bool fMsb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1; result = result.Add(1, m_precision);
if (fMsb) iNumeratorSign = -1;
{
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;
}
} }
if (operation == IDC_DIV) w64Bits = temp.ToUInt64_t(m_radix, m_precision);
{ fMsb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1;
iFinalSign = iNumeratorSign * iDenominatorSign;
divrat(&resultRat, hno, m_precision);
}
else
{
iFinalSign = iNumeratorSign;
modrat(&resultRat, hno );
}
if (m_fIntegerMode && iFinalSign == -1) if (fMsb)
{ {
intrat(&resultRat, m_radix, m_precision); temp = temp.Not(true /* IntegerMode */, m_chopNumbers[m_numwidth], m_radix, m_precision);
NumObjNegate(&resultRat); 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); iFinalSign = iNumeratorSign * iDenominatorSign;
NumObjAssign(&resultRat, rhsRat); result = result.Div(temp, m_precision);
powrat(&resultRat, hno , m_radix, m_precision);
break;
} }
case IDC_ROOT: // Calculates rhsRat to the resultRat(th) root. else
{ {
NumObjAssign(&hno, resultRat); iFinalSign = iNumeratorSign;
NumObjAssign(&resultRat, rhsRat); result = result.Mod(temp);
rootrat(&resultRat, hno, m_radix, m_precision);
break;
} }
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) catch (DWORD dwErrCode)
@ -187,15 +141,8 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa
DisplayError(dwErrCode); DisplayError(dwErrCode);
// On error, return the original value // On error, return the original value
destroyrat(resultRat); result = lhs;
resultRat = lhs.ToPRAT();
} }
destroyrat(hno);
destroyrat(rhsRat);
Rational result{ resultRat };
destroyrat(resultRat);
return result; return result;
} }

View File

@ -1,29 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // 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 "pch.h"
#include "Header Files/CalcEngine.h" #include "Header Files/CalcEngine.h"
using namespace CalcEngine; 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. // dont change that.
void CCalcEngine::SetRadixTypeAndNumWidth(RADIX_TYPE radixtype, NUM_WIDTH numwidth) 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. // back to 1111,1111,1000,0001 when in Word mode.
if (m_fIntegerMode) if (m_fIntegerMode)
{ {
PRAT curRat = m_currentVal.ToPRAT(); uint64_t w64Bits = m_currentVal.ToUInt64_t(m_radix, m_precision);
ULONGLONG w64Bits = NumObjGetUlValue(curRat, m_radix, m_precision);
bool fMsb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1; // make sure you use the old width bool fMsb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1; // make sure you use the old width
if (fMsb) if (fMsb)
{ {
// If high bit is set, then get the decimal number in -ve 2'scompl form. // If high bit is set, then get the decimal number in -ve 2'scompl form.
PRAT chopRat = m_chopNumbers[m_numwidth].ToPRAT(); auto tempResult = m_currentVal.Not(true /* IntegerMode */, m_chopNumbers[m_numwidth], m_radix, m_precision);
NumObjNot(&curRat, true, chopRat, m_radix, m_precision); tempResult = tempResult.Add(1, m_precision);
destroyrat(chopRat);
addrat(&curRat, rat_one, m_precision);
NumObjNegate(&curRat);
m_currentVal = Rational{ curRat };
}
destroyrat(curRat); m_currentVal = tempResult.Negate();
}
} }
if (radixtype >= HEX_RADIX && radixtype <= BIN_RADIX) if (radixtype >= HEX_RADIX && radixtype <= BIN_RADIX)
@ -84,9 +63,9 @@ LONG CCalcEngine::DwWordBitWidthFromeNumWidth(NUM_WIDTH /*numwidth*/)
return wmax; 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; uint32_t radix = 10;
// convert special bases into symbolic values // convert special bases into symbolic values
@ -106,25 +85,16 @@ bool CCalcEngine::TryToggleBit(CalcEngine::Rational& rat, DWORD wbitno)
return false; // ignore error cant happen return false; // ignore error cant happen
} }
PRAT hnumPow = nullptr; Rational result = Integer(rat, m_radix, m_precision);
NumObjAssign(&hnumPow, rat_two); if (result.IsZero())
PRAT hnum = longtorat(wbitno);
powrat(&hnumPow, hnum, m_radix, m_precision);
PRAT resultRat = rat.ToPRAT();
intrat(&resultRat, m_radix, m_precision);
if (NumObjIsZero(resultRat))
{ {
// This is the same work around happenning in SciCalcFunctions. Ought to move to intrat function itself. // 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. // Basic bug is there which doesn't treat 0/ n as 0, or -0 as 0 etc.
NumObjAssign(&resultRat, rat_zero); result = Rational{};
} }
xorrat(&resultRat, hnumPow, m_radix, m_precision); auto pow = Pow(2, static_cast<int32_t>(wbitno), m_radix, m_precision);
rat = Rational{ resultRat }; rat = result.Xor(pow, m_radix, m_precision);
destroyrat(resultRat);
NumObjDestroy(&hnumPow);
NumObjDestroy(&hnum);
return true; return true;
} }

View File

@ -293,9 +293,7 @@ wstring COpndCommand::GetString(uint32_t radix, int32_t precision, wchar_t decim
if (m_fInitialized) if (m_fInitialized)
{ {
PRAT valRat = m_value.ToPRAT(); result = m_value.ToString(radix, eNUMOBJ_FMT::FMT_FLOAT, precision);
result = NumObjToString(valRat, radix, eNUMOBJ_FMT::FMT_FLOAT, precision);
destroyrat(valRat);
} }
return result; return result;

View File

@ -12,6 +12,9 @@ namespace CalcEngine
Rational() noexcept; Rational() noexcept;
Rational(Number const& n) noexcept; Rational(Number const& n) noexcept;
Rational(Number const& p, Number const& q) 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; explicit Rational(PRAT prat) noexcept;
PRAT ToPRAT() const; PRAT ToPRAT() const;
@ -19,7 +22,29 @@ namespace CalcEngine
Number const& P() const; Number const& P() const;
Number const& Q() 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 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: private:
Number m_p; Number m_p;

View File

@ -1,79 +1,35 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
/**************************************************************************\ #include "Rational.h"
* *
* *
* *
* # # ##### *
* # # # # # *
* # # # # # # # *
* # ### ### # # *
* # # ### # # # ### # # ### ##### # ### ### ### *
* # ## # # # ## # # # # # # ## # # # *
* # # # # # # # # # ##### # # ##### # *
* # # # # # # # # # # # # # # ## *
* # # # # # # # # # ### # # ### ### ## *
* *
* *
* Infinte Precision Production Version *
* *
\**************************************************************************/
//
// RETAIL version of NUMOBJ math that uses Infinite Precision
//
#include "../Ratpack/ratpak.h"
// namespace CalcEngine::RationalMath
// Unary functions {
// Rational Frac(Rational const& rat, uint32_t radix, int32_t precision);
void NumObjInvert(PRAT *phno, int32_t precision); Rational Integer(Rational const& rat, uint32_t radix, int32_t precision);
void NumObjNegate(PRAT *phno);
void NumObjAbs(PRAT *phno);
void NumObjSin(PRAT *phno, ANGLE_TYPE angletype, uint32_t radix, int32_t precision); Rational Pow(Rational const& base, Rational const& pow, uint32_t radix, int32_t precision);
void NumObjCos(PRAT *phno, ANGLE_TYPE angletype, uint32_t radix, int32_t precision); Rational Root(Rational const& base, Rational const& root, uint32_t radix, int32_t precision);
void NumObjTan(PRAT *phno, ANGLE_TYPE angletype, uint32_t radix, int32_t precision); Rational Fact(Rational const& rat, uint32_t radix, int32_t precision);
void NumObjAntiLog10(PRAT *phno, 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);
// Rational Invert(Rational const& rat, int32_t precision);
// Comparison functions Rational Abs(Rational const& rat);
//
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 Sin(Rational const& rat, ANGLE_TYPE angletype, uint32_t radix, int32_t precision);
// Assignment operator. ('=' in C language) 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);
void NumObjAssign(PRAT *phnol, PRAT hnor); 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);
// Rational Sinh(Rational const& rat, uint32_t radix, int32_t precision);
// Data type conversion functions Rational Cosh(Rational const& rat, uint32_t radix, int32_t precision);
// Rational Tanh(Rational const& rat, uint32_t radix, int32_t precision);
void NumObjSetIntValue(PRAT *phnol, LONG i ); Rational ASinh(Rational const& rat, uint32_t radix, int32_t precision);
void NumObjSetUlonglongValue(PRAT *phnol, ULONGLONG ul, 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);
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);