Skip to content

Commit 977d43c

Browse files
committed
refactor: return base if exponent is 1 in "pow"
test: update "pow" tests to account for new behavior
1 parent 4d36587 commit 977d43c

6 files changed

Lines changed: 113 additions & 29 deletions

File tree

‎src/SD59x18.sol‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,11 @@ function pow(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
688688
if (x.isZero()) {
689689
result = y.isZero() ? UNIT : ZERO;
690690
} else {
691-
result = exp2(mul(log2(x), y));
691+
if (y.eq(UNIT)) {
692+
result = x;
693+
} else {
694+
result = exp2(log2(x).mul(y));
695+
}
692696
}
693697
}
694698

‎src/UD60x18.sol‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,11 @@ function pow(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
485485
if (x.isZero()) {
486486
result = y.isZero() ? UNIT : ZERO;
487487
} else {
488-
result = exp2(mul(log2(x), y));
488+
if (y.eq(UNIT)) {
489+
result = x;
490+
} else {
491+
result = exp2(mul(log2(x), y));
492+
}
489493
}
490494
}
491495

‎test/sd59x18/fixed-point/pow/pow.t.sol‎

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ contract SD59x18__PowTest is SD59x18__BaseTest {
3434

3535
function testCannotPow__BaseNegative() external BaseNotZero {
3636
SD59x18 x = sd(-0.000000000000000001e18);
37-
SD59x18 y = sd(1e18);
37+
SD59x18 y = sd(2e18);
3838
vm.expectRevert(abi.encodeWithSelector(PRBMathSD59x18__LogInputTooSmall.selector, x));
3939
pow(x, y);
4040
}
@@ -60,10 +60,39 @@ contract SD59x18__PowTest is SD59x18__BaseTest {
6060
_;
6161
}
6262

63-
function testCannotPow__ExponentGreaterThanMaxPermitted() external BaseNotZero BasePositive ExponentNotZero {
63+
function exponentOneSets() internal returns (Set[] memory) {
64+
delete sets;
65+
sets.push(set({ x: 1e18, y: 1e18, expected: 1e18 }));
66+
sets.push(set({ x: E, y: 1e18, expected: E }));
67+
sets.push(set({ x: PI, y: 1e18, expected: PI }));
68+
return sets;
69+
}
70+
71+
function testPow__ExponentOne()
72+
external
73+
parameterizedTest(exponentOneSets())
74+
BaseNotZero
75+
BasePositive
76+
ExponentNotZero
77+
{
78+
SD59x18 actual = pow(s.x, s.y);
79+
assertEq(actual, s.expected);
80+
}
81+
82+
modifier ExponentNotOne() {
83+
_;
84+
}
85+
86+
function testCannotPow__ExponentGreaterThanMaxPermitted()
87+
external
88+
BaseNotZero
89+
BasePositive
90+
ExponentNotZero
91+
ExponentNotOne
92+
{
6493
SD59x18 x = MAX_PERMITTED.add(sd(1));
65-
SD59x18 y = sd(1e18);
66-
vm.expectRevert(abi.encodeWithSelector(PRBMathSD59x18__Exp2InputTooBig.selector, sd(192e18)));
94+
SD59x18 y = sd(1e18 + 1);
95+
vm.expectRevert(abi.encodeWithSelector(PRBMathSD59x18__Exp2InputTooBig.selector, sd(192e18 + 192)));
6796
pow(x, y);
6897
}
6998

@@ -101,6 +130,7 @@ contract SD59x18__PowTest is SD59x18__BaseTest {
101130
BaseNotZero
102131
BasePositive
103132
ExponentNotZero
133+
ExponentNotOne
104134
ExponentLessThanOrEqualToMaxPermitted
105135
{
106136
SD59x18 actual = pow(s.x, s.y);
@@ -115,7 +145,7 @@ contract SD59x18__PowTest is SD59x18__BaseTest {
115145
sets.push(set({ x: 0.24e18, y: 11e18, expected: 0.000000152168114316e18 }));
116146
sets.push(set({ x: 0.5e18, y: 0.7373e18, expected: 0.59986094064056398e18 }));
117147
sets.push(set({ x: 0.799291e18, y: 69e18, expected: 0.000000193481602919e18 }));
118-
sets.push(set({ x: 1e18, y: 1e18, expected: 1e18 }));
148+
sets.push(set({ x: 1e18, y: 2e18, expected: 1e18 }));
119149
sets.push(set({ x: 1e18, y: PI, expected: 1e18 }));
120150
sets.push(set({ x: 2e18, y: 1.5e18, expected: 2_828427124746190097 }));
121151
sets.push(set({ x: E, y: E, expected: 15_154262241479263804 }));
@@ -131,12 +161,16 @@ contract SD59x18__PowTest is SD59x18__BaseTest {
131161
sets.push(
132162
set({
133163
x: 340282366920938463463374607431768211455e18,
134-
y: 1e18,
135-
expected: 340282366920938457799636748773271041925_182187238234989391
164+
y: 1e18 + 1,
165+
expected: 340282366920938487979097481391762860220_000000000004665573
136166
})
137167
);
138168
sets.push(
139-
set({ x: MAX_PERMITTED, y: 1e18, expected: 6277101735386680659358266643954607672760_949507286104301595e18 })
169+
set({
170+
x: MAX_PERMITTED,
171+
y: 1e18 - 1,
172+
expected: 6277101735386679823624773486129835356722228023657461399187e18
173+
})
140174
);
141175
return sets;
142176
}
@@ -147,6 +181,7 @@ contract SD59x18__PowTest is SD59x18__BaseTest {
147181
BaseNotZero
148182
BasePositive
149183
ExponentNotZero
184+
ExponentNotOne
150185
ExponentLessThanOrEqualToMaxPermitted
151186
{
152187
SD59x18 actual = pow(s.x, s.y);

‎test/sd59x18/fixed-point/pow/pow.tree‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@ pow.t.sol
1111
├── when the exponent is zero
1212
│ └── it should return one
1313
└── when the exponent is not zero
14-
├── when the exponent is greater than the maximum permitted
15-
│ └── it should revert
16-
└── when the exponent is less than or equal to the maximum permitted
17-
├── when the exponent is negative
18-
│ └── it should return the correct value
19-
└── when the exponent is positive
20-
└── it should return the correct value
14+
├── when the exponent is one
15+
│ └── it should return the base
16+
└── when the exponent is not one
17+
├── when the exponent is greater than the maximum permitted
18+
│ └── it should revert
19+
└── when the exponent is less than or equal to the maximum permitted
20+
├── when the exponent is negative
21+
│ └── it should return the correct value
22+
└── when the exponent is positive
23+
└── it should return the correct value

‎test/ud60x18/fixed-point/pow/pow.t.sol‎

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,40 @@ contract UD60x18__PowTest is UD60x18__BaseTest {
6565
_;
6666
}
6767

68-
function testCannotPow__ExponentGreaterThanOrEqualToMaxPermitted() external BaseNotZero ExponentNotZero {
68+
function exponentOneSets() internal returns (Set[] memory) {
69+
delete sets;
70+
sets.push(set({ x: 1e18, y: 1e18, expected: 1e18 }));
71+
sets.push(set({ x: E, y: 1e18, expected: E }));
72+
sets.push(set({ x: PI, y: 1e18, expected: PI }));
73+
return sets;
74+
}
75+
76+
function testPow__ExponentOne()
77+
external
78+
parameterizedTest(exponentOneSets())
79+
BaseNotZero
80+
BaseGreaterThanOrEqualToOne
81+
ExponentNotZero
82+
ExponentLessThanOrEqualToMaxPermitted
83+
{
84+
UD60x18 actual = pow(s.x, s.y);
85+
assertEq(actual, s.expected);
86+
}
87+
88+
modifier ExponentNotOne() {
89+
_;
90+
}
91+
92+
function testCannotPow__ExponentGreaterThanOrEqualToMaxPermitted()
93+
external
94+
BaseNotZero
95+
BaseGreaterThanOrEqualToOne
96+
ExponentNotZero
97+
ExponentNotOne
98+
{
6999
UD60x18 x = MAX_PERMITTED.add(ud(1));
70-
UD60x18 y = ud(1e18);
71-
vm.expectRevert(abi.encodeWithSelector(PRBMathUD60x18__Exp2InputTooBig.selector, ud(192e18)));
100+
UD60x18 y = ud(1e18 + 1);
101+
vm.expectRevert(abi.encodeWithSelector(PRBMathUD60x18__Exp2InputTooBig.selector, ud(192e18 + 192)));
72102
pow(x, y);
73103
}
74104

@@ -78,11 +108,11 @@ contract UD60x18__PowTest is UD60x18__BaseTest {
78108

79109
function powSets() internal returns (Set[] memory) {
80110
delete sets;
81-
sets.push(set({ x: 1e18, y: 1e18, expected: 1e18 }));
111+
sets.push(set({ x: 1e18, y: 2e18, expected: 1e18 }));
82112
sets.push(set({ x: 1e18, y: PI, expected: 1e18 }));
83113
sets.push(set({ x: 2e18, y: 1.5e18, expected: 2_828427124746190097 }));
84-
sets.push(set({ x: E, y: E, expected: 15_154262241479263804 }));
85114
sets.push(set({ x: E, y: 1.66976e18, expected: 5_310893029888037563 }));
115+
sets.push(set({ x: E, y: E, expected: 15_154262241479263804 }));
86116
sets.push(set({ x: PI, y: PI, expected: 36_462159607207910473 }));
87117
sets.push(set({ x: 11e18, y: 28.5e18, expected: 478290249106383504726311660571_903531944106436935 }));
88118
sets.push(
@@ -94,12 +124,16 @@ contract UD60x18__PowTest is UD60x18__BaseTest {
94124
sets.push(
95125
set({
96126
x: 340282366920938463463374607431768211455e18,
97-
y: 1e18,
98-
expected: 340282366920938457799636748773271041925_182187238234989391
127+
y: 1e18 + 1,
128+
expected: 340282366920938487979097481391762860220_000000000004665573
99129
})
100130
);
101131
sets.push(
102-
set({ x: MAX_PERMITTED, y: 1e18, expected: 6277101735386680659358266643954607672760_949507286104301595e18 })
132+
set({
133+
x: MAX_PERMITTED,
134+
y: 1e18 - 1,
135+
expected: 6277101735386679823624773486129835356722228023657461399187e18
136+
})
103137
);
104138
return sets;
105139
}
@@ -109,6 +143,7 @@ contract UD60x18__PowTest is UD60x18__BaseTest {
109143
parameterizedTest(powSets())
110144
BaseNotZero
111145
ExponentNotZero
146+
ExponentNotOne
112147
ExponentLessThanOrEqualToMaxPermitted
113148
{
114149
UD60x18 actual = pow(s.x, s.y);

‎test/ud60x18/fixed-point/pow/pow.tree‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ pow.t.sol
1111
├── when the exponent is zero
1212
│ └── it should return one
1313
└── when the exponent is not zero
14-
├── when the exponent is greater than the maximum permitted
15-
│ └── it should revert
16-
└── when the exponent is less than or equal to the maximum permitted
17-
└── it should return the correct value
14+
├── when the exponent is one
15+
│ └── it should return the base
16+
└── when the exponent is not one
17+
├── when the exponent is greater than the maximum permitted
18+
│ └── it should revert
19+
└── when the exponent is less than or equal to the maximum permitted
20+
└── it should return the correct value

0 commit comments

Comments
 (0)