Math

Low-level fixed-point primitives in 18-decimal format (1e18 = 1.0). All pure, gas-efficient, and validated to sub-1e-12 relative error against reference libraries.

Contract: Math.sol

Functions

FunctionGasDescription
exp333Exponential function e^x
expm1439e^x − 1 (precision-preserving for small x)
ln375Natural logarithm
log1p500ln(1 + x) (precision-preserving for small x)
log2391Base-2 logarithm
log10391Base-10 logarithm
pow750Power function x^a
sqrt245Square root
cbrt368Cube root
sqrtTime184Specialized sqrt of time in years for Black-Scholes — no input validation
stdNormCDF660Standard normal CDF Φ(x)
erf685Error function
mulDiv155(a · b) / d with full 512-bit intermediate precision
mul130(a · b) / 1e18 — fixed-point multiply with denominator baked in
abs17Branchless |int256| (handles int256.min cleanly)
min23Branchless minimum of two uint256
max23Branchless maximum of two uint256
clamp78Clamp x into [lo, hi] (composed max then min)
avg21Overflow-safe (a + b) / 2 via (a & b) + ((a ^ b) >> 1)

npm install defimath-lib

Conventions

  • All values use 18-decimal fixed-point (1e18 = 1.0).
  • Signedness mirrors the math: exp takes int256, returns uint256; ln takes uint256, returns int256.
  • All functions are internal pure — no storage access, no external calls.

Quick example

solidity
import "defimath-lib/contracts/math/Math.sol";

uint256 x    = 2e18;                     // x = 2.0
uint256 root = DeFiMath.sqrt(x);         // root ≈ 1.41421e18
int256  lnX  = DeFiMath.ln(x);           // lnX  ≈ 0.69315e18
uint256 ePow = DeFiMath.exp(int256(x));  // ePow ≈ 7.389e18

Important notes

  • Use expm1 for small x. Computing ex − 1 via exp(x) - 1e18 catastrophically cancels when |x| < 0.01. expm1 uses a Taylor series in that range and preserves full 18-digit precision.
  • Use log1p for small x. Same reason — log1p(x) preserves precision near zero where ln(1 + x) would lose ~15 digits to subtraction.
  • Negative exp underflows silently to 0. For x < −41.45e18, exp(x) returns 0 (not a revert) since the true value is below 1e-18 representational precision.
  • CLZ requires Solidity 0.8.31 + EVM "osaka". ln, sqrt, cbrt, and sqrtTime emit the new CLZ opcode introduced in Osaka.
  • sqrtTime is specialized, not general-purpose. It expects x as time in years (1e18 = 1 year) and performs no input validation. It is built for Black-Scholes option pricing — where the caller has already bounded x — and is precision-tuned for [1s, 8y]. For a general fixed-point square root use sqrt instead.

Limits & errors

ErrorTrigger
MulDivByZeroErrormulDiv(a, b, d) when d == 0
MulDivOverflowErrormulDiv(a, b, d) when a · b / d ≥ 2256
MulOverflowErrormul(a, b) when a · b / 1e18 ≥ 2256