[WIN32K]
authorTimo Kreuzer <timo.kreuzer@reactos.org>
Tue, 1 Jan 2013 12:09:53 +0000 (12:09 +0000)
committerTimo Kreuzer <timo.kreuzer@reactos.org>
Tue, 1 Jan 2013 12:09:53 +0000 (12:09 +0000)
Rewrite EngMulDiv.

svn path=/trunk/; revision=58082

reactos/win32ss/gdi/eng/math.c

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