From 92497d7df4b61ee62acfdd58bfb98569ff67214e Mon Sep 17 00:00:00 2001
From: Remco Bloemen <remco@wicked.ventures>
Date: Thu, 23 Aug 2018 11:01:52 -0700
Subject: Fix isRoundingError

---
 .../src/2.0.0/protocol/Exchange/libs/LibMath.sol   | 27 ++++++++++++++--------
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol
index fa09da6ac..146bb9943 100644
--- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol
+++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol
@@ -46,7 +46,7 @@ contract LibMath is
         return partialAmount;
     }
 
-    /// @dev Checks if rounding error > 0.1%.
+    /// @dev Checks if rounding error >= 0.1%.
     /// @param numerator Numerator.
     /// @param denominator Denominator.
     /// @param target Value to multiply with numerator/denominator.
@@ -60,16 +60,23 @@ contract LibMath is
         pure
         returns (bool isError)
     {
+        // The absolute rounding error is the difference between the rounded
+        // value and the ideal value. The relative rounding error is the
+        // absolute rounding error divided by the absolute value of the
+        // ideal value. We want the relative rounding error to be strictly less
+        // than 0.1%.
+        // Let's call `numerator * target % denominator` the remainder.
+        // The ideal value is `numerator * target / denominator`.
+        // The absolute error is `remainder / denominator`.
+        // The relative error is `remainder / numerator * target`.
+        // We want the relative error less than 1 / 1000:
+        //        remainder / numerator * denominator  <  1 / 1000
+        // or equivalently:
+        //        1000 * remainder  <  numerator * target
+        // so we have a rounding error iff:
+        //        1000 * remainder  >=  numerator * target
         uint256 remainder = mulmod(target, numerator, denominator);
-        if (remainder == 0) {
-            return false; // No rounding error.
-        }
-
-        uint256 errPercentageTimes1000000 = safeDiv(
-            safeMul(remainder, 1000000),
-            safeMul(numerator, target)
-        );
-        isError = errPercentageTimes1000000 > 1000;
+        isError = safeMul(1000, remainder) >= safeMul(numerator, target);
         return isError;
     }
 }
-- 
cgit v1.2.3