PRBMath
Solidity library for advanced fixedpoint math that operates with signed 59.18decimal fixedpoint and unsigned 60.18decimal fixedpoint numbers. The name of the number format is due to the integer part having up to 59/60 decimals and the fractional part having up to 18 decimals. The numbers are bound by the minimum and the maximum values permitted by the Solidity types int256 and uint256.
 Operates with signed and unsigned denary fixedpoint numbers, with 18 trailing decimals
 Offers advanced math functions like logarithms, exponentials, powers and square roots
 Provides type safety via userdefined value types
 Gas efficient, but still userfriendly
 Ergonomic developer experience thanks to using free functions instead of libraries
 Bakes in overflowsafe multiplication and division via
mulDiv
 Reverts with custom errors instead of reason strings
 Welldocumented with NatSpec comments
 Built and tested with Foundry
I created this because I wanted a fixedpoint math library that is at the same time intuitive, efficient and safe. I looked at ABDKMath64x64, which is fast, but it uses binary numbers which are counterintuitive and nonfamiliar to humans. Then, I looked at Fixidity, which operates with denary numbers and has wide precision, but is slow and susceptible to phantom overflow. Finally, I looked at Solmate, which checks all the boxes mentioned thus far, but it doesn't offer type safety.
Install
All users are recommended to install PRBMath as a Node.js package:
pnpm add @prb/math
This example uses Pnpm, but using Yarn or Npm is also possible.
Foundry
If you're using Foundry, you have to add this to your remappings.txt
file:
@prb/math/=lib/prbmath/
Usage
There are two userdefined value types:
 SD59x18 (signed)
 UD60x18 (unsigned)
If you don't know what a userdefined value type is, check out this blog post.
If you don't need negative numbers, there's no point in using the signed flavor SD59x18
. The unsigned flavor UD60x18
is more gas efficient.
Note that PRBMath is not a library in the Solidity sense. It's just a collection of free functions.
Importing
It is recommended that you import PRBMath using specific symbols. Importing full files can result in Solidity complaining about duplicate definitions and static analyzers like Slither erroring, especially as repos grow and have more dependencies with overlapping names.
pragma solidity >=0.8.19;
import { SD59x18 } from "@prb/math/src/SD59x18.sol";
import { UD60x18 } from "@prb/math/src/UD60x18.sol";
Any function that is not available in the types directly has to be imported explicitly. Here's an example for the sd
and the ud
functions:
pragma solidity >=0.8.19;
import { SD59x18, sd } from "@prb/math/src/SD59x18.sol";
import { UD60x18, ud } from "@prb/math/src/UD60x18.sol";
Note that PRBMath can only be used in Solidity v0.8.19 and above.
SD59x18
// SPDXLicenseIdentifier: UNLICENSED
pragma solidity >=0.8.19;
import { SD59x18, sd } from "@prb/math/src/SD59x18.sol";
contract SignedConsumer {
/// @notice Calculates 5% of the given signed number.
/// @dev Try this with x = 400e18.
function signedPercentage(SD59x18 x) external pure returns (SD59x18 result) {
SD59x18 fivePercent = sd(0.05e18);
result = x.mul(fivePercent);
}
/// @notice Calculates the binary logarithm of the given signed number.
/// @dev Try this with x = 128e18.
function signedLog2(SD59x18 x) external pure returns (SD59x18 result) {
result = x.log2();
}
}
UD60x18
// SPDXLicenseIdentifier: UNLICENSED
pragma solidity >=0.8.19;
import { UD60x18, ud } from "@prb/math/src/UD60x18.sol";
contract UnsignedConsumer {
/// @notice Calculates 5% of the given signed number.
/// @dev Try this with x = 400e18.
function unsignedPercentage(UD60x18 x) external pure returns (UD60x18 result) {
UD60x18 fivePercent = ud(0.05e18);
result = x.mul(fivePercent);
}
/// @notice Calculates the binary logarithm of the given signed number.
/// @dev Try this with x = 128e18.
function unsignedLog2(UD60x18 x) external pure returns (UD60x18 result) {
result = x.log2();
}
}
Features
Because there's significant overlap between the features available in SD59x18 and UD60x18, there is only one table per section. If in doubt, refer to the source code, which is welldocumented with NatSpec comments.
Mathematical Functions
Name  Operator  Description 

