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

Add UD21x18 and SD21x18 types #212

Merged
merged 5 commits into from
Jun 28, 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
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,14 +184,16 @@ the source code, which is well-documented with NatSpec comments.

### Adjacent Value Types

PRBMath provides adjacent value types that serve as abstractions over other vanilla types such as `int64`. The types currently available are:
PRBMath provides adjacent value types that serve as abstractions over other vanilla types:

| Value Type | Underlying Type |
| ---------- | --------------- |
| `SD1x18` | int64 |
| `SD21x18` | int128 |
| `UD2x18` | uint64 |
| `UD21x18` | uint128 |

These are useful if you want to save gas by using a lower bit width integer, e.g. in a struct.
These are useful if you want to save gas by using a lower bit width integer, e.g., in a struct.

Note that these types don't have any mathematical functionality. To do math with them, you will have to unwrap them into a simple integer and then to
the core types `SD59x18` and `UD60x18`.
Expand Down
3 changes: 3 additions & 0 deletions src/Common.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ uint128 constant MAX_UINT128 = type(uint128).max;
/// @dev The maximum value a uint40 number can have.
uint40 constant MAX_UINT40 = type(uint40).max;

/// @dev The maximum value a uint64 number can have.
uint64 constant MAX_UINT64 = type(uint64).max;

/// @dev The unit number, which the decimal precision of the fixed-point types.
uint256 constant UNIT = 1e18;

Expand Down
25 changes: 25 additions & 0 deletions src/SD21x18.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

/*

██████╗ ██████╗ ██████╗ ███╗ ███╗ █████╗ ████████╗██╗ ██╗
██╔══██╗██╔══██╗██╔══██╗████╗ ████║██╔══██╗╚══██╔══╝██║ ██║
██████╔╝██████╔╝██████╔╝██╔████╔██║███████║ ██║ ███████║
██╔═══╝ ██╔══██╗██╔══██╗██║╚██╔╝██║██╔══██║ ██║ ██╔══██║
██║ ██║ ██║██████╔╝██║ ╚═╝ ██║██║ ██║ ██║ ██║ ██║
╚═╝ ╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝

███████╗██████╗ ██████╗ ██╗██╗ ██╗ ██╗ █████╗
██╔════╝██╔══██╗╚════██╗███║╚██╗██╔╝███║██╔══██╗
███████╗██║ ██║ █████╔╝╚██║ ╚███╔╝ ╚██║╚█████╔╝
╚════██║██║ ██║██╔═══╝ ██║ ██╔██╗ ██║██╔══██╗
███████║██████╔╝███████╗ ██║██╔╝ ██╗ ██║╚█████╔╝
╚══════╝╚═════╝ ╚══════╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚════╝

*/

import "./sd21x18/Casting.sol";
import "./sd21x18/Constants.sol";
import "./sd21x18/Errors.sol";
import "./sd21x18/ValueType.sol";
25 changes: 25 additions & 0 deletions src/UD21x18.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

/*

██████╗ ██████╗ ██████╗ ███╗ ███╗ █████╗ ████████╗██╗ ██╗
██╔══██╗██╔══██╗██╔══██╗████╗ ████║██╔══██╗╚══██╔══╝██║ ██║
██████╔╝██████╔╝██████╔╝██╔████╔██║███████║ ██║ ███████║
██╔═══╝ ██╔══██╗██╔══██╗██║╚██╔╝██║██╔══██║ ██║ ██╔══██║
██║ ██║ ██║██████╔╝██║ ╚═╝ ██║██║ ██║ ██║ ██║ ██║
╚═╝ ╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝

██╗ ██╗██████╗ ██████╗ ██╗██╗ ██╗ ██╗ █████╗
██║ ██║██╔══██╗╚════██╗███║╚██╗██╔╝███║██╔══██╗
██║ ██║██║ ██║ █████╔╝╚██║ ╚███╔╝ ╚██║╚█████╔╝
██║ ██║██║ ██║██╔═══╝ ██║ ██╔██╗ ██║██╔══██╗
╚██████╔╝██████╔╝███████╗ ██║██╔╝ ██╗ ██║╚█████╔╝
╚═════╝ ╚═════╝ ╚══════╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚════╝

*/

