Skip to content

Commit 294b04a

Browse files
test unabsUnsignedMulOrDivLossy
1 parent 1741771 commit 294b04a

2 files changed

Lines changed: 166 additions & 31 deletions

File tree

test/src/lib/implementation/LibDecimalFloatImplementation.mul.t.sol

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,21 @@ contract LibDecimalFloatImplementationMulTest is Test {
2626
assertEq(actualExponent, expectedExponent, "exponent");
2727
}
2828

29+
/// -1 * -1 = 1
30+
function testMulNegativeOne() external pure {
31+
checkMul(-1, 0, -1, 0, 1, 0);
32+
}
33+
34+
/// -1 * 1 = -1
35+
function testMulNegativeOneOne() external pure {
36+
checkMul(-1, 0, 1, 0, -1, 0);
37+
}
38+
39+
/// 1 * -1 = -1
40+
function testMulOneNegativeOne() external pure {
41+
checkMul(1, 0, -1, 0, -1, 0);
42+
}
43+
2944
/// found during testing
3045
/// 1.3979 * 0.5 = 0.69895
3146
/// represented as e76 and
@@ -36,59 +51,48 @@ contract LibDecimalFloatImplementationMulTest is Test {
3651
/// Simple 0 multiply 0
3752
/// 0 * 0 = 0
3853
function testMulZero0Exponent() external pure {
39-
(int256 signedCoefficient, int256 exponent) = LibDecimalFloatImplementation.mul(0, 0, 0, 0);
40-
assertEq(signedCoefficient, NORMALIZED_ZERO_SIGNED_COEFFICIENT);
41-
assertEq(exponent, NORMALIZED_ZERO_EXPONENT);
54+
checkMul(0, 0, 0, 0, 0, 0);
4255
}
4356

4457
/// 0 multiply 0 any exponent
4558
/// 0 * 0 = 0
4659
function testMulZeroAnyExponent(int64 exponentA, int64 exponentB) external pure {
47-
(int256 signedCoefficient, int256 exponent) = LibDecimalFloatImplementation.mul(0, exponentA, 0, exponentB);
48-
assertEq(signedCoefficient, NORMALIZED_ZERO_SIGNED_COEFFICIENT);
49-
assertEq(exponent, NORMALIZED_ZERO_EXPONENT);
60+
checkMul(0, exponentA, 0, exponentB, 0, 0);
5061
}
5162

5263
/// 0 multiply 1
5364
/// 0 * 1 = 0
5465
function testMulZeroOne() external pure {
55-
(int256 signedCoefficient, int256 exponent) = LibDecimalFloatImplementation.mul(0, 0, 1, 0);
56-
assertEq(signedCoefficient, NORMALIZED_ZERO_SIGNED_COEFFICIENT);
57-
assertEq(exponent, NORMALIZED_ZERO_EXPONENT);
66+
checkMul(0, 0, 1, 0, 0, 0);
5867
}
5968

6069
/// 1 multiply 0
6170
/// 1 * 0 = 0
6271
function testMulOneZero() external pure {
63-
(int256 signedCoefficient, int256 exponent) = LibDecimalFloatImplementation.mul(1, 0, 0, 0);
64-
assertEq(signedCoefficient, NORMALIZED_ZERO_SIGNED_COEFFICIENT);
65-
assertEq(exponent, NORMALIZED_ZERO_EXPONENT);
72+
checkMul(1, 0, 0, 0, 0, 0);
6673
}
6774

6875
/// 1 multiply 1
6976
/// 1 * 1 = 1
7077
function testMulOneOne() external pure {
71-
(int256 signedCoefficient, int256 exponent) = LibDecimalFloatImplementation.mul(1, 0, 1, 0);
72-
assertEq(signedCoefficient, 1);
73-
assertEq(exponent, 0);
78+
checkMul(1, 0, 1, 0, 1, 0);
7479
}
7580

7681
/// 123456789 multiply 987654321
7782
/// 123456789 * 987654321 = 121932631112635269
7883
function testMul123456789987654321() external pure {
79-
(int256 signedCoefficient, int256 exponent) = LibDecimalFloatImplementation.mul(123456789, 0, 987654321, 0);
80-
assertEq(signedCoefficient, 121932631112635269);
81-
assertEq(exponent, 0);
84+
checkMul(123456789, 0, 987654321, 0, 121932631112635269, 0);
8285
}
8386

8487
function testMulMaxSignedCoefficient() external pure {
85-
(int256 signedCoefficient, int256 exponent) =
86-
LibDecimalFloatImplementation.mul(type(int256).max, 0, type(int256).max, 0);
87-
// Numbers checked on desmos.
88-
assertEq(
89-
signedCoefficient, int256(3.3519519824856492748935062495514615318698414551480983444308903609304410075182e76)
88+
checkMul(
89+
type(int256).max,
90+
0,
91+
type(int256).max,
92+
0,
93+
int256(3.3519519824856492748935062495514615318698414551480983444308903609304410075182e76),
94+
77
9095
);
91-
assertEq(exponent, 77);
9296
}
9397

9498
/// 123456789 multiply 987654321 with exponents
@@ -97,17 +101,12 @@ contract LibDecimalFloatImplementationMulTest is Test {
97101
exponentA = int128(bound(exponentA, -127, 127));
98102
exponentB = int128(bound(exponentB, -127, 127));
99103

100-
(int256 signedCoefficient, int256 exponent) =
101-
LibDecimalFloatImplementation.mul(123456789, exponentA, 987654321, exponentB);
102-
assertEq(signedCoefficient, 121932631112635269);
103-
assertEq(exponent, exponentA + exponentB);
104+
checkMul(123456789, exponentA, 987654321, exponentB, 121932631112635269, exponentA + exponentB);
104105
}
105106

106107
/// 1e18 * 1e-19 = 1e-1
107108
function testMul1e181e19() external pure {
108-
(int256 signedCoefficient, int256 exponent) = LibDecimalFloatImplementation.mul(1, 18, 1, -19);
109-
assertEq(signedCoefficient, 1);
110-
assertEq(exponent, -1);
109+
checkMul(1, 18, 1, -19, 1, -1);
111110
}
112111

113112
function testMulGasZero() external pure {
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// SPDX-License-Identifier: CAL
2+
pragma solidity =0.8.25;
3+
4+
import {Test} from "forge-std/Test.sol";
5+
6+
import {LibDecimalFloatImplementation} from "src/lib/implementation/LibDecimalFloatImplementation.sol";
7+
8+
contract LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest is Test {
9+
/// a and b are both not negative.
10+
function testUnabsUnsignedMulOrDivLossyPositive(uint256 a, uint256 b, uint256 c, int256 exponent) external pure {
11+
a = bound(a, 0, uint256(type(int256).max));
12+
b = bound(b, 0, uint256(type(int256).max));
13+
c = bound(c, 0, uint256(type(int256).max));
14+
15+
(int256 actualSignedCoefficient, int256 actualExponent) =
16+
LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(int256(a), int256(b), c, exponent);
17+
18+
int256 expectedSignedCoefficient = int256(c);
19+
int256 expectedExponent = exponent;
20+
21+
assertEq(actualSignedCoefficient, expectedSignedCoefficient);
22+
assertEq(actualExponent, expectedExponent);
23+
}
24+
25+
/// a and b are both not negative, c overflows int256.
26+
function testUnabsUnsignedMulOrDivLossyPositiveOverflow(uint256 a, uint256 b, uint256 c, int256 exponent)
27+
external
28+
pure
29+
{
30+
a = bound(a, 0, uint256(type(int256).max));
31+
b = bound(b, 0, uint256(type(int256).max));
32+
c = bound(c, uint256(type(int256).max) + 1, type(uint256).max);
33+
vm.assume(exponent != type(int256).max); // Prevent overflow in exponent.
34+
35+
(int256 actualSignedCoefficient, int256 actualExponent) =
36+
LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(int256(a), int256(b), c, exponent);
37+
// Expect the result to be positive.
38+
int256 expectedSignedCoefficient = int256(c / 10);
39+
int256 expectedExponent = exponent + 1;
40+
assertEq(actualSignedCoefficient, expectedSignedCoefficient, "signed coefficient mismatch");
41+
assertEq(actualExponent, expectedExponent, "exponent mismatch");
42+
}
43+
44+
/// a and b are both negative.
45+
function testUnabsUnsignedMulOrDivLossyNegative(uint256 a, uint256 b, uint256 c, int256 exponent) external pure {
46+
a = bound(a, 1, uint256(type(int256).max));
47+
b = bound(b, 1, uint256(type(int256).max));
48+
c = bound(c, 0, uint256(type(int256).max));
49+
50+
(int256 actualSignedCoefficient, int256 actualExponent) =
51+
LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(-int256(a), -int256(b), c, exponent);
52+
53+
int256 expectedSignedCoefficient = int256(c);
54+
int256 expectedExponent = exponent;
55+
56+
assertEq(actualSignedCoefficient, expectedSignedCoefficient, "signed coefficient mismatch");
57+
assertEq(actualExponent, expectedExponent, "exponent mismatch");
58+
}
59+
60+
/// a and b are both negative, c overflows int256.
61+
function testUnabsUnsignedMulOrDivLossyNegativeOverflow(uint256 a, uint256 b, uint256 c, int256 exponent)
62+
external
63+
pure
64+
{
65+
a = bound(a, 1, uint256(type(int256).max));
66+
b = bound(b, 1, uint256(type(int256).max));
67+
c = bound(c, uint256(type(int256).max) + 1, type(uint256).max);
68+
vm.assume(exponent != type(int256).max); // Prevent overflow in exponent.
69+
70+
(int256 actualSignedCoefficient, int256 actualExponent) =
71+
LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(-int256(a), -int256(b), c, exponent);
72+
73+
// Expect the result to be negative.
74+
int256 expectedSignedCoefficient = int256(c / 10);
75+
int256 expectedExponent = exponent + 1;
76+
77+
assertEq(actualSignedCoefficient, expectedSignedCoefficient, "signed coefficient mismatch");
78+
assertEq(actualExponent, expectedExponent, "exponent mismatch");
79+
}
80+
81+
/// a is negative, b is positive.
82+
function testUnabsUnsignedMulOrDivLossyMixedAB(uint256 a, uint256 b, uint256 c, int256 exponent) external pure {
83+
a = bound(a, 1, uint256(type(int256).max));
84+
b = bound(b, 0, uint256(type(int256).max));
85+
c = bound(c, 0, uint256(type(int256).max));
86+
87+
(int256 actualSignedCoefficient, int256 actualExponent) =
88+
LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(-int256(a), int256(b), c, exponent);
89+
90+
// Expect the result to be negative.
91+
int256 expectedSignedCoefficient = -int256(c);
92+
int256 expectedExponent = exponent;
93+
94+
assertEq(actualSignedCoefficient, expectedSignedCoefficient, "signed coefficient mismatch");
95+
assertEq(actualExponent, expectedExponent, "exponent mismatch");
96+
}
97+
98+
/// a is positive, b is negative. c overflows int256.
99+
function testUnabsUnsignedMulOrDivLossyMixedBA(uint256 a, uint256 b, uint256 c, int256 exponent) external pure {
100+
a = bound(a, 0, uint256(type(int256).max));
101+
b = bound(b, 1, uint256(type(int256).max));
102+
c = bound(c, uint256(type(int256).max) + 2, type(uint256).max);
103+
vm.assume(exponent != type(int256).max); // Prevent overflow in exponent.
104+
105+
(int256 actualSignedCoefficient, int256 actualExponent) =
106+
LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(int256(a), -int256(b), c, exponent);
107+
108+
// Expect the result to be negative.
109+
int256 expectedSignedCoefficient = -int256(c / 10);
110+
int256 expectedExponent = exponent + 1;
111+
112+
assertEq(actualSignedCoefficient, expectedSignedCoefficient, "signed coefficient mismatch");
113+
assertEq(actualExponent, expectedExponent, "exponent mismatch");
114+
}
115+
116+
/// a is negative, b is positive, c overflows int256.
117+
function testUnabsUnsignedMulOrDivLossyMixedABOverflow(uint256 a, uint256 b, uint256 c, int256 exponent)
118+
external
119+
pure
120+
{
121+
a = bound(a, 1, uint256(type(int256).max));
122+
b = bound(b, 0, uint256(type(int256).max));
123+
c = bound(c, uint256(type(int256).max) + 2, type(uint256).max);
124+
vm.assume(exponent != type(int256).max); // Prevent overflow in exponent.
125+
126+
(int256 actualSignedCoefficient, int256 actualExponent) =
127+
LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(-int256(a), int256(b), c, exponent);
128+
129+
// Expect the result to be negative.
130+
int256 expectedSignedCoefficient = -int256(c / 10);
131+
int256 expectedExponent = exponent + 1;
132+
133+
assertEq(actualSignedCoefficient, expectedSignedCoefficient, "signed coefficient mismatch");
134+
assertEq(actualExponent, expectedExponent, "exponent mismatch");
135+
}
136+
}

0 commit comments

Comments
 (0)