Rewrite EngMulDiv.

svn path=/trunk/; revision=58082
This commit is contained in:
Timo Kreuzer 2013-01-01 12:09:53 +00:00
parent 46da747829
commit 5b8a6dd3cc

View file

@ -21,53 +21,57 @@
#include <win32k.h> #include <win32k.h>
/* INT
* FIXME: Is there a better algorithm, like FT_MulDiv? APIENTRY
* EngMulDiv(
* @implemented _In_ INT iMultiplicand,
*/ _In_ INT iMultiplier,
INT APIENTRY EngMulDiv( _In_ INT iDivisor)
INT nMultiplicand,
INT nMultiplier,
INT nDivisor)
{ {
#if SIZEOF_LONG_LONG >= 8 INT64 i64Multiplied, i64Result;
long long ret;
if (!nDivisor) return -1; /* Check for divide by zero */
if (iDivisor == 0)
/* We want to deal with a positive divisor to simplify the logic. */
if (nDivisor < 0)
{ {
nMultiplicand = - nMultiplicand; /* Quick sign check and return "infinite" */
nDivisor = -nDivisor; return ((iMultiplicand ^ iMultiplier) < 0) ? INT_MIN : INT_MAX;
} }
/* If the result is positive, we "add" to round. else, we subtract to round. */ /* We want to deal with a positive divisor to simplify the logic. */
if ( ( (nMultiplicand < 0) && (nMultiplier < 0) ) || if (iDivisor < 0)
( (nMultiplicand >= 0) && (nMultiplier >= 0) ) ) {
ret = (((long long)nMultiplicand * nMultiplier) + (nDivisor/2)) / nDivisor; iMultiplicand = -iMultiplicand;
iDivisor = -iDivisor;
}
/* Do the multiplication */
i64Multiplied = Int32x32To64(iMultiplicand, iMultiplier);
/* If the result is positive, we add to round, else we subtract to round. */
if (i64Multiplied >= 0)
{
i64Multiplied += (iDivisor / 2);
}
else else
ret = (((long long)nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor;
if ((ret > 2147483647) || (ret < -2147483647)) return -1;
return ret;
#else
if (!nDivisor) return -1;
/* We want to deal with a positive divisor to simplify the logic. */
if (nDivisor < 0)
{ {
nMultiplicand = - nMultiplicand; i64Multiplied -= (iDivisor / 2);
nDivisor = -nDivisor;
} }
/* If the result is positive, we "add" to round. else, we subtract to round. */ /* Now do the divide */
if ( ( (nMultiplicand < 0) && (nMultiplier < 0) ) || i64Result = i64Multiplied / iDivisor;
( (nMultiplicand >= 0) && (nMultiplier >= 0) ) )
return ((nMultiplicand * nMultiplier) + (nDivisor/2)) / nDivisor;
return ((nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor; /* Check for positive overflow */
if (i64Result > INT_MAX)
{
return INT_MAX;
}
#endif /* Check for negative overflow. */
if (i64Result < INT_MIN)
{
return INT_MIN;
}
return (INT)i64Result;
} }