import "./ud21x18/Casting.sol";
import "./ud21x18/Constants.sol";
import "./ud21x18/Errors.sol";
import "./ud21x18/ValueType.sol";
27 changes: 24 additions & 3 deletions src/casting/Uint128.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@ pragma solidity >=0.8.19;

import { uMAX_SD1x18 } from "../sd1x18/Constants.sol";
import { SD1x18 } from "../sd1x18/ValueType.sol";
import { uMAX_SD21x18 } from "../sd21x18/Constants.sol";
import { SD21x18 } from "../sd21x18/ValueType.sol";
import { SD59x18 } from "../sd59x18/ValueType.sol";
import { uMAX_UD2x18 } from "../ud2x18/Constants.sol";
import { UD2x18 } from "../ud2x18/ValueType.sol";
import { UD21x18 } from "../ud21x18/ValueType.sol";
import { UD60x18 } from "../ud60x18/ValueType.sol";

/// @notice Thrown when trying to cast a uint128 that doesn't fit in SD1x18.
error PRBMath_IntoSD1x18_Overflow(uint128 x);

/// @notice Thrown when trying to cast a uint128 that doesn't fit in SD21x18.
error PRBMath_IntoSD21x18_Overflow(uint128 x);

/// @notice Thrown when trying to cast a uint128 that doesn't fit in UD2x18.
error PRBMath_IntoUD2x18_Overflow(uint128 x);

