From b71077b2f6c107d9c7551257319317f4bbd7dbc7 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 2 May 2024 15:13:51 +0100 Subject: [PATCH] fix: threshold check in SD59x18 exp2 function --- src/sd59x18/Constants.sol | 4 ++++ src/sd59x18/Math.sol | 6 +++++- test/unit/sd59x18/math/exp2/exp2.t.sol | 10 +++++----- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/sd59x18/Constants.sol b/src/sd59x18/Constants.sol index 94d4603b..6d599ff9 100644 --- a/src/sd59x18/Constants.sol +++ b/src/sd59x18/Constants.sol @@ -16,6 +16,10 @@ SD59x18 constant EXP_MAX_INPUT = SD59x18.wrap(uEXP_MAX_INPUT); int256 constant uEXP2_MAX_INPUT = 192e18 - 1; SD59x18 constant EXP2_MAX_INPUT = SD59x18.wrap(uEXP2_MAX_INPUT); +/// @dev Any value less than this will return 0 in {exp2}. +int256 constant uEXP2_MIN_THRESHOLD = -59_794705707972522261; +SD59x18 constant EXP2_MIN_THRESHOLD = SD59x18.wrap(uEXP2_MIN_THRESHOLD); + /// @dev Half the UNIT number. int256 constant uHALF_UNIT = 0.5e18; SD59x18 constant HALF_UNIT = SD59x18.wrap(uHALF_UNIT); diff --git a/src/sd59x18/Math.sol b/src/sd59x18/Math.sol index 3fd3fa7b..978934eb 100644 --- a/src/sd59x18/Math.sol +++ b/src/sd59x18/Math.sol @@ -6,6 +6,7 @@ import "./Errors.sol" as Errors; import { uEXP_MAX_INPUT, uEXP2_MAX_INPUT, + uEXP2_MIN_THRESHOLD, uHALF_UNIT, uLOG2_10, uLOG2_E, @@ -172,6 +173,9 @@ function exp(SD59x18 x) pure returns (SD59x18 result) { if (xInt > uEXP_MAX_INPUT) { revert Errors.PRBMath_SD59x18_Exp_InputTooBig(x); } + if (xInt < uEXP2_MIN_THRESHOLD) { + return ZERO; + } unchecked { // Inline the fixed-point multiplication to save gas. @@ -202,7 +206,7 @@ function exp2(SD59x18 x) pure returns (SD59x18 result) { int256 xInt = x.unwrap(); if (xInt < 0) { // The inverse of any number less than this is truncated to zero. - if (xInt < -59_794705707972522261) { + if (xInt < uEXP2_MIN_THRESHOLD) { return ZERO; } diff --git a/test/unit/sd59x18/math/exp2/exp2.t.sol b/test/unit/sd59x18/math/exp2/exp2.t.sol index a79450c0..afaa2ab4 100644 --- a/test/unit/sd59x18/math/exp2/exp2.t.sol +++ b/test/unit/sd59x18/math/exp2/exp2.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.19 <0.9.0; import { sd } from "src/sd59x18/Casting.sol"; -import { E, EXP2_MAX_INPUT, MIN_SD59x18, MIN_WHOLE_SD59x18, PI, UNIT, ZERO } from "src/sd59x18/Constants.sol"; +import { E, EXP2_MAX_INPUT, MIN_SD59x18, MIN_WHOLE_SD59x18, PI, UNIT, ZERO, uEXP2_MIN_THRESHOLD, EXP2_MIN_THRESHOLD } from "src/sd59x18/Constants.sol"; import { PRBMath_SD59x18_Exp2_InputTooBig } from "src/sd59x18/Errors.sol"; import { exp2 } from "src/sd59x18/Math.sol"; import { SD59x18 } from "src/sd59x18/ValueType.sol"; @@ -10,8 +10,6 @@ import { SD59x18 } from "src/sd59x18/ValueType.sol"; import { SD59x18_Unit_Test } from "../../SD59x18.t.sol"; contract Exp2_Unit_Test is SD59x18_Unit_Test { - /// @dev Any input smaller than this makes the result zero. - SD59x18 internal constant THRESHOLD = SD59x18.wrap(-59_794705707972522261); function test_Exp2_Zero() external pure { SD59x18 x = ZERO; @@ -28,7 +26,7 @@ contract Exp2_Unit_Test is SD59x18_Unit_Test { delete sets; sets.push(set({ x: MIN_SD59x18, expected: 0 })); sets.push(set({ x: MIN_WHOLE_SD59x18, expected: 0 })); - sets.push(set({ x: THRESHOLD - sd(1), expected: 0 })); + sets.push(set({ x: EXP2_MIN_THRESHOLD - sd(1), expected: 0 })); return sets; } @@ -39,7 +37,9 @@ contract Exp2_Unit_Test is SD59x18_Unit_Test { function negativeAndGteMinPermitted_Sets() internal returns (Set[] memory) { delete sets; - sets.push(set({ x: THRESHOLD, expected: 0.000000000000000001e18 })); + sets.push(set({ x: EXP2_MIN_THRESHOLD, expected: 0.000000000000000001e18 })); + sets.push(set({ x: EXP2_MIN_THRESHOLD - sd(1), expected: 0 })); + sets.push(set({ x: -sd(2**255-1), expected: 0 })); sets.push(set({ x: -33.333333e18, expected: 0.000000000092398923e18 })); sets.push(set({ x: -20.82e18, expected: 0.000000540201132438e18 })); sets.push(set({ x: -16e18, expected: 0.0000152587890625e18 }));