Make special cases (0 inf nan) work for frem.

Besides APFloat, this involved removing code
from two places that thought they knew the
result of frem(0., x) but were wrong.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62645 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Dale Johannesen
2009-01-21 00:35:19 +00:00
parent 6cf7c390ec
commit ed6af24e14
5 changed files with 384 additions and 38 deletions
+63 -23
View File
@@ -1405,6 +1405,42 @@ APFloat::divideSpecials(const APFloat &rhs)
}
}
APFloat::opStatus
APFloat::modSpecials(const APFloat &rhs)
{
switch(convolve(category, rhs.category)) {
default:
assert(0);
case convolve(fcNaN, fcZero):
case convolve(fcNaN, fcNormal):
case convolve(fcNaN, fcInfinity):
case convolve(fcNaN, fcNaN):
case convolve(fcZero, fcInfinity):
case convolve(fcZero, fcNormal):
case convolve(fcNormal, fcInfinity):
return opOK;
case convolve(fcZero, fcNaN):
case convolve(fcNormal, fcNaN):
case convolve(fcInfinity, fcNaN):
category = fcNaN;
copySignificand(rhs);
return opOK;
case convolve(fcNormal, fcZero):
case convolve(fcInfinity, fcZero):
case convolve(fcInfinity, fcNormal):
case convolve(fcInfinity, fcInfinity):
case convolve(fcZero, fcZero):
makeNaN();
return opInvalidOp;
case convolve(fcNormal, fcNormal):
return opOK;
}
}
/* Change sign. */
void
APFloat::changeSign()
@@ -1557,35 +1593,39 @@ APFloat::opStatus
APFloat::mod(const APFloat &rhs, roundingMode rounding_mode)
{
opStatus fs;
APFloat V = *this;
unsigned int origSign = sign;
assertArithmeticOK(*semantics);
fs = V.divide(rhs, rmNearestTiesToEven);
if (fs == opDivByZero)
return fs;
fs = modSpecials(rhs);
int parts = partCount();
integerPart *x = new integerPart[parts];
bool ignored;
fs = V.convertToInteger(x, parts * integerPartWidth, true,
rmTowardZero, &ignored);
if (fs==opInvalidOp)
return fs;
if (category == fcNormal && rhs.category == fcNormal) {
APFloat V = *this;
unsigned int origSign = sign;
fs = V.convertFromZeroExtendedInteger(x, parts * integerPartWidth, true,
rmNearestTiesToEven);
assert(fs==opOK); // should always work
fs = V.divide(rhs, rmNearestTiesToEven);
if (fs == opDivByZero)
return fs;
fs = V.multiply(rhs, rounding_mode);
assert(fs==opOK || fs==opInexact); // should not overflow or underflow
int parts = partCount();
integerPart *x = new integerPart[parts];
bool ignored;
fs = V.convertToInteger(x, parts * integerPartWidth, true,
rmTowardZero, &ignored);
if (fs==opInvalidOp)
return fs;
fs = subtract(V, rounding_mode);
assert(fs==opOK || fs==opInexact); // likewise
fs = V.convertFromZeroExtendedInteger(x, parts * integerPartWidth, true,
rmNearestTiesToEven);
assert(fs==opOK); // should always work
if (isZero())
sign = origSign; // IEEE754 requires this
delete[] x;
fs = V.multiply(rhs, rounding_mode);
assert(fs==opOK || fs==opInexact); // should not overflow or underflow
fs = subtract(V, rounding_mode);
assert(fs==opOK || fs==opInexact); // likewise
if (isZero())
sign = origSign; // IEEE754 requires this
delete[] x;
}
return fs;
}