Expand All @@ -19,14 +25,24 @@ error PRBMath_IntoUD2x18_Overflow(uint128 x);
library PRBMathCastingUint128 {
/// @notice Casts a uint128 number to SD1x18.
/// @dev Requirements:
/// - x must be less than or equal to `MAX_SD1x18`.
/// - x must be less than or equal to `uMAX_SD1x18`.
function intoSD1x18(uint128 x) internal pure returns (SD1x18 result) {
if (x > uint256(int256(uMAX_SD1x18))) {
revert PRBMath_IntoSD1x18_Overflow(x);
}
result = SD1x18.wrap(int64(uint64(x)));
}

/// @notice Casts a uint128 number to SD21x18.
/// @dev Requirements:
/// - x must be less than or equal to `uMAX_SD21x18`.
function intoSD21x18(uint128 x) internal pure returns (SD21x18 result) {
if (x > uint256(int256(uMAX_SD21x18))) {
revert PRBMath_IntoSD21x18_Overflow(x);
}
result = SD21x18.wrap(int128(x));
}

/// @notice Casts a uint128 number to SD59x18.
/// @dev There is no overflow check because the domain of uint128 is a subset of SD59x18.
function intoSD59x18(uint128 x) internal pure returns (SD59x18 result) {
Expand All @@ -35,17 +51,22 @@ library PRBMathCastingUint128 {

/// @notice Casts a uint128 number to UD2x18.
/// @dev Requirements:
/// - x must be less than or equal to `MAX_SD1x18`.
/// - x must be less than or equal to `uMAX_UD2x18`.
function intoUD2x18(uint128 x) internal pure returns (UD2x18 result) {
if (x > uint64(uMAX_UD2x18)) {
revert PRBMath_IntoUD2x18_Overflow(x);
}
result = UD2x18.wrap(uint64(x));
}

/// @notice Casts a uint128 number to UD21x18.
function intoUD21x18(uint128 x) internal pure returns (UD21x18 result) {
result = UD21x18.wrap(x);
}

/// @notice Casts a uint128 number to UD60x18.
/// @dev There is no overflow check because the domain of uint128 is a subset of UD60x18.
function intoUD60x18(uint128 x) internal pure returns (UD60x18 result) {
result = UD60x18.wrap(uint256(x));
result = UD60x18.wrap(x);
}
}
36 changes: 34 additions & 2 deletions src/casting/Uint256.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,57 @@ pragma solidity >=0.8.19;

import { uMAX_SD1x18 } from "../sd1x18/Constants.sol";
import { SD1x18 } from "../sd1x18/ValueType.sol";
import { uMAX_SD21x18 } from "../sd21x18/Constants.sol";
import { SD21x18 } from "../sd21x18/ValueType.sol";
import { uMAX_SD59x18 } from "../sd59x18/Constants.sol";
import { SD59x18 } from "../sd59x18/ValueType.sol";
import { uMAX_UD2x18 } from "../ud2x18/Constants.sol";
import { UD2x18 } from "../ud2x18/ValueType.sol";
import { uMAX_UD21x18 } from "../ud21x18/Constants.sol";
import { UD21x18 } from "../ud21x18/ValueType.sol";
import { UD60x18 } from "../ud60x18/ValueType.sol";

/// @notice Thrown when trying to cast a uint256 that doesn't fit in SD1x18.
error PRBMath_IntoSD1x18_Overflow(uint256 x);

/// @notice Thrown when trying to cast a uint256 that doesn't fit in SD21x18.
error PRBMath_IntoSD21x18_Overflow(uint256 x);

/// @notice Thrown when trying to cast a uint256 that doesn't fit in SD59x18.
error PRBMath_IntoSD59x18_Overflow(uint256 x);

/// @notice Thrown when trying to cast a uint256 that doesn't fit in UD2x18.
error PRBMath_IntoUD2x18_Overflow(uint256 x);

/// @notice Thrown when trying to cast a uint256 that doesn't fit in UD21x18.
error PRBMath_IntoUD21x18_Overflow(uint256 x);

/// @title PRBMathCastingUint256
/// @notice Casting utilities for uint256.
library PRBMathCastingUint256 {
/// @notice Casts a uint256 number to SD1x18.
/// @dev Requirements:
/// - x must be less than or equal to `MAX_SD1x18`.
/// - x must be less than or equal to `uMAX_SD1x18`.
function intoSD1x18(uint256 x) internal pure returns (SD1x18 result) {
if (x > uint256(int256(uMAX_SD1x18))) {
revert PRBMath_IntoSD1x18_Overflow(x);
}
result = SD1x18.wrap(int64(int256(x)));
}

/// @notice Casts a uint256 number to SD21x18.
/// @dev Requirements:
/// - x must be less than or equal to `uMAX_SD21x18`.
function intoSD21x18(uint256 x) internal pure returns (SD21x18 result) {
if (x > uint256(int256(uMAX_SD21x18))) {
revert PRBMath_IntoSD21x18_Overflow(x);
}
result = SD21x18.wrap(int128(int256(x)));
}

/// @notice Casts a uint256 number to SD59x18.
/// @dev Requirements:
/// - x must be less than or equal to `MAX_SD59x18`.
/// - x must be less than or equal to `uMAX_SD59x18`.
function intoSD59x18(uint256 x) internal pure returns (SD59x18 result) {
if (x > uint256(uMAX_SD59x18)) {
revert PRBMath_IntoSD59x18_Overflow(x);
Expand All @@ -42,13 +62,25 @@ library PRBMathCastingUint256 {
}

/// @notice Casts a uint256 number to UD2x18.
/// @dev Requirements:
/// - x must be less than or equal to `uMAX_UD2x18`.
function intoUD2x18(uint256 x) internal pure returns (UD2x18 result) {
if (x > uint256(uMAX_UD2x18)) {
revert PRBMath_IntoUD2x18_Overflow(x);
}
result = UD2x18.wrap(uint64(x));
}

/// @notice Casts a uint256 number to UD2x18.
/// @dev Requirements:
/// - x must be less than or equal to `uMAX_UD21x18`.
function intoUD21x18(uint256 x) internal pure returns (UD21x18 result) {
if (x > uint256(uMAX_UD21x18)) {
revert PRBMath_IntoUD21x18_Overflow(x);
}
result = UD21x18.wrap(uint128(x));
}

/// @notice Casts a uint256 number to UD60x18.
function intoUD60x18(uint256 x) internal pure returns (UD60x18 result) {
result = UD60x18.wrap(x);
Expand Down
18 changes: 16 additions & 2 deletions src/casting/Uint40.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
pragma solidity >=0.8.19;

import { SD1x18 } from "../sd1x18/ValueType.sol";
import { SD21x18 } from "../sd21x18/ValueType.sol";
import { SD59x18 } from "../sd59x18/ValueType.sol";
import { UD2x18 } from "../ud2x18/ValueType.sol";
import { UD21x18 } from "../ud21x18/ValueType.sol";
import { UD60x18 } from "../ud60x18/ValueType.sol";

/// @title PRBMathCastingUint40
Expand All @@ -15,6 +17,12 @@ library PRBMathCastingUint40 {
result = SD1x18.wrap(int64(uint64(x)));
}

/// @notice Casts a uint40 number into SD21x18.
/// @dev There is no overflow check because the domain of uint40 is a subset of SD21x18.
function intoSD21x18(uint40 x) internal pure returns (SD21x18 result) {
result = SD21x18.wrap(int128(uint128(x)));
}

/// @notice Casts a uint40 number into SD59x18.
/// @dev There is no overflow check because the domain of uint40 is a subset of SD59x18.
function intoSD59x18(uint40 x) internal pure returns (SD59x18 result) {
Expand All @@ -24,12 +32,18 @@ library PRBMathCastingUint40 {
/// @notice Casts a uint40 number into UD2x18.
/// @dev There is no overflow check because the domain of uint40 is a subset of UD2x18.
function intoUD2x18(uint40 x) internal pure returns (UD2x18 result) {
result = UD2x18.wrap(uint64(x));
result = UD2x18.wrap(x);
}

/// @notice Casts a uint40 number into UD21x18.
/// @dev There is no overflow check because the domain of uint40 is a subset of UD21x18.
function intoUD21x18(uint40 x) internal pure returns (UD21x18 result) {
result = UD21x18.wrap((x));
}

/// @notice Casts a uint40 number into UD60x18.
/// @dev There is no overflow check because the domain of uint40 is a subset of UD60x18.
function intoUD60x18(uint40 x) internal pure returns (UD60x18 result) {
result = UD60x18.wrap(uint256(x));
result = UD60x18.wrap(x);
}
}
34 changes: 26 additions & 8 deletions src/sd1x18/Casting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,19 @@ pragma solidity >=0.8.19;

import "../Common.sol" as Common;
import "./Errors.sol" as CastingErrors;
import { SD21x18 } from "../sd21x18/ValueType.sol";
import { SD59x18 } from "../sd59x18/ValueType.sol";
import { UD2x18 } from "../ud2x18/ValueType.sol";
import { UD21x18 } from "../ud21x18/ValueType.sol";
import { UD60x18 } from "../ud60x18/ValueType.sol";
import { SD1x18 } from "./ValueType.sol";

/// @notice Casts an SD1x18 number into SD21x18.
/// @dev There is no overflow check because the domain of SD1x18 is a subset of SD21x18.
function intoSD21x18(SD1x18 x) pure returns (SD21x18 result) {
result = SD21x18.wrap(int128(int256(SD1x18.unwrap(x))));
}

/// @notice Casts an SD1x18 number into SD59x18.
/// @dev There is no overflow check because the domain of SD1x18 is a subset of SD59x18.
function intoSD59x18(SD1x18 x) pure returns (SD59x18 result) {
Expand All @@ -24,6 +32,16 @@ function intoUD2x18(SD1x18 x) pure returns (UD2x18 result) {
result = UD2x18.wrap(uint64(xInt));
}

/// @notice Casts an SD1x18 number into UD21x18.
/// - x must be positive.
function intoUD21x18(SD1x18 x) pure returns (UD21x18 result) {
int64 xInt = SD1x18.unwrap(x);
if (xInt < 0) {
revert CastingErrors.PRBMath_SD1x18_ToUD21x18_Underflow(x);
}
result = UD21x18.wrap(uint128(uint64(xInt)));
}

/// @notice Casts an SD1x18 number into UD60x18.
/// @dev Requirements:
/// - x must be positive.
Expand All @@ -35,26 +53,26 @@ function intoUD60x18(SD1x18 x) pure returns (UD60x18 result) {
result = UD60x18.wrap(uint64(xInt));
}

/// @notice Casts an SD1x18 number into uint256.
/// @notice Casts an SD1x18 number into uint128.
/// @dev Requirements:
/// - x must be positive.
function intoUint256(SD1x18 x) pure returns (uint256 result) {
function intoUint128(SD1x18 x) pure returns (uint128 result) {
int64 xInt = SD1x18.unwrap(x);
if (xInt < 0) {
revert CastingErrors.PRBMath_SD1x18_ToUint256_Underflow(x);
revert CastingErrors.PRBMath_SD1x18_ToUint128_Underflow(x);
}
result = uint256(uint64(xInt));
result = uint128(uint64(xInt));
}

/// @notice Casts an SD1x18 number into uint128.
/// @notice Casts an SD1x18 number into uint256.
/// @dev Requirements:
/// - x must be positive.
function intoUint128(SD1x18 x) pure returns (uint128 result) {
function intoUint256(SD1x18 x) pure returns (uint256 result) {
int64 xInt = SD1x18.unwrap(x);
if (xInt < 0) {
revert CastingErrors.PRBMath_SD1x18_ToUint128_Underflow(x);
revert CastingErrors.PRBMath_SD1x18_ToUint256_Underflow(x);
}
result = uint128(uint64(xInt));
result = uint256(uint64(xInt));
}

/// @notice Casts an SD1x18 number into uint40.
Expand Down
2 changes: 1 addition & 1 deletion src/sd1x18/Constants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ SD1x18 constant E = SD1x18.wrap(2_718281828459045235);
int64 constant uMAX_SD1x18 = 9_223372036854775807;
SD1x18 constant MAX_SD1x18 = SD1x18.wrap(uMAX_SD1x18);

/// @dev The maximum value an SD1x18 number can have.
/// @dev The minimum value an SD1x18 number can have.
int64 constant uMIN_SD1x18 = -9_223372036854775808;
SD1x18 constant MIN_SD1x18 = SD1x18.wrap(uMIN_SD1x18);

Expand Down
15 changes: 9 additions & 6 deletions src/sd1x18/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@ pragma solidity >=0.8.19;

import { SD1x18 } from "./ValueType.sol";

/// @notice Thrown when trying to cast a SD1x18 number that doesn't fit in UD2x18.
/// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in UD2x18.
error PRBMath_SD1x18_ToUD2x18_Underflow(SD1x18 x);

/// @notice Thrown when trying to cast a SD1x18 number that doesn't fit in UD60x18.
/// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in UD21x18.
error PRBMath_SD1x18_ToUD21x18_Underflow(SD1x18 x);

/// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in UD60x18.
error PRBMath_SD1x18_ToUD60x18_Underflow(SD1x18 x);

/// @notice Thrown when trying to cast a SD1x18 number that doesn't fit in uint128.
/// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in uint128.
error PRBMath_SD1x18_ToUint128_Underflow(SD1x18 x);

/// @notice Thrown when trying to cast a SD1x18 number that doesn't fit in uint256.
/// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in uint256.
error PRBMath_SD1x18_ToUint256_Underflow(SD1x18 x);

/// @notice Thrown when trying to cast a SD1x18 number that doesn't fit in uint40.
/// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in uint40.
error PRBMath_SD1x18_ToUint40_Overflow(SD1x18 x);

/// @notice Thrown when trying to cast a SD1x18 number that doesn't fit in uint40.
/// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in uint40.
error PRBMath_SD1x18_ToUint40_Underflow(SD1x18 x);
Loading