exp
MathComputes the natural exponential of x in 18-decimal fixed-point.
Avg. gas
289
Max abs. error
3.0e-16
when exp(x) < 1
Max rel. error
2.2e-14
when exp(x) ≥ 1
Signature
function exp(int256 x) internal pure returns (uint256 y)Parameters
| Name | Type | Description |
|---|---|---|
| x | int256 | Signed input in 18-decimal fixed-point format (1e18 = 1.0). |
Returns
| Name | Type | Description |
|---|---|---|
| y | uint256 | Result e^x in 18-decimal fixed-point format. |
Bounds
| Bound | Value |
|---|---|
| EXP_UPPER_BOUND | 135e18 — positive-input ceiling; at or above it the function reverts. Chosen just below the ~135.306e18 uint256 wrap point so int256(exp(x)) stays safe in expm1. |
| EXP_LOWER_BOUND | −41.446531…e18 — negative-input floor. At x ≤ EXP_LOWER_BOUND the true result is below 1e-18, so the function returns 0 silently (no revert). |
Behavior
- Handles negative inputs internally via reciprocal logic — pass any signed
int256. - Reverts with
ExpUpperBoundError()whenx ≥ 135e18. - For very negative inputs (roughly
x < −41.45e18) returns 0 — a graceful underflow, not a revert. - Pure assembly hot path; no external calls or storage.
How it works
The challenge is approximating e^x accurately across a wide input range with only integer arithmetic. DeFiMath applies a two-stage range reduction. Stage 1 splits x = k · ln(2) + r with integer k and r ∈ [0, ln(2)), so e^x = 2^k · e^r — the 2^k factor becomes a free left shift. Stage 2 divides r by 64 (a right-shift by 6): r' = r / 64 ∈ [0, ~0.0108], confining the costly part to a tiny interval.
On that interval a [3,3] Padé approximant approximates e^r' with a handful of multiplies and a single integer division:
e^r' ≈ (120 + 60r' + 12r'² + r'³) / (120 − 60r' + 12r'² − r'³)
The two reductions are then undone in reverse: the result is raised to the 64th power via six successive squarings (y² → y⁴ → … → y⁶⁴) to invert the r / 64 step, then left-shifted by k to apply the 2^k factor. Those squarings amplify the approximant's relative error, so the finished exp holds to a max relative error of 2.2e-14 (and 3.0e-16 absolute near the root x = 0).
Negative inputs use the same machinery on |x|, then reciprocate: exp(−x) = 1 / exp(x). The two endpoints are asymmetric: at x ≥ EXP_UPPER_BOUND (135e18) the function reverts with ExpUpperBoundError. The cap sits just below the ~135.306e18 point where the result would wrap uint256 — the small margin keeps int256(exp(x)) safe inside expm1 even after approximation-error headroom, and exp(135) ≈ 4.3e58 is already astronomically large. At x ≤ EXP_LOWER_BOUND (≈ −41.446e18) the true result is sub-1e-18 — not representable in 18-decimal fixed-point — so the function returns 0 silently as a graceful underflow rather than reverting. The whole hot path stays in unchecked Yul assembly — no library calls, ~289 gas.
Errors
| Error | Trigger |
|---|---|
| ExpUpperBoundError | x ≥ EXP_UPPER_BOUND (positive overflow only — the negative branch underflows silently to 0) |
Example
import "defimath-lib/contracts/math/Math.sol";
int256 x = 1e18; // x = 1.0
uint256 y = Math.exp(x); // y ≈ 2.71828e18