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 "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<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 :
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;
}
}

View File

@ -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<wstring, CSTRINGSENGMAX> 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<Rational>()},
m_memoryValue{ make_unique<Rational>() },
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);
}
}

View File

@ -32,9 +32,9 @@ 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;
@ -46,7 +46,7 @@ INT NPrecedenceOfOp(int nopCode)
{
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
}
@ -134,7 +134,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
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) ||
IsOpInRange(wParam, IDC_BINEDITSTART, IDC_BINEDITSTART + 63) ||
(IDC_INV == wParam) ||
(IDC_SIGN == wParam && 10 != m_radix))
{
@ -145,7 +145,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
}
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<unsigned int>(wParam-IDC_0);
unsigned int iValue = static_cast<unsigned int>(wParam - IDC_0);
// this is redundant, illegal keys are disabled
if (iValue >= static_cast<unsigned int>(m_radix))
@ -186,7 +186,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
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;
@ -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 */);
@ -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,7 +372,7 @@ DoPrecedenceCheckAgain:
}
/* Now branch off to do other commands and functions. */
switch(wParam)
switch (wParam)
{
case IDC_CLEAR: /* Total clear. */
{
@ -384,10 +384,10 @@ DoPrecedenceCheckAgain:
m_lastVal = Rational{};
m_bChangeOp=false;
m_nPrecNum=m_nTempCom=m_nLastCom=m_nOpCode= m_openParenCount =0;
m_bChangeOp = false;
m_nPrecNum = m_nTempCom = m_nLastCom = m_nOpCode = m_openParenCount = 0;
m_nPrevOpCode = 0;
m_bNoPrevEqu= true;
m_bNoPrevEqu = true;
/* clear the parenthesis status box indicator, this will not be
@ -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;
@ -691,10 +691,7 @@ DoPrecedenceCheckAgain:
m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal);
}
PRAT curRat = m_currentVal.ToPRAT();
NumObjNegate(&curRat);
m_currentVal = Rational{ curRat };
destroyrat(curRat);
m_currentVal = m_currentVal.Negate();
DisplayNum();
m_HistoryCollector.AddUnaryOpToHistory(IDC_SIGN, m_bInv, m_angletype);
@ -703,7 +700,7 @@ DoPrecedenceCheckAgain:
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<Rational>(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<Rational>(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<Rational>(TruncateNumForIntMath(Rational{ memRat }));
destroyrat(curRat);
destroyrat(memRat);
Rational result = m_memoryValue->Sub(m_currentVal, m_precision);
m_memoryValue = make_unique<Rational>(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);
}
}
}

View File

@ -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,18 +83,15 @@ 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 ||
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.bRecord != m_bRecord)
{
gldPrevious.precision = m_precision;
gldPrevious.radix = m_radix;
@ -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);
}

View File

@ -21,43 +21,37 @@
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);
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);
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);
PRAT curRat = m_currentVal.ToPRAT();
ULONGLONG w64Bits = NumObjGetUlValue(curRat, m_radix, m_precision);
ULONGLONG msb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1;
result = Integer(rat, m_radix, m_precision);
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
NumObjSetUlonglongValue(&curRat, w64Bits, m_radix, m_precision);
m_currentVal = Rational{ curRat };
destroyrat(curRat);
result = Rational{ w64Bits, m_radix, m_precision };
}
break;
@ -65,53 +59,29 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r
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);
result = Integer(rat, m_radix, m_precision);
ULONGLONG lsb = ((w64Bits & 0x01) == 1) ? 1 : 0;
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));
NumObjSetUlonglongValue(&curRat, w64Bits, m_radix, m_precision);
m_currentVal = Rational{ curRat };
destroyrat(curRat);
result = Rational{ w64Bits, m_radix, m_precision };
}
break;
case IDC_PERCENT:
{
PRAT hno = nullptr;
PRAT hno100 = nullptr;
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);
divrat(&tempRat, hno100, m_precision);
destroyrat(hno100);
result = rat.Div(100, m_precision);
}
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;
result = m_lastVal.Div(100, m_precision);
result = rat.Mul(result, m_precision);
}
break;
}
@ -119,106 +89,76 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r
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);
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)
{
m_bInv ? asinhrat(&tempRat, m_radix, m_precision) : sinhrat(&tempRat, m_radix, m_precision);
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)
{
m_bInv ? acosanglerat(&tempRat, m_angletype, m_radix, m_precision) : NumObjCos(&tempRat, m_angletype, m_radix, m_precision);
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)
{
m_bInv ? acoshrat(&tempRat, m_radix, m_precision) : coshrat(&tempRat, m_radix, m_precision);
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)
{
m_bInv ? atananglerat(&tempRat, m_angletype, m_radix, m_precision) : NumObjTan(&tempRat, m_angletype, m_radix, m_precision);
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)
{
m_bInv ? atanhrat(&tempRat, m_precision) : tanhrat(&tempRat, m_radix, m_precision);
result = m_bInv ? ATanh(rat, m_precision) : Tanh(rat, m_radix, m_precision);
}
break;
case IDC_REC: /* Reciprocal. */
NumObjInvert(&tempRat, m_precision);
result = Invert(rat, m_precision);
break;
case IDC_SQR: /* Square */
powrat(&tempRat, rat_two, m_radix, m_precision);
result = Pow(rat, 2, m_radix, m_precision);
break;
case IDC_SQRT: /* Sqrt only in Std mode */
rootrat(&tempRat, rat_two, m_radix, m_precision);
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. */
{
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;
}
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. */
log10rat(&tempRat, m_precision);
result = Log10(rat, m_precision);
break;
case IDC_POW10:
NumObjAntiLog10(&tempRat, m_radix, m_precision);
result = Pow(10, rat, 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);
}
result = m_bInv ? Exp(rat, m_radix, m_precision) : Log(rat, m_precision);
break;
case IDC_FAC: /* Calculate factorial. Inverse is ineffective. */
factrat(&tempRat, m_radix, m_precision);
result = Fact(rat, m_radix, m_precision);
break;
case IDC_DEGREES:
@ -231,63 +171,43 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r
{
if (!m_fIntegerMode)
{
PRAT hnoMin = nullptr;
PRAT hnoSec = nullptr;
PRAT hnoShft = nullptr;
Rational shftRat{ m_bInv ? 100 : 60 };
try
{
NumObjSetIntValue(&hnoShft, m_bInv ? 100 : 60);
Rational degreeRat = Integer(rat, m_radix, m_precision);
NumObjAssign(&hnoMin, tempRat);
intrat(&tempRat, m_radix, m_precision);
Rational minuteRat = rat.Sub(degreeRat, m_precision);
minuteRat = minuteRat.Mul(shftRat, m_precision);
subrat(&hnoMin, tempRat, m_precision);
mulrat(&hnoMin, hnoShft, m_precision);
NumObjAssign(&hnoSec, hnoMin );
intrat(&hnoMin, m_radix, m_precision);
Rational secondRat = minuteRat;
subrat(&hnoSec, hnoMin, m_precision);
mulrat(&hnoSec, hnoShft, m_precision);
minuteRat = Integer(minuteRat, m_radix, m_precision);
secondRat = secondRat.Sub(minuteRat, m_precision);
secondRat = secondRat.Mul(shftRat, m_precision);
//
// tempRat == degrees, hnoMin == minutes, hnoSec == seconds
// degreeRat == degrees, minuteRat == minutes, secondRat == seconds
//
NumObjSetIntValue(&hnoShft, m_bInv ? 60 : 100);
divrat(&hnoSec, hnoShft, m_precision);
addrat(&hnoMin, hnoSec, m_precision);
shftRat = Rational{ m_bInv ? 60 : 100 };
secondRat = secondRat.Div(shftRat, m_precision);
divrat(&hnoMin, hnoShft, m_precision);
addrat(&tempRat, hnoMin, m_precision);
minuteRat = minuteRat.Add(secondRat, m_precision);
minuteRat = minuteRat.Div(shftRat, m_precision);
destroyrat(hnoShft);
destroyrat(hnoMin);
destroyrat(hnoSec);
}
catch (DWORD nErrCode)
{
destroyrat(hnoShft);
destroyrat(hnoMin);
destroyrat(hnoSec);
destroyrat(tempRat);
throw nErrCode;
}
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 */

View File

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

View File

@ -5,138 +5,104 @@
#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)
{
NumObjSetIntValue(&hno, m_dwWordBitWidth);
if (NumObjIsGreaterEq(resultRat, hno, m_precision)) // Lsh/Rsh >= than current word size is always 0
if (m_fIntegerMode && result.IsGreaterEq(Rational{ m_dwWordBitWidth }, m_precision)) // Lsh/Rsh >= than current word size is always 0
{
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)
{
NumObjSetIntValue(&hno, m_dwWordBitWidth);
if (NumObjIsGreaterEq(resultRat, hno, m_precision))
if (m_fIntegerMode && result.IsGreaterEq(Rational{ m_dwWordBitWidth }, m_precision)) // Lsh/Rsh >= than current word size is always 0
{
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;
// 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);
auto temp = result;
result = rhs;
if(m_fIntegerMode)
if (m_fIntegerMode)
{
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;
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);
result = rhs.Not(true /* IntegerMode */, m_chopNumbers[m_numwidth], m_radix, m_precision);
result = result.Add(1, m_precision);
iNumeratorSign = -1;
}
w64Bits = NumObjGetUlValue(hno, m_radix, m_precision);
w64Bits = temp.ToUInt64_t(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);
temp = temp.Not(true /* IntegerMode */, m_chopNumbers[m_numwidth], m_radix, m_precision);
temp = temp.Add(1, m_precision);
iDenominatorSign = -1;
}
@ -145,57 +111,38 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa
if (operation == IDC_DIV)
{
iFinalSign = iNumeratorSign * iDenominatorSign;
divrat(&resultRat, hno, m_precision);
result = result.Div(temp, m_precision);
}
else
{
iFinalSign = iNumeratorSign;
modrat(&resultRat, hno );
result = result.Mod(temp);
}
if (m_fIntegerMode && iFinalSign == -1)
{
intrat(&resultRat, m_radix, m_precision);
NumObjNegate(&resultRat);
result = Integer(result, m_radix, m_precision).Negate();
}
break;
}
case IDC_PWR: // Calculates rhsRat to the resultRat(th) power.
{
NumObjAssign(&hno, resultRat);
NumObjAssign(&resultRat, rhsRat);
powrat(&resultRat, hno , m_radix, m_precision);
case IDC_PWR: // Calculates rhs to the result(th) power.
result = Pow(rhs, result, m_radix, m_precision);
break;
}
case IDC_ROOT: // Calculates rhsRat to the resultRat(th) root.
{
NumObjAssign(&hno, resultRat);
NumObjAssign(&resultRat, rhsRat);
rootrat(&resultRat, hno, m_radix, m_precision);
case IDC_ROOT: // Calculates rhs to the result(th) root.
result = Root(rhs, result, m_radix, m_precision);
break;
}
}
}
catch (DWORD dwErrCode)
{
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;
}

View File

@ -1,28 +1,12 @@
// 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
// 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<int32_t>(wbitno), m_radix, m_precision);
rat = result.Xor(pow, m_radix, m_precision);
return true;
}

View File

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

View File

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

View File

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