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

@ -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;
}