The ladder measures a slope: digits lost one step at a time. This page measures the cliffs. Each probe is one op evaluated once where a domain ends: a logarithm within a per-second rate of one, an exponential of −42, a probability of one in 10^18, a base a hair above one raised to a year of seconds, the tail of the normal distribution where an option's price lives. Every library runs the probe in its own representation and the result is compared with the exact value; a cell either has digits or says how the library had no answer: zero where the result fell below the format's floor, revert with the reason, range when the argument does not fit the word, n/a when the library has no way to compute the op. FP127's own ends are on the page too: exp at ±88, the word at 1.7 × 10^38, the tail of erfc at 9.3.
How this was measured
- digits
- digits = floor(-log10 |v - t| / |t|), capped at 60 (reported as exact); errUlps is the signed error in units of the representation's last place (none for binary128).
- gas
- gas is measured inside the adapter around the op, after the adapter and the FP127 object are warm. The FP127 (deployed) form includes the staticcall; the others are internal calls.
- live
- EdgeRunner.run(op, form, args) on Sepolia evaluates any cell with one eth_call and returns (ok, raw, reason, gas); the edges page's verify button sends the probe's encoded arguments and compares the raw word bit for bit.
- range
- RANGE means the argument does not fit the representation at all (above 2^127 for FP127, 2^63 for 64.64, 2^128 as a bit pattern for binary128) and nothing was called.
- reproduce
- make edges regenerates edges.json and edges.md from test/ladder/Edges.t.sol and this script; make edges-check fails CI when the committed dataset differs.
- reverted
- A revert is recorded with its selector and name. Unsupported means the library has no way to compute the op (the accrual libraries have no general ops; only FP127 has the secondary Lambert branch; the libraries without erf, erfc or normCdf run the same series and continued fraction through their own ops instead, so those cells are not Unsupported).
- truth
- Every probe is one op evaluated once. The truth is mpmath at 200 decimal digits from the exact arguments; truthFormat is the same op from the arguments as the representation holds them (floored on a grid, nearest for binary128), so digitsFormat measures the op alone and digits what a caller sees.
- zero
- A cell is marked zero when the library returned 0 and the truth is not 0: the result fell below the representation's floor. On an 18-decimal grid that is anything below 1e-18; on FP127's, below 2^-128.
- versions
- Generated 2026-10-15; aave aave-v3-origin@8305565ae342 (MathUtils, transcribed), abdk v3.2, balancer balancer-v3-monorepo@2b9ce4b1b8ad (LogExpMath.sol, vendored), forge forge Version: 1.7.1, fp127 2b291a7, huff sepolia:0xfae694D0c2c44181791F838c54Ed64C3151FfE30@11857616, maker dss pot.sol rpow via solady v0.1.26, morpho morpho-blue@8e26ca6a8dbc (MathLib, transcribed), prb-math v4.2.0, solady v0.1.26.
ln(x)
The logarithm near one is where a per-second rate lives: ln(1 + r) for r = 1e-9 has eight digits on an 18-decimal grid.
| probe | truth | FP127 | ABDK | Solady | PRBMath | Quad | Balancer | Aave | Morpho | Maker |
|---|---|---|---|---|---|---|---|---|---|---|
| ln(1+1e-6) | 0.0000009999995000003333… | 34 |
13 |
12 |
11 |
28 |
12 |
|||
| ln(1+1e-9) |
0.0000000009999999995000… | 30 |
10 |
9 |
8 |
25 |
9 |
|||
| ln(1+1e-12) | 0.0000000000009999999999… | 26 |
7 |
6 |
5 |
22 |
5 |
|||
| ln(1+1e-15) | 9.9999999999999950000000… | 24 |
4 |
15 |
2 |
19 |
3 |
|||
| ln(1+1e-18) |
9.9999999999999999950000… | 21 |
1 |
18 |
zero |
16 |
zero |
|||
| ln(1-1e-12) | -0.000000000001000000000… | 26 |
6 |
12 |
5 |
24 |
12 |
|||
| ln(1e-18) | -41.44653167389282231232… | 22 |
3 |
19 |
19 |
33 |
20 |
|||
| ln(1e-30) | -69.07755278982137052053… | 10 |
revert |
revert |
revert |
33 |
revert |
|||
| ln(1e30) | 69.077552789821370520539… | 41 |
range | 20 |
18 |
33 |
20 |
|||
| ln(1e38) | 87.498233533773735992683… | 40 |
range | 20 |
18 |
33 |
20 |
exp(x)
exp below -42 is zero on an 18-decimal grid and has one digit at -40: every probability, discount or decay smaller than 1e-18 is gone.
| probe | truth | FP127 | ABDK | Solady | PRBMath | Quad | Balancer | Aave | Morpho | Maker |
|---|---|---|---|---|---|---|---|---|---|---|
| exp(-1e-12) | 0.9999999999990000000000… | 39 |
18 |
24 |
18 |
34 |
24 |
|||
| exp(-20) | 0.0000000020611536224385… | 31 |
10 |
9 |
9 |
32 |
9 |
|||
| exp(-30) | 9.3576229688401746049158… | 26 |
6 |
5 |
5 |
32 |
5 |
|||
| exp(-40) |
4.2483542552915889953292… | 21 |
2 |
1 |
1 |
32 |
1 |
|||
| exp(-41) | 1.5628821893349887680908… | 21 |
1 |
0 |
0 |
32 |
0 |
|||
| exp(-42) |
5.7495222642935598066643… | 21 |
1 |
zero |
zero |
32 |
revert |
|||
| exp(-43) | 2.1151310375910804866314… | 21 |
0 |
zero |
zero |
32 |
revert |
|||
| exp(-60) | 8.7565107626965203384887… | 13 |
zero |
zero |
zero |
32 |
revert |
|||
| exp(-88) |
6.0546018954011858845318… | 1 |
zero |
zero |
zero |
31 |
revert |
|||
| exp(-89) |
2.2273635617957437392229… | zero |
zero |
zero |
zero |
31 |
revert |
|||
| exp(-100) | 3.7200759760208359629596… | zero |
zero |
zero |
zero |
31 |
revert |
|||
| exp(40) | 235385266837019985.40789… | 43 |
19 |
20 |
16 |
32 |
21 |
|||
| exp(43) | 4727839468229346561.4744… | 43 |
21 |
21 |
16 |
32 |
20 |
|||
| exp(44) |
12851600114359308275.809… | 43 |
revert |
20 |
16 |
32 |
20 |
|||
| exp(60) | 114200738981568428366295… | 45 |
revert |
20 |
16 |
32 |
20 |
|||
| exp(88) |
165163625499400185552832… | 44 |
revert |
20 |
16 |
31 |
20 |
|||
| exp(89) |
448961281917434524628424… | revert |
revert |
20 |
16 |
31 |
20 |
|||
| exp(100) | 2.6881171418161354484126… | revert |
revert |
21 |
16 |
31 |
21 |
|||
| exp(130) | 2.8726495508178319332673… | revert |
revert |
20 |
16 |
31 |
21 |
|||
| exp(135) | 4.2633899483147210448936… | revert |
revert |
20 |
revert |
31 |
revert |
|||
| exp(136) |
1.1589095424138854283480… | revert |
revert |
revert |
revert |
31 |
revert |
sqrt(x)
The root of a tiny number: sqrt(1e-20) is 1e-10, which the grid holds, but 1e-20 itself is zero on it.
| probe | truth | FP127 | ABDK | Solady | PRBMath | Quad | Balancer | Aave | Morpho | Maker |
|---|---|---|---|---|---|---|---|---|---|---|
| sqrt(1e-6) | 0.001 | 33 |
13 |
exact |
exact |
34 |
exact |
|||
| sqrt(1e-12) | 0.000001 | 27 |
8 |
exact |
exact |
34 |
exact |
|||
| sqrt(1e-18) | 0.000000001 | 21 |
1 |
exact |
exact |
34 |
exact |
|||
| sqrt(1e-20) |
0.0000000001 | 19 |
zero |
zero |
zero |
34 |
zero |
|||
| sqrt(1e-30) | 1.0e-15 | 8 |
zero |
zero |
zero |
34 |
zero |
|||
| sqrt(1e30) | 1000000000000000.0 | exact |
range | exact |
exact |
exact |
18 |
|||
| sqrt(1e36) | 1000000000000000000.0 | exact |
range | exact |
exact |
exact |
18 |
|||
| sqrt(1e38) | 10000000000000000000.0 | exact |
range | exact |
exact |
exact |
17 |
|||
| sqrt(1e40) |
100000000000000000000.0 | range | range | exact |
exact |
exact |
18 |
|||
| sqrt(1e50) | 100000000000000000000000… | range | range | exact |
revert |
exact |
18 |
range | range |
pow(x, y)
A base near one to a large power: per-second rates over years, and Uniswap's tick range 1.0001^(+-887272).
| probe | truth | FP127 | ABDK | Solady | PRBMath | Quad | Balancer | Aave | Morpho | Maker |
|---|---|---|---|---|---|---|---|---|---|---|
| pow(1+0.05/31536000, 31536000) |
1.0512710963343545550116… | 31 |
11 |
10 |
9 |
27 |
11 |
|||
| pow(1+0.001/31536000, 31536000) |
1.0010005001666924709092… | 31 |
11 |
10 |
9 |
26 |
10 |
|||
| pow(1+0.05/31536000, 315360000) |
1.6487212700466205410050… | 30 |
10 |
9 |
8 |
26 |
10 |
|||
| pow(1+0.05/31536000/12, 31536000*12) |
1.0512710963725515826369… | 30 |
10 |
10 |
8 |
25 |
9 |
|||
| pow(1.0001, 887272) |
340256786836388094050805… | revert |
revert |
12 |
11 |
29 |
17 |
|||
| pow(1.0001, -887272) |
2.9389568075855848388747… | 4 |
zero |
zero |
zero |
29 |
revert |
|||
| pow(0.999999, 1000000) | 0.3678792572316450942857… | 32 |
13 |
12 |
11 |
28 |
18 |
|||
| pow(2, 0.5) | 1.4142135623730950488016… | 39 |
18 |
17 |
18 |
33 |
17 |
|||
| pow(10, -18) | 1.0e-18 | 20 |
1 |
exact |
exact |
31 |
revert |
|||
| pow(1e-9, 0.5) | 0.0000316227766016837933… | 29 |
10 |
9 |
9 |
32 |
9 |
|||
| pow(1e-18, 0.5) | 0.000000001 | 21 |
1 |
exact |
exact |
32 |
exact |
mul(a, b)
Tiny times tiny: a fee on a fee, a unit price times a unit size, below 1e-18 is zero.
| probe | truth | FP127 | ABDK | Solady | PRBMath | Quad | Balancer | Aave | Morpho | Maker |
|---|---|---|---|---|---|---|---|---|---|---|
| mul(1e-9, 1e-9) |
1.0e-18 | 20 |
1 |
zero |
zero |
33 |
zero |
|||
| mul(1e-10, 1e-10) |
1.0e-20 | 18 |
zero |
zero |
zero |
34 |
zero |
|||
| mul(1e-12, 1e-8) | 1.0e-20 | 18 |
zero |
zero |
zero |
34 |
zero |
|||
| mul(1e19, 1e19) | 100000000000000000000000… | exact |
range | exact |
exact |
exact |
exact |
|||
| mul(1e20, 1e20) |
100000000000000000000000… | revert |
range | exact |
exact |
exact |
exact |
div(a, b)
Small over large, and one over tiny.
| probe | truth | FP127 | ABDK | Solady | PRBMath | Quad | Balancer | Aave | Morpho | Maker |
|---|---|---|---|---|---|---|---|---|---|---|
| div(1, 3) | 0.3333333333333333333333… | 38 |
19 |
17 |
17 |
34 |
17 |
|||
| div(1e-12, 1e9) | 1.0e-21 | 17 |
zero |
zero |
zero |
34 |
zero |
|||
| div(1e-9, 1e12) | 1.0e-21 | 17 |
zero |
zero |
zero |
33 |
zero |
|||
| div(1e30, 1e-9) | 100000000000000000000000… | revert |
range | 8 |
8 |
exact |
8 |
|||
| div(1, 1e-30) | 100000000000000000000000… | 8 |
revert |
revert |
revert |
exact |
revert |
W0(x)
The principal Lambert branch near its branch point -1/e, where the slope is infinite; only Solady has it among the others.
| probe | truth | FP127 | ABDK | Solady | PRBMath | Quad | Balancer | Aave | Morpho | Maker |
|---|---|---|---|---|---|---|---|---|---|---|
| lambertW0(-1/e+1e-6) | -0.997670166272007889180… | 35 |
15 |
|||||||
| lambertW0(-1/e+1e-9) | -0.999926268755381939963… | 34 |
13 |
|||||||
| lambertW0(-1/e+1e-12) | -0.999997668357830588824… | 32 |
12 |
|||||||
| lambertW0(-1/e+1e-15) | -0.999999926266945067481… | 30 |
10 |
|||||||
| lambertW0(-1/e+1e-18) |
-0.999999997668356020215… | 29 |
8 |
|||||||
| lambertW0(-1e-18) | -1.000000000000000001000… | 20 |
17 |
|||||||
| lambertW0(1e-18) | 9.9999999999999999900000… | 20 |
18 |
|||||||
| lambertW0(1e30) | 64.904633770046124079605… | 41 |
range | 20 |
||||||
| lambertW0(1e38) | 83.078448213164095927204… | 40 |
range | 20 |
W-1(x)
The secondary branch, toward zero from below; FP127 only.
| probe | truth | FP127 | ABDK | Solady | PRBMath | Quad | Balancer | Aave | Morpho | Maker |
|---|---|---|---|---|---|---|---|---|---|---|
| lambertWm1(-1/e+1e-9) | -1.000073734868993836022… | 34 |
||||||||
| lambertWm1(-1e-10) | -26.29523881924692569411… | 30 |
||||||||
| lambertWm1(-1e-30) | -73.37311031382297679706… | 11 |
log1p(x)
ln(1 + x) as an op: the libraries without it compute ln(1 + x), and 1 + x is where x loses its digits.
| probe | truth | FP127 | ABDK | Solady | PRBMath | Quad | Balancer | Aave | Morpho | Maker |
|---|---|---|---|---|---|---|---|---|---|---|
| log1p(1e-6) | 0.0000009999995000003333… | 34 |
13 |
12 |
11 |
28 |
12 |
|||
| log1p(1e-9) |
0.0000000009999999995000… | 30 |
10 |
8 |
8 |
25 |
8 |
|||
| log1p(1e-12) | 0.0000000000009999999999… | 26 |
7 |
12 |
5 |
22 |
6 |
|||
| log1p(1e-15) | 9.9999999999999950000000… | 24 |
4 |
15 |
2 |
18 |
3 |
|||
| log1p(1e-18) | 9.9999999999999999950000… | 21 |
1 |
18 |
zero |
15 |
zero |
|||
| log1p(1e-20) |
9.9999999999999999999500… | 18 |
zero |
zero |
zero |
14 |
zero |
|||
| log1p(1e-30) | 9.9999999999999999999999… | 8 |
zero |
zero |
zero |
4 |
zero |
|||
| log1p(-1e-9) | -0.000000001000000000500… | 30 |
10 |
9 |
8 |
25 |
9 |
|||
| log1p(1e6) | 13.815511557963774104441… | 40 |
20 |
19 |
18 |
33 |
19 |
expm1(x)
e^x - 1 as an op: the libraries without it compute exp(x) - 1 and the one cancels the digits.
| probe | truth | FP127 | ABDK | Solady | PRBMath | Quad | Balancer | Aave | Morpho | Maker |
|---|---|---|---|---|---|---|---|---|---|---|
| expm1(1e-6) | 0.0000010000005000001666… | 33 |
13 |
12 |
11 |
27 |
12 |
|||
| expm1(1e-9) | 0.0000000010000000005000… | 29 |
9 |
8 |
8 |
24 |
8 |
|||
| expm1(1e-12) | 0.0000000000010000000000… | 26 |
7 |
12 |
5 |
21 |
12 |
|||
| expm1(1e-15) | 1.0000000000000005000000… | 23 |
4 |
15 |
2 |
18 |
15 |
|||
| expm1(1e-18) | 1.0000000000000000005000… | 20 |
1 |
18 |
zero |
15 |
18 |
|||
| expm1(1e-20) | 1.0000000000000000000050… | 18 |
zero |
zero |
zero |
14 |
zero |
|||
| expm1(-1e-9) | -0.000000000999999999500… | 30 |
10 |
9 |
9 |
25 |
9 |
|||
| expm1(-40) | -0.999999999999999995751… | 38 |
19 |
18 |
18 |
34 |
18 |
|||
| expm1(-88) | -0.999999999999999999999… | 39 |
38 |
38 |
38 |
34 |
revert |
|||
| expm1(20) | 485165194.40979027796910… | 44 |
19 |
19 |
17 |
32 |
21 |
compound(r, n)
(1 + r)^n for an integer n: per-second rates over years. FP127 and Maker take an exact integer power; the rest exp(n ln(1 + r)).
| probe | truth | FP127 | ABDK | Solady | PRBMath | Quad | Balancer | Aave | Morpho | Maker |
|---|---|---|---|---|---|---|---|---|---|---|
| compound(0.05/31536000, 31536000) |
1.0512710963343545550116… | 31 |
11 |
12 |
10 |
26 |
11 |
19 |
||
| compound(0.05/31536000, 315360000) |
1.6487212700466205410050… | 30 |
10 |
11 |
9 |
25 |
10 |
18 |
||
| compound(0.001/31536000, 31536000) |
1.0010005001666924709092… | 31 |
12 |
10 |
10 |
26 |
10 |
19 |
||
| compound(0.1/365, 365) |
1.1051557816162643739380… | 36 |
17 |
17 |
15 |
31 |
16 |
24 |
||
| compound(1e-12, 1000000000) |
1.0010005001667078411678… | 29 |
11 |
12 |
12 |
25 |
18 |
22 |
||
| compound(-0.5, 10) | 0.0009765625 | exact |
exact |
exact |
exact |
32 |
exact |
revert |
||
| compound(0.000000001, 10000000) | 1.0100501670791178067101… | 31 |
12 |
10 |
10 |
27 |
10 |
19 |
powu(x, n)
An integer power. Solady's rpow, PRBMath's powu, ABDK's pow and Maker's rpow square at the format's precision; FP127 on a 256-bit mantissa.
| probe | truth | FP127 | ABDK | Solady | PRBMath | Quad | Balancer | Aave | Morpho | Maker |
|---|---|---|---|---|---|---|---|---|---|---|
| powu(2, 10) | 1024.0 | exact |
exact |
exact |
exact |
32 |
17 |
exact |
||
| powu(1.0001, 887272) |
340256786836388094050805… | revert |
revert |
13 |
12 |
29 |
17 |
revert |
||
| powu(1.0001, -887272) |
2.9389568075855848388747… | 4 |
revert |
zero |
zero |
29 |
zero |
|||
| powu(0.999999, 1000000) | 0.3678792572316450942857… | 32 |
13 |
14 |
13 |
28 |
18 |
23 |
||
| powu(1+0.05/31536000, 31536000) | 1.0512710963343545550116… | 31 |
11 |
12 |
10 |
27 |
11 |
19 |
||
| powu(10, 38) | 100000000000000000000000… | exact |
revert |
exact |
exact |
31 |
16 |
revert |
||
| powu(3, -5) | 0.0041152263374485596707… | 36 |
17 |
15 |
15 |
32 |
15 |
|||
| powu(1.1, 100) | 13780.612339822270184118… | 36 |
17 |
19 |
19 |
32 |
15 |
29 |
erf(x)
The error function; the libraries without it run the same series and continued fraction through their own ops.
| probe | truth | FP127 | ABDK | Solady | PRBMath | Quad | Balancer | Aave | Morpho | Maker |
|---|---|---|---|---|---|---|---|---|---|---|
| erf(1e-10) | 0.0000000001128379167095… | 28 |
9 |
8 |
8 |
33 |
8 |
|||
| erf(0.5) | 0.5204998778130465376827… | 39 |
17 |
16 |
16 |
32 |
16 |
|||
| erf(1) | 0.8427007929497148693412… | 39 |
17 |
16 |
16 |
32 |
16 |
|||
| erf(3) | 0.9999779095030014145586… | 39 |
15 |
14 |
14 |
32 |
14 |
|||
| erf(4) | 0.9999999845827420997199… | 39 |
12 |
11 |
11 |
32 |
11 |
|||
| erf(5) | 0.9999999999984625402055… | 38 |
19 |
18 |
18 |
34 |
18 |
|||
| erf(6) | 0.9999999999999999784802… | 39 |
19 |
18 |
18 |
34 |
18 |
|||
| erf(8) | 0.9999999999999999999999… | 39 |
28 |
28 |
28 |
34 |
revert |
|||
| erf(9) | 0.9999999999999999999999… | 39 |
36 |
36 |
36 |
34 |
revert |
erfc(x)
The tail of the normal distribution: erfc(6) is 2e-17, erfc(9.3) one ULP of FP127, zero on an 18-decimal grid from about 6.4.
| probe | truth | FP127 | ABDK | Solady | PRBMath | Quad | Balancer | Aave | Morpho | Maker |
|---|---|---|---|---|---|---|---|---|---|---|
| erfc(1) | 0.1572992070502851306587… | 38 |
17 |
16 |
16 |
31 |
15 |
|||
| erfc(3) | 0.0000220904969985854413… | 34 |
10 |
9 |
9 |
27 |
9 |
|||
| erfc(4) | 0.0000000154172579002800… | 31 |
4 |
3 |
3 |
24 |
3 |
|||
| erfc(5) | 0.0000000000015374597944… | 27 |
7 |
6 |
6 |
32 |
6 |
|||
| erfc(6) |
2.1519736712498913116593… | 23 |
2 |
1 |
1 |
32 |
1 |
|||
| erfc(7) | 4.1838256077794143986140… | 16 |
zero |
zero |
zero |
32 |
revert |
|||
| erfc(8) | 1.1224297172982927079967… | 10 |
zero |
zero |
zero |
32 |
revert |
|||
| erfc(9) | 4.1370317465138102380539… | 2 |
zero |
zero |
zero |
32 |
revert |
|||
| erfc(9.3) |
1.6532441840301569593991… | 0 |
zero |
zero |
zero |
34 |
revert |
|||
| erfc(10) | 2.0884875837625447570007… | zero |
zero |
zero |
zero |
31 |
revert |
normCdf(x)
N(d) of Black-Scholes: zero on an 18-decimal grid from d = -8.3, two ULPs of FP127 at -13.
| probe | truth | FP127 | ABDK | Solady | PRBMath | Quad | Balancer | Aave | Morpho | Maker |
|---|---|---|---|---|---|---|---|---|---|---|
| normCdf(1e-12) | 0.5000000000003989422804… | 38 |
19 |
18 |
18 |
34 |
18 |
|||
| normCdf(-1) | 0.1586552539314570514147… | 38 |
17 |
16 |
16 |
32 |
16 |
|||
| normCdf(-3) | 0.0013498980316300945266… | 35 |
14 |
13 |
13 |
29 |
13 |
|||
| normCdf(-5) | 0.0000002866515718791939… | 32 |
8 |
6 |
6 |
26 |
6 |
|||
| normCdf(-6) |
0.0000000009865876450376… | 30 |
10 |
8 |
8 |
32 |
8 |
|||
| normCdf(-8) | 6.2209605742717841235159… | 24 |
4 |
3 |
3 |
31 |
3 |
|||
| normCdf(-8.3) |
5.2055697448902851579958… | 23 |
3 |
2 |
2 |
32 |
2 |
|||
| normCdf(-9) | 1.1285884059538406477355… | 21 |
1 |
zero |
zero |
31 |
zero |
|||
| normCdf(-10) | 7.6198530241605260659733… | 15 |
zero |
zero |
zero |
32 |
revert |
|||
| normCdf(-13) |
6.1171643995498796822752… | 1 |
zero |
zero |
zero |
31 |
revert |
|||
| normCdf(-14) | 7.7935368191928002543596… | zero |
zero |
zero |
zero |
31 |
revert |
|||
| normCdf(5) | 0.9999997133484281208060… | 39 |
14 |
12 |
12 |
32 |
12 |
Cells show correct significant digits against the exact value (hover for the value), or zero, revert, range, n/a as defined above. Verify calls run(op, form, args) on 0x4A32B0f99FC1e888bB9e5cb85399aDd7890B0957 through the public Sepolia RPC with the probe's encoded arguments and compares the raw word with the committed cell. Every cell was re-run through the live EdgeRunner on Sepolia by scripts/ladder/liveedges.py; the verify button repeats that call. The whole dataset is edges.json; the generator is make edges.