| BL19 | BL127 | ABDKMathQuad | PRBMath SD59x18 | Solady | |
|---|---|---|---|---|---|
| digits | 71 | 38 | 34 | 18 | 18 |
| add | 662 | 128 | 734 | 189 | 3 |
| mul | 530 | 267 | 709 | 485 | 126 |
| div | 800 | 413 | 818 | 509 | 93 |
| exp t | 3,278 | 2,835 | 5,668 | 2,816 | 430 |
| ln t | 3,106 | 1,944 | 16,356 | 7,083 | 556 |
| pow t | 5,964 | 3,317 | 23,479 | 10,065 | 1,279 |
| sqrt t | 1,205 | 469 | 760 | 978 | 393 |
Inline library, median gas per call, over random inputs that take no shortcut for the ops marked t and over the input ladder for the rest; digits are precision at 1. BL19 is cheaper than Quad on add, mul, div, exp, ln and pow, not on sqrt. BL127 is cheaper than PRBMath on add, mul, div, ln, pow and sqrt, not on exp. Solady is cheaper than both on every op here, at 18 digits; its add is the unchecked rawAdd. Sources: bl19/gas.json (BL19, Quad), gas.json (the rest).
Only BL19 and BL127 offer erf, erfc, normCdf and both Lambert W branches (Solady has W₀ alone), each correctly rounded or the nearest word. BL19's per-op detail, with the deployed objects, is on its page.
Gas per op
Every op of BL19 and BL127 against every library we compare, all called inline.
| op | BL19 | BL127 | ABDKMathQuad | PRBMath | Solady | ABDK 64.64 | Balancer | Solmate | PRB UD60x18 | snekmate | OpenZeppelin | Uniswap |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| abs | 133 | 140 | 21 | 121 | 18 | 120 | 18 | |||||
| add | 662 | 128 | 734 | 189 | 3 | 162 | 150 | |||||
| atanh t | 3,882 | 2,944 | ||||||||||
| avg | 663 | 114 | 154 | 60 | 31 | 105 | 113 | 318 | ||||
| cbrt t | 2,734 | 1,936 | 619 | 2,313 | 1,424 | |||||||
| ceil | 523 | 147 | 201 | 117 | ||||||||
| clamp | 491 | 241 | 49 | |||||||||
| cmp | 248 | 476 | ||||||||||
| compound t | 5,858 | 3,078 | ||||||||||
| cosh t | 3,692 | 4,073 | ||||||||||
| dist | 819 | 289 | 32 | |||||||||
| div | 800 | 413 | 818 | 509 | 93 | 221 | 97 | 261 | ||||
| divDown | 987 | 476 | 87 | 150 | 323 | 239 | 179 | |||||
| divUp | 988 | 479 | 113 | 176 | 386 | 621 | 282 | |||||
| eq | 176 | 108 | ||||||||||
| erf t | 10,624 | 7,559 | ||||||||||
| erfc t | 10,654 | 7,186 | ||||||||||
| exp t | 3,278 | 2,835 | 5,668 | 2,816 | 430 | 3,380 | 1,040 | 430 | 2,720 | 604 | ||
| exp10 t | 3,177 | 3,081 | ||||||||||
| exp2 t | 3,096 | 2,712 | 5,031 | 2,671 | 3,225 | 2,557 | ||||||
| expm1 t | 2,395 | 2,996 | ||||||||||
| factorial | 719 | 400 | 579 | |||||||||
| floor | 522 | 72 | 201 | 28 | ||||||||
| frac | 428 | 69 | 125 | 8 | ||||||||
| fromBL127 | 440 | 539 | ||||||||||
| fromFixed18 | 554 | 140 | ||||||||||
| fromUint | 413 | |||||||||||
| fromUintDown | 487 | 500 | ||||||||||
| fromUintUp | 488 | |||||||||||
| gavg t | 2,099 | 1,003 | 960 | 449 | 833 | 949 | ||||||
| hypot t | 3,556 | 1,164 | ||||||||||
| inv | 747 | 242 | 1,253 | 177 | 93 | 202 | 94 | |||||
| lambertW0 t | 10,672 | 8,304 | 3,045 | |||||||||
| lambertWm1 t | 10,759 | 8,156 | ||||||||||
| lerp t | 6,515 | 477 | 282 | |||||||||
| ln t | 3,106 | 1,944 | 16,356 | 7,083 | 556 | 7,080 | 1,091 | 632 | 6,474 | 1,226 | ||
| log10 t | 3,101 | 1,934 | 8,618 | 1,895 | 8,233 | |||||||
| log1p t | 2,587 | 2,064 | ||||||||||
| log2 t | 2,885 | 1,723 | 15,553 | 6,724 | 6,990 | 1,914 | 6,402 | |||||
| log2Up | 679 | 209 | 247 | 505 | 513 | |||||||
| lt | 233 | 488 | ||||||||||
| max | 250 | 125 | 23 | 86 | ||||||||
| min | 251 | 126 | 23 | 86 | ||||||||
| mul | 530 | 267 | 709 | 485 | 126 | 171 | 131 | 237 | ||||
| mulDown | 727 | 315 | 86 | 150 | 323 | 239 | 179 | |||||
| mulUp | 728 | 337 | 110 | 176 | 386 | 621 | 282 | |||||
| neg | 127 | 116 | 9 | 134 | 76 | |||||||
| normCdf t | 12,354 | 6,037 | ||||||||||
| pow t | 5,964 | 3,317 | 23,479 | 10,065 | 1,279 | 2,223 | 1,355 | 9,544 | ||||
| powu t | 6,647 | 5,252 | 4,006 | 2,318 | 3,133 | 2,559 | 3,881 | |||||
| round | 474 | 212 | ||||||||||
| sign | 139 | 75 | 181 | 84 | 78 | |||||||
| sinh t | 3,670 | 4,109 | ||||||||||
| sqrt t | 1,205 | 469 | 760 | 978 | 393 | 828 | 2,351 | 456 | 824 | 766 | ||
| sub | 745 | 140 | 1,230 | 187 | 3 | 162 | 150 | |||||
| tanh t | 3,717 | 3,975 | ||||||||||
| toBL127 | 343 | 292 | ||||||||||
| toFixed18 | 480 | 121 | ||||||||||
| toFixed18Down | 723 | 160 | ||||||||||
| toFixed18Up | 724 | 185 | ||||||||||
| toIntDown | 466 | 278 | ||||||||||
| toIntUp | 467 | |||||||||||
| toUintDown | 405 | 240 | ||||||||||
| toUintUp | 406 | |||||||||||
| zeroFloorSub | 829 | 212 | 17 | 92 |
The function each cell measures
- ABDKMathQuad
absabs(x);addadd(a, b);cmpcmp(a, b);divdiv(a, b);eqeq(a, b);expexp(x);exp2pow_2(x);fromBL127from128x128(x) (truncates; fromBL127 rounds to nearest);fromUintDownfromUInt(x) (truncates the significand);invdiv(fromUInt(1), x) (composed);lnln(x);log2log_2(x);ltcmp(a, b) < 0 (composed);mulmul(a, b);negneg(x);powexp(mul(y, ln(x))) (composed);signsign(x);sqrtsqrt(x);subsub(a, b);toBL127to128x128(x) (truncates; toBL127 rounds to nearest);toIntDowntoInt(x) (truncates: floor for x >= 0, the rows kept);toUintDowntoUInt(x) (truncates: floor for x >= 0)- PRBMath
absabs(x);addadd(a, b);avgavg(a, b);ceilceil(x);divdiv(a, b);expexp(x);exp2exp2(x);floorfloor(x);fracfrac(x);gavggm(a, b);invinv(x);lnln(x);log10log10(x);log2log2(x);mulmul(a, b);negunary(x);powpow(x, y);powupowu(x, n), n a uint256 (n >= 0);signsign(x);sqrtsqrt(x);subsub(a, b)- Solady
absabs(int256);addrawAdd(int256, int256) (unchecked);avgavg(int256, int256);cbrtcbrtWad(x) (x >= 0);clampclamp(int256, int256, int256);distdist(int256, int256);divsDivWad(a, b);divDowndivWad(a, b) (a >= 0, b > 0);divUpdivWadUp(a, b) (a >= 0, b > 0);expexpWad(x);factorialfactorial(uint256) on the integer x (integral x);gavgmulSqrt(a, b) (a, b >= 0);invsDivWad(1e18, x) (composed);lambertW0lambertW0Wad(x);lerplerp(a, b, t, 0, 1e18) (t in [0, 1]: Solady clamps t);lnlnWad(x);log2Uplog2Up(uint256) on the integer x (integral x >= 1);maxmax(int256, int256);minmin(int256, int256);mulsMulWad(a, b) (toward zero);mulDownmulWad(a, b) (a, b >= 0);mulUpmulWadUp(a, b) (a, b >= 0);powpowWad(x, y);powurpow(x, n, 1e18) (x >= 0, n >= 0);sqrtsqrtWad(x) (x >= 0);subrawSub(int256, int256) (unchecked);zeroFloorSubzeroFloorSub(uint256, uint256) (a, b >= 0)- ABDK 64.64
absabs(x);addadd(a, b);avgavg(a, b);divdiv(a, b);expexp(x);exp2exp_2(x);gavggavg(a, b);invinv(x);lnln(x);log2log_2(x);mulmul(a, b);negneg(x);powupow(x, n), n a uint256 (n >= 0);sqrtsqrt(x);subsub(a, b)- Balancer
cbrtpow(x, 333333333333333333) (composed; x >= 0);expexp(x);lnln(x);log10log(x, 10e18);log2log(x, 2e18);powpow(x, y) (x, y >= 0);sqrtpow(x, 0.5e18) (composed; x >= 0)- Solmate
divwadDiv(a, b) (toward zero);divDowndivWadDown(a, b) (a, b >= 0);divUpdivWadUp(a, b) (a, b >= 0);expwadExp(x);lnwadLn(x);mulwadMul(a, b) (toward zero);mulDownmulWadDown(a, b) (a, b >= 0);mulUpmulWadUp(a, b) (a, b >= 0);powwadPow(x, y);powurpow(x, n, 1e18) (x >= 0, n >= 0);sqrtsqrt(x * 1e18) (composed: the integer root; x >= 0)- PRB UD60x18
addadd(a, b) (a, b >= 0);avgavg(a, b) (a, b >= 0);ceilceil(x) (x >= 0);divdiv(a, b) (a, b >= 0);expexp(x) (x >= 0);exp2exp2(x) (x >= 0);floorfloor(x) (x >= 0);fracfrac(x) (x >= 0);gavggm(a, b) (a, b >= 0);invinv(x) (x >= 0);lnln(x) (x >= 0);log10log10(x) (x >= 0);log2log2(x) (x >= 0);mulmul(a, b) (a, b >= 0);powpow(x, y) (x, y >= 0);powupowu(x, n), n a uint256 (x >= 0, n >= 0);sqrtsqrt(x) (x >= 0);subsub(a, b) (a, b >= 0)- snekmate
avg_int256_average(a, b);cbrt_wad_cbrt(x) (x >= 0);divDown_mul_div(a, 1e18, b, False) (a, b >= 0);divUp_mul_div(a, 1e18, b, True) (a, b >= 0);exp_wad_exp(x);ln_wad_ln(x);log2Up_log2(uint256, True) on the integer x (integral x >= 1);mulDown_mul_div(a, b, 1e18, False) (a, b >= 0);mulUp_mul_div(a, b, 1e18, True) (a, b >= 0);sign_signum(x)- OpenZeppelin
absSignedMath.abs(int256);avgSignedMath.average(a, b) (toward zero; BL127's avg floors);divDownMath.mulDiv(a, 1e18, b) (a, b >= 0);divUpMath.mulDiv(a, 1e18, b, Rounding.Ceil) (a, b >= 0);log2UpMath.log2(uint256, Rounding.Ceil) on the integer x (integral x >= 1);maxSignedMath.max(a, b);minSignedMath.min(a, b);mulDownMath.mulDiv(a, b, 1e18) (a, b >= 0);mulUpMath.mulDiv(a, b, 1e18, Rounding.Ceil) (a, b >= 0);sqrtMath.sqrt(x * 1e18) (composed: the integer root; x >= 0);zeroFloorSubMath.saturatingSub(uint256, uint256) (a, b >= 0)- Uniswap
divDownFullMath.mulDiv(a, 1e18, b) (a, b >= 0);divUpFullMath.mulDivRoundingUp(a, 1e18, b) (a, b >= 0);mulDownFullMath.mulDiv(a, b, 1e18) (a, b >= 0);mulUpFullMath.mulDivRoundingUp(a, b, 1e18) (a, b >= 0)
Median gas per inline call: over random inputs that take no shortcut for the ops marked t, else over the op's input ladder. BL19 and ABDKMathQuad are measured on the same values (bl19/gas.json), the others on BL127's inputs (gas.json). Empty: the library does not offer the op; rev: it offers it and reverted on every input. Hover a cell for the function it calls. Calling the deployed contract instead adds the staticcall: about 554 gas on BL127's add (682 against 128); every op's object figure is on the BL127 and BL19 pages.
Precision per op
| op | vectors | reverts | min bits | mean bits | worst input |
|---|---|---|---|---|---|
| abs | 98 | 1 | exact | exact | |
| add | 377 | 23 | exact | exact | |
| atanh | 534 | 5 | 130 | 131 | 0x000000000000…0x0000000000000000000000000000000000000b504f333f9de6484597d89b3754 |
| avg | 200 | 0 | 129 | 234 | 0xffffffffffff…0xfffffffffffffffff21f494c589c000000000000000000000000000000000000,0xfffffffffffffffffffffffffffffd34d62c1fdb28540383534af43c13a51359 |
| cbrt | 98 | 1 | 130 | 164 | 0x000000000000…0x00000000000000001bce1abd36207803b5f3bb79b2f817e5a2d5e288b8fe5d96 |
| ceil | 97 | 2 | exact | exact | |
| clamp | 300 | 0 | exact | exact | |
| compound | 141 | 59 | 130 | 208 | 0x000000000000…0x0000000000000000000000000000000019999999999999999999999999999999,0x0000000000000000000000000000016d00000000000000000000000000000000 |
| cosh | 575 | 4 | 129 | 175 | 0x000000000000…0x0000000000000000000000000000000000000000000000010000000000000000 |
| dist | 190 | 10 | exact | exact | |
| div | 377 | 23 | 129 | 193 | 0x23fccae3cfdc…0x23fccae3cfdca92920400cceaf07264105d9fd08f1256e2392022e9d1745ab4a,0x00000000000000000000000000000003243f6a8885a308d313198a2e03707344 |
| divDown | 363 | 37 | 128 | 188 | 0xffffffffffff…0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff,0x7870107c047009ebaad71c7ebbaf317671aaa8a105a47733a492aebe56be3702 |
| divUp | 367 | 33 | 129 | 190 | 0x000000000000…0x0000000000000000000000000000000180000000000000000000000000000000,0x00000000000000000000000000000000004189374bc6a7ef9db22d0e56041893 |
| erf | 584 | 0 | 132 | 186 | 0x000000000000…0x000000000000000000000000000000029a7e647802374d98add579a7fcc24210 |
| erfc | 584 | 0 | 130 | 132 | 0x000000000000…0x000000000000000000000000000000029a7e647802374d98add579a7fcc24210 |
| exp | 117 | 4 | 130 | 207 | 0xffffffffffff…0xffffffffffffffffffffffffffffffa6947ae147ae147ae147ae147ae147ae14 |
| exp10 | 80 | 3 | 131 | 217 | 0xffffffffffff…0xfffffffffffffffffffffffffffffff141f0353d3320c8f151d83c6c95e647d4 |
| exp2 | 104 | 3 | 130 | 217 | 0xffffffffffff…0xffffffffffffffffffffffffffffff7f00000000000000000000000000000000 |
| expm1 | 577 | 2 | 130 | 153 | 0x000000000000…0x0000000000000000000000000000000000000000000000010000000000000000 |
| factorial | 12 | 6 | exact | exact | |
| floor | 99 | 0 | exact | exact | |
| frac | 99 | 0 | exact | exact | |
| fromFixed18 | 33 | 4 | 131 | 191 | 0xffffffffffff…0xfffffffffffffffffffffffffffffffff5cc03f34ac9aaa4896da2872a07e2d0 |
| gavg | 200 | 0 | 131 | 210 | 0x000000000000…0x0000000000000000000000000000000000000000000000000000000000000400,0x0000000000000000000000000000000000000000000000000000800000000000 |
| hypot | 121 | 0 | 131 | 183 | 0x000000000000…0x0000000000000000000000000000000080000000000000000000000000000000,0x00000000000000000000000000000003243f6a8885a308d313198a2e03707344 |
| inv | 62 | 3 | exact | exact | 0x203165f4c782…0x203165f4c782db9cffce938726dd1ec020de05fd184a1af4395e2a8402671297 |
| lambertW0 | 140 | 3 | 130 | 134 | 0xffffffffffff…0xffffffffffffffffffffffffffffffffa3d70a3d70a3d70a3d70a3d70a3d70a3 |
| lambertWm1 | 86 | 6 | 130 | 131 | 0xffffffffffff…0xffffffffffffffffffffffffffffffffb30b072074fe3b487073a1b28c4adf68 |
| lerp | 289 | 11 | exact | exact | |
| ln | 322 | 4 | 130 | 135 | 0x000000000000…0x0000000000000000000000000019eeee1991f56daa32cdc95baeb71517c3c017 |
| log10 | 322 | 4 | 130 | 135 | 0x000000000000…0x00000000000000000000000000000000005fa366409a1e0f1037a02f8b4a8778 |
| log1p | 561 | 18 | 130 | 132 | 0x000000000000…0x0000000000000000000000000000000000000000000000010000000000000000 |
| log2 | 322 | 4 | 130 | 233 | 0x000000000000…0x0000000000000000028dfc4db50a10ff45a3860e8964d6a14a662cfe41b5139e |
| log2Up | 322 | 4 | exact | exact | |
| max | 200 | 0 | exact | exact | |
| min | 200 | 0 | exact | exact | |
| mul | 231 | 169 | 132 | 232 | 0xffffffffffff…0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe,0x8000000000000000000000000000000000000000000000000000000000000001 |
| mulDown | 218 | 182 | 131 | 229 | 0x000000000000…0x0000000000000000000000000000000000000000000000000000000000000002,0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe |
| mulUp | 225 | 175 | 129 | 226 | 0xffffffffffff…0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe,0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff |
| neg | 98 | 1 | exact | exact | |
| normCdf | 584 | 0 | 147 | 228 | 0x000000000000…0x00000000000000000000000000000004bba8d97f090a853b60da8e5e13acf310 |
| pow | 501 | 99 | 130 | 181 | 0x000000000000…0x0000000000000000000000000000017b8003884dd86c89a488fc31f62f8cea98,0xfffffffffffffffffffffffffffffffee80023779f2d390dbf519c550fe6719a |
| powu | 435 | 165 | 130 | 204 | 0xffffffffffff…0xfffffffffffffffffffffffffffffffc29a12310624d183ca1d03b091fb77270,0x0000000000000000000000000000004000000000000000000000000000000000 |
| round | 97 | 2 | exact | exact | |
| sign | 99 | 0 | exact | exact | |
| sinh | 575 | 4 | 130 | 149 | 0x000000000000…0x0000000000000000000000000000000000016a09e667f3bcc908b2fb1366ea95 |
| sqrt | 298 | 3 | 129 | 198 | 0x000000000000…0x0000000000000000000000000000000000000000000000000000000000020000 |
| sub | 380 | 20 | exact | exact | |
| tanh | 579 | 0 | 130 | 216 | 0x000000000000…0x00000000000000000000000000000000005a827999fcef32422cbec4d9baa55f |
| toFixed18 | 99 | 0 | 181 | 199 | 0xffffffffffff…0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff |
| toFixed18Down | 99 | 0 | 181 | 199 | 0xffffffffffff…0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff |
| toFixed18Up | 99 | 0 | 182 | 201 | 0x000000000000…0x0000000000000000000000000000000000000000000000000000000000000001 |
| zeroFloorSub | 189 | 11 | exact | exact |
Relative correct bits of the 127.128 result, msb(|truth|) − msb(|truth − got|), against the real truth (mpmath at 200 decimal places) over the committed vectors in test/bl127/vectors/, for results of magnitude 1 or more. "exact" is bit-identical with the truth. Every op is also held to its rounding contract: nearest within half an ULP, floor, ceil and trunc within one; maxErrUlp in the data. Reverts counts vectors where the oracle and the Yul both reject the input with the same error. Hover a worst input for the whole word. Source: precision.json.
- Integer, rounding and comparison ops: bit-exact.
mulandsqrtround down anddivtoward zero, within one ULP; "exact" in the table means equal to an oracle that rounds the same way. The directed ops round the way their names say, within one ULP. - Every transcendental (
exp,ln,pow,powu,compound,cbrt, the hyperbolics,erf,erfc,normCdf, both Lambert W branches) is correctly rounded to nearest: each fast value carries a derived error bound and a rounding test, and a wider stage decides what the test cannot, so the word is within half an ULP (maxErrUlpin the data) at every committed vector and on every random input of the sweep, plain and with every test forced.exp(ln x)returns the same word for 10,000 steps. Thepowexception of earlier releases (an exponent near 290) is gone in 3.0.