* 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.
227 lines
8.1 KiB
C++
227 lines
8.1 KiB
C++
// 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. ***/
|
|
/*** ***/
|
|
/*** scifunc.c ***/
|
|
/*** ***/
|
|
/*** Functions contained: ***/
|
|
/*** SciCalcFunctions--do sin, cos, tan, com, log, ln, rec, fac, etc.***/
|
|
/*** DisplayError--Error display driver. ***/
|
|
/*** ***/
|
|
/*** Functions called: ***/
|
|
/*** SciCalcFunctions call DisplayError. ***/
|
|
/*** ***/
|
|
/*** ***/
|
|
/**************************************************************************/
|
|
#include "pch.h"
|
|
#include "Header Files/CalcEngine.h"
|
|
|
|
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)
|
|
{
|
|
Rational result{};
|
|
try
|
|
{
|
|
switch (op)
|
|
{
|
|
case IDC_CHOP:
|
|
result = m_bInv ? Frac(rat, m_radix, m_precision) : Integer(rat, m_radix, m_precision);
|
|
break;
|
|
|
|
/* Return complement. */
|
|
case IDC_COM:
|
|
result = rat.Not(m_fIntegerMode, m_chopNumbers[m_numwidth], m_radix, m_precision);
|
|
break;
|
|
|
|
// Rotate Left with hi bit wrapped over to lo bit
|
|
case IDC_ROL:
|
|
if (m_fIntegerMode)
|
|
{
|
|
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
|
|
|
|
result = Rational{ w64Bits, m_radix, m_precision };
|
|
}
|
|
break;
|
|
|
|
// Rotate right with lo bit wrapped over to hi bit
|
|
case IDC_ROR:
|
|
if (m_fIntegerMode)
|
|
{
|
|
result = Integer(rat, m_radix, m_precision);
|
|
|
|
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));
|
|
|
|
result = Rational{ w64Bits, m_radix, m_precision };
|
|
}
|
|
break;
|
|
|
|
case IDC_PERCENT:
|
|
{
|
|
// If the operator is multiply/divide, we evaluate this as "X [op] (Y%)"
|
|
// Otherwise, we evaluate it as "X [op] (X * Y%)"
|
|
if (m_nOpCode == IDC_MUL || m_nOpCode == IDC_DIV)
|
|
{
|
|
result = rat.Div(100, m_precision);
|
|
}
|
|
else
|
|
{
|
|
result = m_lastVal.Div(100, m_precision);
|
|
result = rat.Mul(result, m_precision);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IDC_SIN: /* Sine; normal and arc */
|
|
if (!m_fIntegerMode)
|
|
{
|
|
result = m_bInv ? ASin(rat, m_angletype, m_radix, m_precision) : Sin(rat, m_angletype, m_radix, m_precision);
|
|
}
|
|
break;
|
|
|
|
case IDC_SINH: /* Sine- hyperbolic and archyperbolic */
|
|
if (!m_fIntegerMode)
|
|
{
|
|
result = m_bInv ? ASinh(rat, m_radix, m_precision) : Sinh(rat, m_radix, m_precision);
|
|
}
|
|
break;
|
|
|
|
case IDC_COS: /* Cosine, follows convention of sine function. */
|
|
if (!m_fIntegerMode)
|
|
{
|
|
result = m_bInv ? ACos(rat, m_angletype, m_radix, m_precision) : Cos(rat, m_angletype, m_radix, m_precision);
|
|
}
|
|
break;
|
|
|
|
case IDC_COSH: /* Cosine hyperbolic, follows convention of sine h function. */
|
|
if (!m_fIntegerMode)
|
|
{
|
|
result = m_bInv ? ACosh(rat, m_radix, m_precision) : Cosh(rat, m_radix, m_precision);
|
|
}
|
|
break;
|
|
|
|
case IDC_TAN: /* Same as sine and cosine. */
|
|
if (!m_fIntegerMode)
|
|
{
|
|
result = m_bInv ? ATan(rat, m_angletype, m_radix, m_precision) : Tan(rat, m_angletype, m_radix, m_precision);
|
|
}
|
|
break;
|
|
|
|
case IDC_TANH: /* Same as sine h and cosine h. */
|
|
if (!m_fIntegerMode)
|
|
{
|
|
result = m_bInv ? ATanh(rat, m_precision) : Tanh(rat, m_radix, m_precision);
|
|
}
|
|
break;
|
|
|
|
case IDC_REC: /* Reciprocal. */
|
|
result = Invert(rat, m_precision);
|
|
break;
|
|
|
|
case IDC_SQR: /* Square */
|
|
result = Pow(rat, 2, m_radix, m_precision);
|
|
break;
|
|
|
|
case IDC_SQRT: /* Square Root */
|
|
result = Root(rat, 2, m_radix, m_precision);
|
|
break;
|
|
|
|
case IDC_CUBEROOT:
|
|
case IDC_CUB: /* Cubing and cube root functions. */
|
|
result = IDC_CUBEROOT == op ? Root(rat, 3, m_radix, m_precision) : Pow(rat, 3, m_radix, m_precision);
|
|
break;
|
|
|
|
case IDC_LOG: /* Functions for common log. */
|
|
result = Log10(rat, m_precision);
|
|
break;
|
|
|
|
case IDC_POW10:
|
|
result = Pow(10, rat, m_radix, m_precision);
|
|
break;
|
|
|
|
case IDC_LN: /* Functions for natural log. */
|
|
result = m_bInv ? Exp(rat, m_radix, m_precision) : Log(rat, m_precision);
|
|
break;
|
|
|
|
case IDC_FAC: /* Calculate factorial. Inverse is ineffective. */
|
|
result = Fact(rat, m_radix, m_precision);
|
|
break;
|
|
|
|
case IDC_DEGREES:
|
|
ProcessCommand(IDC_INV);
|
|
// This case falls through to IDC_DMS case because in the old Win32 Calc,
|
|
// the degrees functionality was achieved as 'Inv' of 'dms' operation,
|
|
// so setting the IDC_INV command first and then performing 'dms' operation as global variables m_bInv, m_bRecord
|
|
// are set properly through ProcessCommand(IDC_INV)
|
|
case IDC_DMS:
|
|
{
|
|
if (!m_fIntegerMode)
|
|
{
|
|
Rational shftRat{ m_bInv ? 100 : 60 };
|
|
|
|
Rational degreeRat = Integer(rat, m_radix, m_precision);
|
|
|
|
Rational minuteRat = rat.Sub(degreeRat, m_precision);
|
|
minuteRat = minuteRat.Mul(shftRat, m_precision);
|
|
|
|
Rational secondRat = minuteRat;
|
|
|
|
minuteRat = Integer(minuteRat, m_radix, m_precision);
|
|
|
|
secondRat = secondRat.Sub(minuteRat, m_precision);
|
|
secondRat = secondRat.Mul(shftRat, m_precision);
|
|
|
|
//
|
|
// degreeRat == degrees, minuteRat == minutes, secondRat == seconds
|
|
//
|
|
|
|
shftRat = Rational{ m_bInv ? 60 : 100 };
|
|
secondRat = secondRat.Div(shftRat, m_precision);
|
|
|
|
minuteRat = minuteRat.Add(secondRat, m_precision);
|
|
minuteRat = minuteRat.Div(shftRat, m_precision);
|
|
|
|
result = degreeRat.Add(minuteRat, m_precision);
|
|
}
|
|
break;
|
|
}
|
|
} // end switch( op )
|
|
}
|
|
catch (DWORD nErrCode)
|
|
{
|
|
DisplayError(nErrCode);
|
|
result = rat;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/* Routine to display error messages and set m_bError flag. Errors are */
|
|
/* called with DisplayError (n), where n is a DWORD between 0 and 5. */
|
|
|
|
void CCalcEngine::DisplayError(DWORD nError)
|
|
{
|
|
wstring errorString{ GetString(IDS_ERRORS_FIRST + SCODE_CODE(nError)) };
|
|
|
|
SetPrimaryDisplay(errorString, true /*isError*/);
|
|
|
|
m_bError = true; /* Set error flag. Only cleared with CLEAR or CENTR. */
|
|
|
|
m_HistoryCollector.ClearHistoryLine(errorString);
|
|
}
|
|
|