From 1c14948f8abcd0bbee3113d4d137565a03b0f329 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Fri, 31 May 2019 16:09:07 -0700 Subject: [PATCH] Saved 20k gas on cobb douglas computation w binary search --- .../staking/contracts/src/libs/LibMath.sol | 44 +++++++++++++------ 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/contracts/staking/contracts/src/libs/LibMath.sol b/contracts/staking/contracts/src/libs/LibMath.sol index 3edd2b13aa..82aca4ed52 100644 --- a/contracts/staking/contracts/src/libs/LibMath.sol +++ b/contracts/staking/contracts/src/libs/LibMath.sol @@ -27,16 +27,35 @@ library LibMath { function _nthRoot(uint256 base, uint256 n) internal pure returns (uint256 root) { assembly { ///// Implements Newton's Approximation, derived from Newton's nth Root Algorithm ///// - // See https://en.wikipedia.org/wiki/Nth_root#nth_root_algorithm + ///// See https://en.wikipedia.org/wiki/Nth_root#nth_root_algorithm + // 1. Find greatest power-of-2 <= `value` - let m := 0 - for {let v := base} - gt(v, 0) - {v := shr(1, v)} + let nearestPowerOf2 := 0x80000000000000000000000000000000 + let m := 128 + for {let p := 64} + gt(p, 0) + { p := div(p, 2) } { - m := add(m, 1) + switch gt(nearestPowerOf2, base) + case 0 { + switch lt(nearestPowerOf2, base) + case 0 { + p := 0 + } + case 1 { + nearestPowerOf2 := shl(p, nearestPowerOf2) + m := add(m, p) + } + } + case 1 { + nearestPowerOf2 := shr(p, nearestPowerOf2) + m := sub(m, p) + } + } + if gt(nearestPowerOf2, base) { + nearestPowerOf2 := shr(1, nearestPowerOf2) + m := sub(m, 1) } - m := sub(m, 1) // 2. Find greatest power-of-2 that, when raised to the power of `n`, // is <= `value` @@ -48,6 +67,7 @@ library LibMath { // 4. Run Newton's Approximation to approximate the root root := add(x, div(y, mul(n, exp(2, mul(div(m, n), sub(n, 1)))))) + /** * Note 1: * On some clients (like ganache), execution freezes when running exponentiation @@ -69,6 +89,7 @@ library LibMath { * } */ + // ganache core workaround (issue #430) function exp2(b,p) -> z { z := b for {p := sub(p, 1)} @@ -85,12 +106,8 @@ library LibMath { and(lt(i, 20), gt(delta, 0)) {i := add(i,1)} { - let lhsDenominator := - exp2( - root, - sub(n, 1) - ) - + // compute lhs + let lhsDenominator := exp2(root, sub(n, 1)) let lhs := div(base, lhsDenominator) // check for overlow @@ -108,6 +125,7 @@ library LibMath { } } } + function _nthRootFixedPoint( uint256 base, uint256 n,