exp
MathComputes the exponential function e^x for a signed 18-decimal fixed-point input.
Gas
333
Max abs. error
5.1e-14
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. |
Behavior
- Handles negative inputs internally via reciprocal logic — pass any signed
int256. - Reverts with
ExpUpperBoundError()whenx ≥ 135.305999…e18. - 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 fundamental challenge is approximating e^x accurately across a wide input range using only integer arithmetic. DeFiMath uses a three-stage reduction: split x = k · ln(2) + r where k is an integer and r ∈ [0, ln(2)], then e^x = 2^k · e^r. This turns the 2^k factor into a free left shift and confines the costly part to a small interval.
We then reduce r further by dividing by 256, giving r' ∈ [0, ~0.0027]. On this tiny interval the [2,2] Padé approximant
e^r' ≈ ((r' + 3)² + 3) / ((r' − 3)² + 3)
is accurate to well below 18-decimal precision in just two squarings and a single integer division. To undo the 256× reduction we raise the result to the 256th power — four quartic squarings (y⁴, then y¹⁶, y⁶⁴, y²⁵⁶). Finally we shift left by k to apply the 2^k factor.
Negative inputs use the same machinery on |x|, then reciprocate: exp(−x) = 1 / exp(x). Inputs with |x| ≥ 135.305… would overflow uint256, so the function reverts above that bound; inputs below −41.45e18 underflow to 0 (the true value is sub-1e-18). The whole hot path stays in unchecked Yul assembly — no library calls, ~333 gas.
Example
import "defimath-lib/contracts/math/Math.sol";
int256 x = 1e18; // x = 1.0
uint256 y = DeFiMath.exp(x); // y ≈ 2.71828e18