Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Threshold check #229

Merged
merged 5 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
test = "test"

[profile.ci]
fuzz = { runs = 10_000 }
fuzz = { runs = 10_000, max_test_rejects = 100_000 }
verbosity = 4

[fmt]
Expand Down
8 changes: 8 additions & 0 deletions src/sd59x18/Constants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,18 @@ SD59x18 constant E = SD59x18.wrap(2_718281828459045235);
int256 constant uEXP_MAX_INPUT = 133_084258667509499440;
SD59x18 constant EXP_MAX_INPUT = SD59x18.wrap(uEXP_MAX_INPUT);

/// @dev Any value less than this returns 0 in {exp}.
int256 constant uEXP_MIN_THRESHOLD = -41_446531673892822322;
SD59x18 constant EXP_MIN_THRESHOLD = SD59x18.wrap(uEXP_MIN_THRESHOLD);

/// @dev The maximum input permitted in {exp2}.
int256 constant uEXP2_MAX_INPUT = 192e18 - 1;
SD59x18 constant EXP2_MAX_INPUT = SD59x18.wrap(uEXP2_MAX_INPUT);

/// @dev Any value less than this returns 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);
Expand Down
12 changes: 10 additions & 2 deletions src/sd59x18/Math.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import "./Errors.sol" as Errors;
import {
uEXP_MAX_INPUT,
uEXP2_MAX_INPUT,
uEXP_MIN_THRESHOLD,
uEXP2_MIN_THRESHOLD,
uHALF_UNIT,
uLOG2_10,
uLOG2_E,
Expand Down Expand Up @@ -168,6 +170,12 @@ function div(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
function exp(SD59x18 x) pure returns (SD59x18 result) {
int256 xInt = x.unwrap();

// Any input less than the threshold returns zero.
// This check also prevents an overflow for very small numbers.
if (xInt < uEXP_MIN_THRESHOLD) {
return ZERO;
}

// This check prevents values greater than 192e18 from being passed to {exp2}.
if (xInt > uEXP_MAX_INPUT) {
revert Errors.PRBMath_SD59x18_Exp_InputTooBig(x);
Expand Down Expand Up @@ -201,8 +209,8 @@ function exp(SD59x18 x) pure returns (SD59x18 result) {
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) {
// The inverse of any number less than the threshold is truncated to zero.
if (xInt < uEXP2_MIN_THRESHOLD) {
return ZERO;
}

Expand Down
10 changes: 5 additions & 5 deletions test/unit/sd59x18/math/exp/exp.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@
pragma solidity >=0.8.19 <0.9.0;

import { sd } from "src/sd59x18/Casting.sol";
import { E, EXP_MAX_INPUT, MIN_SD59x18, MIN_WHOLE_SD59x18, PI, UNIT, ZERO } from "src/sd59x18/Constants.sol";
import { E, EXP_MAX_INPUT, EXP_MIN_THRESHOLD, MIN_SD59x18, MIN_WHOLE_SD59x18, PI, UNIT, ZERO } from "src/sd59x18/Constants.sol";
import { PRBMath_SD59x18_Exp_InputTooBig } from "src/sd59x18/Errors.sol";
import { exp } from "src/sd59x18/Math.sol";
import { SD59x18 } from "src/sd59x18/ValueType.sol";

import { SD59x18_Unit_Test } from "../../SD59x18.t.sol";

contract Exp_Unit_Test is SD59x18_Unit_Test {
SD59x18 internal constant THRESHOLD = SD59x18.wrap(-41_446531673892822322);

function test_Exp_Zero() external pure {
SD59x18 x = ZERO;
SD59x18 actual = exp(x);
Expand All @@ -27,7 +25,7 @@ contract Exp_Unit_Test is SD59x18_Unit_Test {
delete sets;
sets.push(set({ x: MIN_SD59x18 }));
sets.push(set({ x: MIN_WHOLE_SD59x18 }));
sets.push(set({ x: THRESHOLD - sd(1) }));
sets.push(set({ x: EXP_MIN_THRESHOLD - sd(1) }));
return sets;
}

Expand All @@ -38,7 +36,9 @@ contract Exp_Unit_Test is SD59x18_Unit_Test {

function negativeAndGteThreshold_Sets() internal returns (Set[] memory) {
delete sets;
sets.push(set({ x: THRESHOLD, expected: 0.000000000000000001e18 }));
sets.push(set({ x: MIN_SD59x18, expected: 0 }));
sets.push(set({ x: EXP_MIN_THRESHOLD - sd(1), expected: 0 }));
sets.push(set({ x: EXP_MIN_THRESHOLD, expected: 0.000000000000000001e18 }));
sets.push(set({ x: -33.333333e18, expected: 0.000000000000003338e18 }));
sets.push(set({ x: -20.82e18, expected: 0.0000000009077973e18 }));
sets.push(set({ x: -16e18, expected: 0.000000112535174719e18 }));
Expand Down
11 changes: 5 additions & 6 deletions test/unit/sd59x18/math/exp2/exp2.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@
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, EXP2_MIN_THRESHOLD, MIN_SD59x18, MIN_WHOLE_SD59x18, PI, UNIT, ZERO } 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";

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;
SD59x18 actual = exp2(x);
Expand All @@ -28,7 +25,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;
}

Expand All @@ -39,7 +36,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: MIN_SD59x18, expected: 0 }));
sets.push(set({ x: EXP2_MIN_THRESHOLD - sd(1), expected: 0 }));
sets.push(set({ x: EXP2_MIN_THRESHOLD, expected: 0.000000000000000001e18 }));
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 }));
Expand Down