@@ -206,67 +206,53 @@ library FixedPointMathLib {
206206 /// Note: This function is an approximation. Monotonically increasing.
207207 function expWad (int256 x ) internal pure returns (int256 r ) {
208208 unchecked {
209- // When the result is less than 0.5 we return zero.
210- // This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`.
211- if (x <= - 41446531673892822313 ) return r;
209+ // Accept `-41446531673892822313 < x < 135305999368893231589` with a
210+ // single unsigned comparison; sort out the two edges on the cold path.
211+ if (uint256 (x) + 41446531673892822312 >= 176752531042786053901 ) {
212+ // When the true result is less than 1 wei we return zero.
213+ // This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`.
214+ if (x <= - 41446531673892822313 ) return r;
212215
213- /// @solidity memory-safe-assembly
214- assembly {
215- // When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as
216- // an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`.
217- if iszero ( slt (x, 135305999368893231589 )) {
216+ /// @solidity memory-safe-assembly
217+ assembly {
218+ // When the result is greater than `(2**255 - 1) / 1e18` we can not
219+ // represent it as an int. This happens when
220+ // `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`.
218221 mstore (0x00 , 0xa37bfec9 ) // `ExpOverflow()`.
219222 revert (0x1c , 0x04 )
220223 }
221224 }
222225
223- // `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96`
224- // for more intermediate precision and a binary basis. This base conversion
225- // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
226+ // Convert `x` from `10**18` fixed point to `2**96` fixed point.
226227 x = (x << 78 ) / 5 ** 18 ;
227228
228- // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
229- // of two such that exp(x) = exp(x') * 2**k, where k is an integer.
230- // Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
231- int256 k = ((x << 96 ) / 54916777467707473351141471128 + 2 ** 95 ) >> 96 ;
229+ // Reduce to `x' in (-½ ln 2, ½ ln 2) * 2**96` with `exp(x) = 2**k * exp(x')`.
230+ // `6196328019 = round(2**128 / (ln 2 * 2**96))`; `k` is in the range `[-60, 195]`.
231+ int256 k = (x * 6196328019 + 2 ** 127 ) >> 128 ;
232232 x = x - k * 54916777467707473351141471128 ;
233233
234- // `k` is in the range `[-61, 195]`.
235-
236- // Evaluate using a (6, 7)-term rational approximation.
237- // `p` is made monic, we'll multiply by a scale factor later.
238- int256 y = x + 1346386616545796478920950773328 ;
239- y = ((y * x) >> 96 ) + 57155421227552351082224309758442 ;
240- int256 p = y + x - 94201549194550492254356042504812 ;
241- p = ((p * y) >> 96 ) + 28719021644029726153956944680412240 ;
242- p = p * x + (4385272521454847904659076985693276 << 96 );
243-
244- // We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
245- int256 q = x - 2855989394907223263936484059900 ;
246- q = ((q * x) >> 96 ) + 50020603652535783019961831881945 ;
247- q = ((q * x) >> 96 ) - 533845033583426703283633433725380 ;
248- q = ((q * x) >> 96 ) + 3604857256930695427073651918091429 ;
249- q = ((q * x) >> 96 ) - 14423608567350463180887372962807573 ;
250- q = ((q * x) >> 96 ) + 26449188498355588339934803723976023 ;
234+ // `exp(x') = (E + x' * O) / (E - x' * O)`, a (5, 5)-term symmetric
235+ // rational with `E`, `O` polynomials in `x'^2`. `E` is monic, so its
236+ // single Horner stage needs no `>> 96`: with the constant term
237+ // pre-shifted, `e` and `t` are in `2**192` basis.
238+ int256 u = (x * x) >> 96 ;
239+ int256 e = (u + 8876005618932925505308977557156 ) * u
240+ + (79886213883764523772906264239809 << 96 );
241+ int256 o = ((2639738311906822815584886674 * u) >> 96 ) + 1109410564309688178690540877381 ;
242+ o = ((o * u) >> 96 ) + 39943106941882261691307222498689 ;
243+ int256 t = x * o;
251244
252245 /// @solidity memory-safe-assembly
253246 assembly {
254247 // Div in assembly because solidity adds a zero check despite the unchecked.
255- // The q polynomial won't have zeros in the domain as all its roots are complex.
256- // No scaling is necessary because p is already `2**96` too large.
257- r := sdiv (p, q)
248+ // The denominator is positive on the whole reduced domain.
249+ r := sdiv (add (e, t), sar (96 , sub (e, t)))
258250 }
259251
260- // r should be in the range `(0.09, 0.25) * 2**96`.
261-
262- // We now need to multiply r by:
263- // - The scale factor `s ≈ 6.031367120`.
264- // - The `2**k` factor from the range reduction.
265- // - The `1e18 / 2**96` factor for base conversion.
266- // We do this all at once, with an intermediate result in `2**213`
267- // basis, so the final right shift is always by a positive amount.
252+ // Multiply by `2**k * 1e18 / 2**96`. `r < 1.5 * 2**96`, so the
253+ // product cannot overflow, and the shift amount is never negative.
268254 r = int256 (
269- (uint256 (r) * 3822833074963236453042738258902158003155416615667 ) >> uint256 (195 - k)
255+ (uint256 (r) * 633825300114114700748351602688000000000000000000 ) >> uint256 (195 - k)
270256 );
271257 }
272258 }
@@ -277,11 +263,6 @@ library FixedPointMathLib {
277263 function lnWad (int256 x ) internal pure returns (int256 r ) {
278264 /// @solidity memory-safe-assembly
279265 assembly {
280- // We want to convert `x` from `10**18` fixed point to `2**96` fixed point.
281- // We do this by multiplying by `2**96 / 10**18`. But since
282- // `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here
283- // and add `ln(2**96 / 10**18)` at the end.
284-
285266 // Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`.
286267 r := shl (7 , lt (0xffffffffffffffffffffffffffffffff , x))
287268 r := or (r, shl (6 , lt (0xffffffffffffffff , shr (r, x))))
@@ -301,47 +282,44 @@ library FixedPointMathLib {
301282 // ln(2^k * x) = k * ln(2) + ln(x)
302283 x := shr (159 , shl (r, x))
303284
304- // Evaluate using a (8, 8)-term rational approximation.
305- // `p` is made monic, we will multiply by a scale factor later.
306- // forgefmt: disable-next-item
307- let p := sub ( // This heavily nested expression is to avoid stack-too-deep for via-ir.
308- sar (96 , mul (add (43456485725739037958740375743393 ,
309- sar (96 , mul (add (24828157081833163892658089445524 ,
310- sar (96 , mul (add (3273285459638523848632254066296 ,
311- x), x))), x))), x)), 11111509109440967052023855526967 )
312- p := sub (sar (96 , mul (p, x)), 45023709667254063763336534515857 )
313- p := sub (sar (96 , mul (p, x)), 14706773417378608786704636184526 )
314- p := sub (mul (p, x), shl (96 , 795164235651350426258249787498 ))
315- // We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
316-
317- // `q` is monic by convention.
318- let q := add (5573035233440673466300451813936 , x)
319- q := add (71694874799317883764090561454958 , sar (96 , mul (x, q)))
320- q := add (283447036172924575727196451306956 , sar (96 , mul (x, q)))
321- q := add (401686690394027663651624208769553 , sar (96 , mul (x, q)))
322- q := add (204048457590392012362485061816622 , sar (96 , mul (x, q)))
323- q := add (31853899698501571402653359427138 , sar (96 , mul (x, q)))
324- q := add (909429971244387300277376558375 , sar (96 , mul (x, q)))
325-
326- // `p / q` is in the range `(0, 0.125) * 2**96`.
327-
328- // Finalization, we need to:
329- // - Multiply by the scale factor `s = 5.549…`.
330- // - Add `ln(2**96 / 10**18)`.
331- // - Add `k * ln(2)`.
332- // - Multiply by `10**18 / 2**96 = 5**18 >> 78`.
333-
334- // The q polynomial is known not to have zeros in the domain.
335- // No scaling required because p is already `2**96` too large.
336- p := sdiv (p, q)
337- // Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`.
338- p := mul (1677202110996718588342820967067443963516166 , p)
339- // Add `ln(2) * k * 5**18 * 2**192`.
340- // forgefmt: disable-next-item
341- p := add (mul (16597577552685614221487285958193947469193820559219878177908093499208371 , sub (159 , r)), p)
342- // Add `ln(2**96 / 10**18) * 5**18 * 2**192`.
343- p := add (600920179829731861736702779321621459595472258049074101567377883020018308 , p)
344- // Base conversion: mul `2**18 / 2**192`.
285+ // `s = (x - sqrt(2)) * 2**96 / (x + sqrt(2))`, so that
286+ // `ln(x) = ln(2)/2 + 2 * atanh(s)`.
287+ let s :=
288+ sdiv (
289+ shl (96 , sub (x, 112045541949572279837463876455 )),
290+ add (x, 112045541949572279837463876455 )
291+ )
292+
293+ // `2 * atanh(s) = s * A(w) / B(w)`, a (3, 3)-term odd rational in `w = s^2`.
294+ let w := sar (96 , mul (s, s))
295+ let a :=
296+ add (
297+ sar (96 , mul (sub (w, 1813347344949966953757847210329 ), w)),
298+ 5824670411451500986303020460168
299+ )
300+ a := sub (sar (96 , mul (a, w)), 4518264490991587979207438354337 )
301+ let b :=
302+ sub (
303+ sar (96 , mul (188151507788160136135094921663 , w)),
304+ 1676640319226537252003611223372
305+ )
306+ b := add (sar (96 , mul (b, w)), 3665379287557676720634158507137 )
307+ b := sub (sar (96 , mul (b, w)), 2259132245495793985525851698055 )
308+
309+ // `B` is bounded away from zero on the whole domain.
310+ let p := sdiv (mul (s, a), b)
311+
312+ // Add `(2k + 1) * ln(2)/2` and `ln(2**96 / 10**18)`, then convert to `WAD`,
313+ // all in `5**18 * 2**192` basis.
314+ p := mul (302231454903657293676544000000000000000000 , p)
315+ p := add (
316+ mul (
317+ 8298788776342807110743642979096973734596910279609939088954046749604186 ,
318+ sub (319 , shl (1 , r))
319+ ),
320+ p
321+ )
322+ p := add (600920179829731861736750627322249724520361163382248881493645412721105578 , p)
345323 r := sar (174 , p)
346324 }
347325 }
@@ -428,12 +406,35 @@ library FixedPointMathLib {
428406 int256 t = w | 1 ;
429407 /// @solidity memory-safe-assembly
430408 assembly {
431- x := sdiv (mul (x, wad), t)
432- }
433- x = (t * (wad + lnWad (x)));
434- /// @solidity memory-safe-assembly
435- assembly {
436- w := sdiv (x, add (wad, t))
409+ x := sdiv (add (mul (x, wad), shr (1 , t)), t)
410+ // Inline the `lnWad` core at `2**96` precision, so that the final
411+ // step rounds to nearest regardless of `lnWad`'s wad rounding.
412+ let v := shl (7 , lt (0xffffffffffffffffffffffffffffffff , x))
413+ v := or (v, shl (6 , lt (0xffffffffffffffff , shr (v, x))))
414+ v := or (v, shl (5 , lt (0xffffffff , shr (v, x))))
415+ v := or (v, shl (4 , lt (0xffff , shr (v, x))))
416+ v := or (v, shl (3 , lt (0xff , shr (v, x))))
417+ // forgefmt: disable-next-item
418+ v := xor (v, byte (and (0x1f , shr (shr (v, x), 0x8421084210842108cc6318c6db6d54be )),
419+ 0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff ))
420+ x := shr (159 , shl (v, x))
421+ let s := sdiv (shl (96 , sub (x, 112045541949572279837463876455 )),
422+ add (x, 112045541949572279837463876455 ))
423+ let z := sar (96 , mul (s, s))
424+ let a := add (sar (96 , mul (sub (z, 1813347344949966953757847210329 ), z)),
425+ 5824670411451500986303020460168 )
426+ a := sub (sar (96 , mul (a, z)), 4518264490991587979207438354337 )
427+ let b := sub (sar (96 , mul (188151507788160136135094921663 , z)),
428+ 1676640319226537252003611223372 )
429+ b := add (sar (96 , mul (b, z)), 3665379287557676720634158507137 )
430+ b := sub (sar (96 , mul (b, z)), 2259132245495793985525851698055 )
431+ // `l = ln(x' / 1e18) * 2**96`.
432+ let l := add (sdiv (mul (s, a), b),
433+ add (mul (27458388733853736675570735564 , sub (319 , shl (1 , v))),
434+ 1988278089788132588087242333381 ))
435+ // `w = t * (2**96 + l) * 1e18 / (2**96 * (1e18 + t))`, rounded to nearest.
436+ let d := mul (shl (96 , 1 ), add (wad, t))
437+ w := sdiv (add (mul (mul (t, add (shl (96 , 1 ), l)), wad), shr (1 , d)), d)
437438 }
438439 }
439440 }
0 commit comments