abs 
N/A  Absolute value 
avg 
N/A  Arithmetic average 
ceil 
N/A  Smallest whole number greater than or equal to x 
div 
/ 
Fixedpoint division 
exp 
N/A  Natural exponential e^x 
exp2 
N/A  Binary exponential 2^x 
floor 
N/A  Greatest whole number less than or equal to x 
frac 
N/A  Fractional part 
gm 
N/A  Geometric mean 
inv 
N/A  Inverse 1÷x 
ln 
N/A  Natural logarithm ln(x) 
log10 
N/A  Common logarithm log10(x) 
log2 
N/A  Binary logarithm log2(x) 
mul 
* 
Fixedpoint multiplication 
pow 
N/A  Power function x^y 
powu 
N/A  Power function x^y with y simple integer 
sqrt 
N/A  Square root 
Adjacent Value Types
PRBMath provides adjacent value types that serve as abstractions over other vanilla types such as int64
. The types currently available are:
Value Type  Underlying Type 

SD1x18 
int64 
UD2x18 
uint64 
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
.
Casting Functions
All PRBMath types have casting functions to and from all other types, including a few basic types like uint128
and uint40
.
Name  Description 

intoSD1x18 
Casts a number to SD1x18 
intoSD59x18 
Casts a number to SD59x18 
intoUD2x18 
Casts a number to UD2x18 
intoUD60x18 
Casts a number to UD60x18 
intoUint256 
Casts a number to uint256 
intoUint128 
Casts a number to uint128 
intoUint40 
Casts a number to uint40 
sd1x18 
Alias for SD1x18.wrap

sd59x18 
Alias for SD59x18.wrap

ud2x18 
Alias for UD2x18.wrap

ud60x18 
Alias for UD60x18.wrap

Conversion Functions
The difference between "conversion" and "casting" is that conversion functions multiply or divide the inputs, whereas casting functions simply cast them.
Name  Description 

convert(SD59x18) 
Converts an SD59x18 number to a simple integer by dividing it by 1e18 
convert(UD60x18) 
Converts a UD60x18 number to a simple integer by dividing it by 1e18 
convert(int256) 
Converts a simple integer to SD59x18 by multiplying it by 1e18 
convert(uint256) 
Converts a simple integer to UD60x18 type by multiplying it by 1e18 
Helper Functions
In addition to offering mathematical, casting, and conversion functions, PRBMath provides numerous helper functions for userdefined value types:
Name  Operator  Description 

add 
+ 
Checked addition 
and 
& 
Logical AND 
eq 
== 
Equality 
gt 
> 
Greater than operator 
gte 
>= 
Greater than or equal to 
isZero 
N/A  Check if a number is zero 
lshift 
N/A  Bitwise left shift 
lt 
< 
Less than 
lte 
<= 
Less than or equal to 
mod 
% 
Modulo 
neq 
!= 
Not equal operator 
not 
~ 
Negation operator 
or 
 
Logical OR 
rshift 
N/A  Bitwise right shift 
sub 
 
Checked subtraction 
unary 
 
