Skip to content

Commit

Permalink
refactor: truncate instead of round up in "mulDiv18"
Browse files Browse the repository at this point in the history
test: update test to account for new truncating behavior
  • Loading branch information
PaulRBerg committed Nov 25, 2022
1 parent 977d43c commit 21fb327
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 42 deletions.
23 changes: 9 additions & 14 deletions src/Core.sol
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ function mulDiv(uint256 x, uint256 y, uint256 denominator) pure returns (uint256
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}

// Handle non-overflow cases, 256 by 256 division. "prod1 > 0 == false" is equivalent to "prod1 == 0" but faster.
if (prod1 > 0 == false) {
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
unchecked {
return prod0 / denominator;
}
Expand Down Expand Up @@ -205,28 +205,23 @@ function mulDiv18(uint256 x, uint256 y) pure returns (uint256 result) {
}

uint256 remainder;
uint256 roundUpUnit;
assembly {
remainder := mulmod(x, y, UNIT)
roundUpUnit := gt(remainder, 499999999999999999)
}

if (prod1 > 0 == false) {
if (prod1 == 0) {
unchecked {
return (prod0 / UNIT) + roundUpUnit;
return prod0 / UNIT;
}
}

assembly {
result := add(
mul(
or(
div(sub(prod0, remainder), UNIT_LPOTD),
mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, UNIT_LPOTD), UNIT_LPOTD), 1))
),
UNIT_INVERSE
result := mul(
or(
div(sub(prod0, remainder), UNIT_LPOTD),
mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, UNIT_LPOTD), UNIT_LPOTD), 1))
),
roundUpUnit
UNIT_INVERSE
)
}
}
Expand Down
32 changes: 24 additions & 8 deletions test/sd59x18/fixed-point/mul/mul.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,11 @@ contract SD59x18__MulTest is SD59x18__BaseTest {
set({ x: MIN_SD59x18.add(sd(0.5e18 + 1)), y: -0.000000000000000001e18, expected: MAX_SCALED_SD59x18 })
);
sets.push(
set({ x: MIN_WHOLE_SD59x18.add(sd(0.5e18)), y: -0.000000000000000001e18, expected: MAX_SCALED_SD59x18 })
set({
x: MIN_WHOLE_SD59x18.add(sd(0.5e18)),
y: -0.000000000000000001e18,
expected: MAX_SCALED_SD59x18.sub(sd(1))
})
);
sets.push(set({ x: -1e24, y: -1e20, expected: 1e26 }));
sets.push(set({ x: -12_983.989e18, y: -782.99e18, expected: 1_016_6333.54711e18 }));
Expand All @@ -117,9 +121,9 @@ contract SD59x18__MulTest is SD59x18__BaseTest {
sets.push(set({ x: -0.00001e18, y: -0.00001e18, expected: 0.0000000001e18 }));
sets.push(set({ x: -0.000000001e18, y: -0.000000001e18, expected: 0.000000000000000001e18 }));
sets.push(set({ x: -0.000000000000000001e18, y: -0.000000000000000001e18, expected: 0 }));
sets.push(set({ x: -0.000000000000000006e18, y: -0.1e18, expected: 0.000000000000000001e18 }));
sets.push(set({ x: -0.000000000000000006e18, y: -0.1e18, expected: 0 }));
sets.push(set({ x: 0.000000000000000001e18, y: 0.000000000000000001e18, expected: 0 }));
sets.push(set({ x: 0.000000000000000006e18, y: 0.1e18, expected: 0.000000000000000001e18 }));
sets.push(set({ x: 0.000000000000000006e18, y: 0.1e18, expected: 0 }));
sets.push(set({ x: 0.000000001e18, y: 0.000000001e18, expected: 0.000000000000000001e18 }));
sets.push(set({ x: 0.00001e18, y: 0.00001e18, expected: 0.0000000001e18 }));
sets.push(set({ x: 0.001e18, y: 0.01e18, expected: 0.00001e18 }));
Expand All @@ -133,7 +137,11 @@ contract SD59x18__MulTest is SD59x18__BaseTest {
sets.push(set({ x: 12_983.989e18, y: 782.99e18, expected: 1_016_6333.54711e18 }));
sets.push(set({ x: 1e24, y: 1e20, expected: 1e26 }));
sets.push(
set({ x: MAX_WHOLE_SD59x18.sub(sd(0.5e18)), y: 0.000000000000000001e18, expected: MAX_SCALED_SD59x18 })
set({
x: MAX_WHOLE_SD59x18.sub(sd(0.5e18)),
y: 0.000000000000000001e18,
expected: MAX_SCALED_SD59x18.sub(sd(1))
})
);
sets.push(set({ x: MAX_SD59x18.sub(sd(0.5e18)), y: 0.000000000000000001e18, expected: MAX_SCALED_SD59x18 }));
return sets;
Expand All @@ -157,7 +165,11 @@ contract SD59x18__MulTest is SD59x18__BaseTest {
set({ x: MIN_SD59x18.add(sd(0.5e18 + 1)), y: 0.000000000000000001e18, expected: MIN_SCALED_SD59x18 })
);
sets.push(
set({ x: MIN_WHOLE_SD59x18.add(sd(0.5e18)), y: 0.000000000000000001e18, expected: MIN_SCALED_SD59x18 })
set({
x: MIN_WHOLE_SD59x18.add(sd(0.5e18)),
y: 0.000000000000000001e18,
expected: MIN_SCALED_SD59x18.add(sd(1))
})
);
sets.push(set({ x: -1e24, y: 1e20, expected: -1e26 }));
sets.push(set({ x: -12_983.989e18, y: 782.99e18, expected: -1_016_6333.54711e18 }));
Expand All @@ -172,9 +184,9 @@ contract SD59x18__MulTest is SD59x18__BaseTest {
sets.push(set({ x: -0.00001e18, y: 0.00001e18, expected: -0.0000000001e18 }));
sets.push(set({ x: -0.000000001e18, y: 0.000000001e18, expected: -0.000000000000000001e18 }));
sets.push(set({ x: -0.000000000000000001e18, y: 0.000000000000000001e18, expected: 0 }));
sets.push(set({ x: -0.000000000000000006e18, y: 0.1e18, expected: -0.000000000000000001e18 }));
sets.push(set({ x: -0.000000000000000006e18, y: 0.1e18, expected: 0 }));
sets.push(set({ x: 0.000000000000000001e18, y: -0.000000000000000001e18, expected: 0 }));
sets.push(set({ x: 0.000000000000000006e18, y: -0.1e18, expected: -0.000000000000000001e18 }));
sets.push(set({ x: 0.000000000000000006e18, y: -0.1e18, expected: 0 }));
sets.push(set({ x: 0.000000001e18, y: -0.000000001e18, expected: -0.000000000000000001e18 }));
sets.push(set({ x: 0.00001e18, y: -0.00001e18, expected: -0.0000000001e18 }));
sets.push(set({ x: 0.001e18, y: -0.01e18, expected: -0.00001e18 }));
Expand All @@ -188,7 +200,11 @@ contract SD59x18__MulTest is SD59x18__BaseTest {
sets.push(set({ x: 12_983.989e18, y: -782.99e18, expected: -1_016_6333.54711e18 }));
sets.push(set({ x: 1e24, y: -1e20, expected: -1e26 }));
sets.push(
set({ x: MAX_WHOLE_SD59x18.sub(sd(0.5e18)), y: -0.000000000000000001e18, expected: MIN_SCALED_SD59x18 })
set({
x: MAX_WHOLE_SD59x18.sub(sd(0.5e18)),
y: -0.000000000000000001e18,
expected: MIN_SCALED_SD59x18.add(sd(1))
})
);
sets.push(set({ x: MAX_SD59x18.sub(sd(0.5e18)), y: -0.000000000000000001e18, expected: MIN_SCALED_SD59x18 }));
return sets;
Expand Down
12 changes: 6 additions & 6 deletions test/sd59x18/fixed-point/pow/pow.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ contract SD59x18__PowTest is SD59x18__BaseTest {

function negativeExponentSets() internal returns (Set[] memory) {
delete sets;
sets.push(set({ x: 0.000000000000000001e18, y: -0.000000000000000001e18, expected: 1e18 + 41 }));
sets.push(set({ x: 0.000000000000000001e18, y: -0.000000000000000001e18, expected: 1e18 + 40 }));
sets.push(set({ x: 0.000000000001e18, y: -4.4e9, expected: 1_000000121576500300 }));
sets.push(set({ x: 0.1e18, y: -0.8e18, expected: 6_309573444801932444 }));
sets.push(set({ x: 0.24e18, y: -11e18, expected: 6571678_991286039528731186 }));
Expand Down Expand Up @@ -139,7 +139,7 @@ contract SD59x18__PowTest is SD59x18__BaseTest {

function positiveExponentSets() internal returns (Set[] memory) {
delete sets;
sets.push(set({ x: 0.000000000000000001e18, y: 0.000000000000000001e18, expected: 0.999999999999999959e18 }));
sets.push(set({ x: 0.000000000000000001e18, y: 0.000000000000000001e18, expected: 0.999999999999999960e18 }));
sets.push(set({ x: 1e6, y: 4.4e9, expected: 0.99999987842351448e18 }));
sets.push(set({ x: 0.1e18, y: 0.8e18, expected: 0.158489319246111349e18 }));
sets.push(set({ x: 0.24e18, y: 11e18, expected: 0.000000152168114316e18 }));
Expand All @@ -148,10 +148,10 @@ contract SD59x18__PowTest is SD59x18__BaseTest {
sets.push(set({ x: 1e18, y: 2e18, expected: 1e18 }));
sets.push(set({ x: 1e18, y: PI, expected: 1e18 }));
sets.push(set({ x: 2e18, y: 1.5e18, expected: 2_828427124746190097 }));
sets.push(set({ x: E, y: E, expected: 15_154262241479263804 }));
sets.push(set({ x: E, y: 1.66976e18, expected: 5_310893029888037563 }));
sets.push(set({ x: E, y: E, expected: 15_154262241479263793 }));
sets.push(set({ x: E, y: 1.66976e18, expected: 5_310893029888037560 }));
sets.push(set({ x: PI, y: PI, expected: 36_462159607207910473 }));
sets.push(set({ x: 11e18, y: 28.5e18, expected: 478290249106383504726311660571_903531944106436935 }));
sets.push(set({ x: 11e18, y: 28.5e18, expected: 478290249106383504389245497918_050372801213485439 }));
sets.push(
set({ x: 32.15e18, y: 23.99e18, expected: 1436387590627448555101723413293079116_943375472179194989 })
);
Expand All @@ -162,7 +162,7 @@ contract SD59x18__PowTest is SD59x18__BaseTest {
set({
x: 340282366920938463463374607431768211455e18,
y: 1e18 + 1,
expected: 340282366920938487979097481391762860220_000000000004665573
expected: 340282366920938487757736552507248225013_000000000004316573
})
);
sets.push(
Expand Down
12 changes: 6 additions & 6 deletions test/sd59x18/fixed-point/powu/powu.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ contract SD59x18__PowuTest is SD59x18__BaseTest {
set({
x: -38685626227668133590.597631999999999999e18,
y: 3,
expected: -57896044618658097711785492504343953922145259302939748255014_626107971862774100
expected: -57896044618658097711785492504343953922145259302939748254975_940481744194640509
})
);
sets.push(set({ x: -1e24, y: 3, expected: -1e36 }));
Expand All @@ -119,9 +119,9 @@ contract SD59x18__PowuTest is SD59x18__BaseTest {
})
);
sets.push(set({ x: -100e18, y: 4, expected: 1e26 }));
sets.push(set({ x: -5.491e18, y: 19, expected: -113077820843204_476043049664958629 }));
sets.push(set({ x: -5.491e18, y: 19, expected: -113077820843204_476043049664958463 }));
sets.push(set({ x: NEGATIVE_E, y: 2, expected: 7_389056098930650225 }));
sets.push(set({ x: NEGATIVE_PI, y: 3, expected: -31_006276680299820162 }));
sets.push(set({ x: NEGATIVE_PI, y: 3, expected: -31_006276680299820158 }));
sets.push(set({ x: -2e18, y: 100, expected: 1267650600228_229401496703205376e18 }));
sets.push(set({ x: -2e18, y: 5, expected: -32e18 }));
sets.push(set({ x: -1e18, y: 1, expected: -1e18 }));
Expand Down Expand Up @@ -150,8 +150,8 @@ contract SD59x18__PowuTest is SD59x18__BaseTest {
sets.push(set({ x: 2e18, y: 5, expected: 32e18 }));
sets.push(set({ x: 2e18, y: 100, expected: 1267650600228_229401496703205376e18 }));
sets.push(set({ x: E, y: 2, expected: 7_389056098930650225 }));
sets.push(set({ x: PI, y: 3, expected: 31_006276680299820162 }));
sets.push(set({ x: 5.491e18, y: 19, expected: 113077820843204_476043049664958629 }));
sets.push(set({ x: PI, y: 3, expected: 31_006276680299820158 }));
sets.push(set({ x: 5.491e18, y: 19, expected: 113077820843204_476043049664958463 }));
sets.push(set({ x: 100e18, y: 4, expected: 1e26 }));
sets.push(
set({
Expand All @@ -166,7 +166,7 @@ contract SD59x18__PowuTest is SD59x18__BaseTest {
set({
x: 38685626227668133590.597631999999999999e18,
y: 3,
expected: 57896044618658097711785492504343953922145259302939748255014_626107971862774100
expected: 57896044618658097711785492504343953922145259302939748254975_940481744194640509
})
);
sets.push(
Expand Down
2 changes: 1 addition & 1 deletion test/ud60x18/fixed-point/mul/mul.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ contract UD60x18__MulTest is UD60x18__BaseTest {
function mulSets() internal returns (Set[] memory) {
delete sets;
sets.push(set({ x: 0.000000000000000001e18, y: 0.000000000000000001e18, expected: 0 }));
sets.push(set({ x: 0.000000000000000006e18, y: 0.1e18, expected: 0.000000000000000001e18 }));
sets.push(set({ x: 0.000000000000000006e18, y: 0.1e18, expected: 0 }));
sets.push(set({ x: 0.000000001e18, y: 0.000000001e18, expected: 0.000000000000000001e18 }));
sets.push(set({ x: 0.00001e18, y: 0.00001e18, expected: 0.0000000001e18 }));
sets.push(set({ x: 0.001e18, y: 0.01e18, expected: 0.00001e18 }));
Expand Down
8 changes: 4 additions & 4 deletions test/ud60x18/fixed-point/pow/pow.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,10 @@ contract UD60x18__PowTest is UD60x18__BaseTest {
sets.push(set({ x: 1e18, y: 2e18, expected: 1e18 }));
sets.push(set({ x: 1e18, y: PI, expected: 1e18 }));
sets.push(set({ x: 2e18, y: 1.5e18, expected: 2_828427124746190097 }));
sets.push(set({ x: E, y: 1.66976e18, expected: 5_310893029888037563 }));
sets.push(set({ x: E, y: E, expected: 15_154262241479263804 }));
sets.push(set({ x: E, y: 1.66976e18, expected: 5_310893029888037560 }));
sets.push(set({ x: E, y: E, expected: 15_154262241479263793 }));
sets.push(set({ x: PI, y: PI, expected: 36_462159607207910473 }));
sets.push(set({ x: 11e18, y: 28.5e18, expected: 478290249106383504726311660571_903531944106436935 }));
sets.push(set({ x: 11e18, y: 28.5e18, expected: 478290249106383504389245497918_050372801213485439 }));
sets.push(
set({ x: 32.15e18, y: 23.99e18, expected: 1436387590627448555101723413293079116_943375472179194989 })
);
Expand All @@ -125,7 +125,7 @@ contract UD60x18__PowTest is UD60x18__BaseTest {
set({
x: 340282366920938463463374607431768211455e18,
y: 1e18 + 1,
expected: 340282366920938487979097481391762860220_000000000004665573
expected: 340282366920938487757736552507248225013_000000000004316573
})
);
sets.push(
Expand Down
6 changes: 3 additions & 3 deletions test/ud60x18/fixed-point/powu/powu.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ contract UD60x18__PowuTest is UD60x18__BaseTest {
sets.push(set({ x: 2e18, y: 5, expected: 32e18 }));
sets.push(set({ x: 2e18, y: 100, expected: 1267650600228_229401496703205376e18 }));
sets.push(set({ x: E, y: 2, expected: 7_389056098930650225 }));
sets.push(set({ x: PI, y: 3, expected: 31_006276680299820162 }));
sets.push(set({ x: 5.491e18, y: 19, expected: 113077820843204_476043049664958629 }));
sets.push(set({ x: PI, y: 3, expected: 31_006276680299820158 }));
sets.push(set({ x: 5.491e18, y: 19, expected: 113077820843204_476043049664958463 }));
sets.push(set({ x: 100e18, y: 4, expected: 1e26 }));
sets.push(
set({
Expand All @@ -85,7 +85,7 @@ contract UD60x18__PowuTest is UD60x18__BaseTest {
set({
x: 38685626227668133590.597631999999999999e18,
y: 3,
expected: 57896044618658097711785492504343953922145259302939748255014_626107971862774100
expected: 57896044618658097711785492504343953922145259302939748254975_940481744194640509
})
);
sets.push(
Expand Down

0 comments on commit 21fb327

Please sign in to comment.