CalcEngine: Manage precision internally to Rational and convert functions to operator overrides (#35)

* Convert Rational::Negate to an operator override
* Convert Rational::Add to + and += operator overrides.
* Convert Rational::Sub to - and -= operator overrides.
* Convert Rational::Div and ::Mul to use /, /=, *, *= operator overrides.
* Convert Rational::Mod to use %= and % operator overrides
* Convert Rational::Rsh and ::Lsh to use >>=, >>, <<=, << operator overrides
* Convert Rational::And, ::Or, ::Xor to use &=, &, |=, |, ^=, ^ operator overrides
* Convert Rational relational functions to operator overrides
* Remove unnecessary precision arguments from Rational class and remove use of explicit Rational constructors in favor of implicit conversions for value types
* Remove unnecessary precision variable from RationalMath operations
* Replace unnecessary Rational::Not with Xor operation
* Remove unnecessary Rational::IsZero() in favor of == 0 comparisons
* Fix rounding issues in ratpak that result from using large precisions.
* Move assignment stmt out of IsCurrentTooBigForTrig
This commit is contained in:
Josh Koon
2019-02-25 11:41:32 -08:00
committed by GitHub
parent 424891516f
commit 0cb5e9bae0
15 changed files with 368 additions and 332 deletions

View File

@@ -1259,20 +1259,7 @@ wstring NumberToString(_Inout_ PNUMBER& pnum, int format, uint32_t radix, int32_
//-----------------------------------------------------------------------------
wstring RatToString(_Inout_ PRAT& prat, int format, uint32_t radix, int32_t precision)
{
// Convert p and q of rational form from internal base to requested base.
// Scale by largest power of BASEX possible.
long scaleby = min(prat->pp->exp, prat->pq->exp);
scaleby = max(scaleby, 0);
prat->pp->exp -= scaleby;
prat->pq->exp -= scaleby;
PNUMBER p = nRadixxtonum(prat->pp, radix, precision);
PNUMBER q = nRadixxtonum(prat->pq, radix, precision);
// finally take the time hit to actually divide.
divnum(&p, q, radix, precision);
destroynum(q);
PNUMBER p = RatToNumber(prat, radix, precision);
wstring result = NumberToString(p, format, radix, precision);
destroynum(p);
@@ -1280,6 +1267,40 @@ wstring RatToString(_Inout_ PRAT& prat, int format, uint32_t radix, int32_t prec
return result;
}
PNUMBER RatToNumber(_In_ PRAT prat, uint32_t radix, int32_t precision)
{
PRAT temprat = nullptr;
DUPRAT(temprat, prat);
// Convert p and q of rational form from internal base to requested base.
// Scale by largest power of BASEX possible.
long scaleby = min(temprat->pp->exp, temprat->pq->exp);
scaleby = max(scaleby, 0);
temprat->pp->exp -= scaleby;
temprat->pq->exp -= scaleby;
PNUMBER p = nRadixxtonum(temprat->pp, radix, precision);
PNUMBER q = nRadixxtonum(temprat->pq, radix, precision);
destroyrat(temprat);
// finally take the time hit to actually divide.
divnum(&p, q, radix, precision);
destroynum(q);
return p;
}
// Converts a PRAT to a PNUMBER and back to a PRAT, flattening/simplifying the rational in the process
void flatrat(_Inout_ PRAT& prat, uint32_t radix, int32_t precision)
{
PNUMBER pnum = RatToNumber(prat, radix, precision);
destroyrat(prat);
prat = numtorat(pnum, radix);
destroynum(pnum);
}
//-----------------------------------------------------------------------------
//
// FUNCTION: gcd

View File

@@ -73,16 +73,11 @@ void gcdrat( PRAT *pa, uint32_t radix, int32_t precision)
void fracrat( PRAT *pa , uint32_t radix, int32_t precision)
{
// Only do the intrat operation if number is nonzero.
// Only do the flatrat operation if number is nonzero.
// and only if the bottom part is not one.
if ( !zernum( (*pa)->pp ) && !equnum( (*pa)->pq, num_one ) )
{
wstring ratStr = RatToString(*pa, FMT_FLOAT, radix, precision);
PNUMBER pnum = StringToNumber(ratStr, radix, precision);
destroyrat( *pa );
*pa = numtorat( pnum, radix);
destroynum( pnum );
flatrat(*pa, radix, precision);
}
remnum( &((*pa)->pp), (*pa)->pq, BASEX );

View File

@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
@@ -316,6 +316,10 @@ extern std::wstring NumberToString(_Inout_ PNUMBER& pnum, int format, uint32_t r
// returns a text representation of a PRAT
extern std::wstring RatToString(_Inout_ PRAT& prat, int format, uint32_t radix, int32_t precision);
// converts a PRAT into a PNUMBER
extern PNUMBER RatToNumber(_In_ PRAT prat, uint32_t radix, int32_t precision);
// flattens a PRAT by converting it to a PNUMBER and back to a PRAT
extern void flatrat(_Inout_ PRAT& prat, uint32_t radix, int32_t precision);
extern long numtolong(_In_ PNUMBER pnum, uint32_t radix );
extern long rattolong(_In_ PRAT prat, uint32_t radix, int32_t precision);

View File

@@ -291,19 +291,18 @@ void intrat( PRAT *px, uint32_t radix, int32_t precision)
// and only if the bottom part is not one.
if ( !zernum( (*px)->pp ) && !equnum( (*px)->pq, num_one ) )
{
wstring ratStr = RatToString(*px, FMT_FLOAT, radix, precision);
PNUMBER pnum = StringToNumber(ratStr, radix, precision);
destroyrat( *px );
*px = numtorat( pnum, radix);
destroynum( pnum );
flatrat(*px, radix, precision);
// Subtract the fractional part of the rational
PRAT pret = nullptr;
DUPRAT(pret,*px);
modrat( &pret, rat_one );
subrat( px, pret, precision);
destroyrat( pret );
// Simplify the value if possible to resolve rounding errors
flatrat(*px, radix, precision);
}
}