in src/CalcManager/Ratpack/exp.cpp [399:527]
void powratcomp(_Inout_ PRAT* px, _In_ PRAT y, uint32_t radix, int32_t precision)
{
int32_t sign = SIGN(*px);
// Take the absolute value
(*px)->pp->sign = 1;
(*px)->pq->sign = 1;
if (zerrat(*px))
{
// *px is zero.
if (rat_lt(y, rat_zero, precision))
{
throw(CALC_E_DOMAIN);
}
else if (zerrat(y))
{
// *px and y are both zero, special case a 1 return.
DUPRAT(*px, rat_one);
// Ensure sign is positive.
sign = 1;
}
}
else
{
PRAT pxint = nullptr;
DUPRAT(pxint, *px);
subrat(&pxint, rat_one, precision);
if (rat_gt(pxint, rat_negsmallest, precision) && rat_lt(pxint, rat_smallest, precision) && (sign == 1))
{
// *px is one, special case a 1 return.
DUPRAT(*px, rat_one);
// Ensure sign is positive.
sign = 1;
}
else
{
// Only do the exp if the number isn't zero or one
PRAT podd = nullptr;
DUPRAT(podd, y);
fracrat(&podd, radix, precision);
if (rat_gt(podd, rat_negsmallest, precision) && rat_lt(podd, rat_smallest, precision))
{
// If power is an integer let ratpowi32 deal with it.
PRAT iy = nullptr;
DUPRAT(iy, y);
subrat(&iy, podd, precision);
int32_t inty = rattoi32(iy, radix, precision);
PRAT plnx = nullptr;
DUPRAT(plnx, *px);
lograt(&plnx, precision);
mulrat(&plnx, iy, precision);
if (rat_gt(plnx, rat_max_exp, precision) || rat_lt(plnx, rat_min_exp, precision))
{
// Don't attempt exp of anything large or small.A
destroyrat(plnx);
destroyrat(iy);
destroyrat(pxint);
destroyrat(podd);
throw(CALC_E_DOMAIN);
}
destroyrat(plnx);
ratpowi32(px, inty, precision);
if ((inty & 1) == 0)
{
sign = 1;
}
destroyrat(iy);
}
else
{
// power is a fraction
if (sign == -1)
{
// Need to throw an error if the exponent has an even denominator.
// As a first step, the numerator and denominator must be divided by 2 as many times as
// possible, so that 2/6 is allowed.
// If the final numerator is still even, the end result should be positive.
PRAT pNumerator = nullptr;
PRAT pDenominator = nullptr;
bool fBadExponent = false;
// Get the numbers in arbitrary precision rational number format
DUPRAT(pNumerator, rat_zero); // pNumerator->pq is 1 one
DUPRAT(pDenominator, rat_zero); // pDenominator->pq is 1 one
DUPNUM(pNumerator->pp, y->pp);
pNumerator->pp->sign = 1;
DUPNUM(pDenominator->pp, y->pq);
pDenominator->pp->sign = 1;
while (IsEven(pNumerator, radix, precision) && IsEven(pDenominator, radix, precision)) // both Numerator & denominator is even
{
divrat(&pNumerator, rat_two, precision);
divrat(&pDenominator, rat_two, precision);
}
if (IsEven(pDenominator, radix, precision)) // denominator is still even
{
fBadExponent = true;
}
if (IsEven(pNumerator, radix, precision)) // numerator is still even
{
sign = 1;
}
destroyrat(pNumerator);
destroyrat(pDenominator);
if (fBadExponent)
{
throw(CALC_E_DOMAIN);
}
}
else
{
// If the exponent is not odd disregard the sign.
sign = 1;
}
lograt(px, precision);
mulrat(px, y, precision);
exprat(px, radix, precision);
}
destroyrat(podd);
}
destroyrat(pxint);
}
(*px)->pp->sign *= sign;
}