Checked unary 
uncheckedAdd 
N/A  Unchecked addition 
uncheckedSub 
N/A  Unchecked subtraction 
xor 
^ 
Exclusive or (XOR) 
These helpers are designed to streamline basic operations such as addition and equality checks, eliminating the need to constantly unwrap and rewrap variables. However, it is important to be aware that utilizing these functions may result in increased gas costs compared to unwrapping and directly using the vanilla types.
// SPDXLicenseIdentifier: UNLICENSED
pragma solidity >=0.8.19;
import { UD60x18, ud } from "@prb/math/src/UD60x18.sol";
function addRshiftEq() pure returns (bool result) {
UD60x18 x = ud(1e18);
UD60x18 y = ud(3e18);
y = y.add(x); // also: y = y + x
y = y.rshift(2);
result = x.eq(y); // also: y == x
}
Assertions
PRBMath comes with typed assertions that you can use for writing tests with PRBTest, which is based on Foundry. This is useful if, for example, you would like to assert that two UD60x18 numbers are equal.
pragma solidity >=0.8.19;
import { UD60x18, ud } from "@prb/math/src/UD60x18.sol";
import { Assertions as PRBMathAssertions } from "@prb/math/test/Assertions.sol";
import { PRBTest } from "@prb/math/src/test/PRBTest.sol";
contract MyTest is PRBTest, PRBMathAssertions {
function testAdd() external {
UD60x18 x = ud(1e18);
UD60x18 y = ud(2e18);
UD60x18 z = ud(3e18);
assertEq(x.add(y), z);
}
}
Gas Efficiency
PRBMath is faster than ABDKMath for abs
, exp
, exp2
, gm
, inv
, ln
, log2
, but it is slower than ABDKMath for avg
, div
, mul
, powu
and sqrt
.
The main reason why PRBMath lags behind ABDKMath's mul
and div
functions is that it operates with 256bit word sizes, and so it has to account for
possible intermediary overflow. ABDKMath, on the other hand, operates with 128bit word sizes.
Note: I did not find a good way to automatically generate gas reports for PRBMath. See the #134 discussion for more details about this issue.
PRBMath
Gas estimations based on the v2.0.1 and the v3.0.0 releases.
SD59x18  Min  Max  Avg  UD60x18  Min  Max  Avg  

abs  68  72  70  n/a  n/a  n/a  n/a  
avg  95  105  100  avg  57  57  57  
ceil  82  117  101  ceil  78  78  78  
div  431  483  451  div  205  205  205  
exp  38  2797  2263  exp  1874  2742  2244  
exp2  63  2678  2104  exp2  1784  2652  2156  
floor  82  117  101  floor  43  43  43  
frac  23  23  23  frac  23  23  23  
gm  26  892  690  gm  26  893  691  
inv  40  40  40  inv  40  40  40  
ln  463  7306  4724  ln  419  6902  3814  
log10  104  9074  4337  log10  503  8695  4571  
log2  377  7241  4243  log2  330  6825  3426  
mul  455  463  459  mul  219  275  247  
pow  64  11338  8518  pow  64  10637  6635  
powu  293  24745  5681  powu  83  24535  5471  
sqrt  140  839  716  sqrt  114  846  710 
ABDKMath64x64
Gas estimations based on the v3.0 release of ABDKMath. See my abdkgasestimations repo.
Method  Min  Max  Avg 

abs  88  92  90 
avg  41  41  41 
div  168  168  168 
exp  77  3780  2687 
exp2  77  3600  2746 
gavg  166  875  719 
inv  157  157  157 
ln  7074  7164  7126 
log2  6972  7062  7024 
mul  111  111  111 
pow  303  4740  1792 
sqrt  129  809  699 
Contributing
Feel free to dive in! Open an issue, start a discussion or submit a PR.
Pre Requisites
You will need the following software on your machine:
In addition, familiarity with Solidity is requisite.
Set Up
Clone this repository including submodules:
$ git clone recursesubmodules j8 git@github.com:PaulRBerg/prbmath.git
Then, inside the project's directory, run this to install the Node.js dependencies:
$ pnpm install
Now you can start making changes.
Syntax Highlighting
You will need the following VSCode extensions:
Security
While I set a high bar for code quality and test coverage, you should not assume that this project is completely safe to use. PRBMath has not yet been audited by a thirdparty security researcher.
Caveat Emptor
This is experimental software and is provided on an "as is" and "as available" basis. I do not give any warranties and will not be liable for any loss, direct or indirect through continued use of this codebase.
Contact
If you discover any bugs or security issues, please report them via Telegram.
Acknowledgments
 Mikhail Vladimirov for the insights he shared in the Math in Solidity article series.
 Remco Bloemen for his work on overflowsafe multiplication and division, and for responding to the questions I asked him while developing the library.
 Everyone who has contributed a PR to this repository.
License
This project is licensed under MIT.