Try   HackMD

Logarithm Approximation Precision

This cosument formally proves maximum absolute errors of approximated logarithm calculation to be used in Uniswap v2 protocol.

Base-2 Logarithm Approximation

We approximate base-2 logarithm iteratively. Initial approximation for

log2x is defined like this:

l0(x)=log2x

So the initial approximation is just the logarithm rounded down, i.e. towards

. The absolute error of the initial approximation is bounded like this:

ε0(x)=l0(x)log2x(1;+0]

Every next approximation is defined like this:

li+1(x)=log2x+12li((x2log2x2127)22127)

Here

ab means
a
rounded down to the closest factor of
b
.

The absolute error of this approximation is:

εi+1(x)=li+1log2x==log2x+12li((x2log2x2127)22127)log2(2log2xx2log2x)==log2x+12li((x2log2x2127)22127)log2xlog2x2log2x==12li((x2log2x2127)22127)log2x2log2x==12li((x2log2x2127)22127)12log2(x2log2x)2==12(li((x2log2x2127)22127)log2(x2log2x)2)

Let's note, that

log2x1<log2xlog2x

thus

2log2x1<2log2x2log2x

then

x2<2log2xx

and finally:

x2log2x[1;2)

Let's pick

α such that

x2log2x2127=x2log2x(1α)

α=x2log2xx2log2x2127x2log2x[0;2127)

Let's pick

β such that

(x2log2x2127)22127=(x2log2x2127)2(1β)

β=(x2log2x2127)2(x2log2x2127)22127(x2log2x2127)2[0;2127)

Now we have:

εi+1(x)===12(li((x2log2x(1α))2(1β))log2(x2log2x)2)==12(li((x2log2x)2(1α)2(1β))log2((x2log2x)2(1α)2(1β))++log2((1α)2(1β)))==12(εi((x2log2x2127)22127)+log2((1α)2(1β)))==12(εi((x2log2x2127)22127)+2log2(1α)+log2(1β))(12minεi+32log2(12127);+0]==(2(i+1)+3(12(i+1))log2(12127);0]

Base-1.01 Logarithm Approximation

We approximate base-1.01 logarithm

log1.01x like this:

log1.01xξli(x)

Where

ξ=1285013416526911433821264>1log21.01. The error of such approximation is:

ξli(x)log1.01x==ξ(log2x+εi(x))log2xlog21.01==log2x(ξ1log21.01)+ξεi(x)

For

x[2112;2112) the approximation error is within the following range:

(112(ξ1log21.01)+ξ(2i+3(12i)log2(12127));112(ξ1log21.01))

Base-
1.0001
Logarithm Approximation

We approximate base-

1.0001 logarithm
log1.0001x
like this:

log1.0001xψli(x)

Where

ψ=255738958999603826347141264>1log21.0001. The error of such approximation is:

ψli(x)log1.0001x==ψ(log2x+εi(x))log2xlog21.0001==log2x(ψ1log21.0001)+ψεi(x)

For

x[264;264) the approximation error is within the following range:

(64(ψ1log21.0001)+ψ(2i+3(12i)log2(12127));64(ψ1log21.0001))

Approximation of
getRatioAtTick1
(normal ticks)

Function

getRatioAtTick(x) approximates
1.01x
with relative pricision not worse than
0.01%
. Thus:

getRatioAtTick(x)=γ(x)1.01x

where

γ(x)[0.9999;1.0001]. By inverting this function we have:

getRatioAtTick1(x)=log1.01xγ(y)=log1.01xlog1.01γ(y)

Here

y is some number. Note, that while actual
getRatioAtTick(x)
function may be calculated only for integer arguments, we assume that it is consinuously and strictly-monotonically defined for all real numbers. This assumtion allows us to consider inverse function
getRatioAtTick1(x)
to be defined for all positive arguments.

We approximate the inverse function

getRatioAtTick1(x) like this:

log1.01xlog1.01γ(y)ξli(x)

The absoulte error of such approximation is:

ξli(x)log1.01x+log1.01γ(y)

For

x[2112;2112) the error is within the following range:

(112(ξ1log21.01)++ξ(2i+3(12i)log2(12127))++log1.010.9999;112(ξ1log21.01)+log1.011.0001)

Here

112(ξ1log21.01) and
112(ξ1log21.01)
are contributed by the imperfection of
ξ
value;
ξ(2i)
is contributed by the finity of
i
;
ξ3(12i)log2(12127)
is contributed by the rounding errors inside the approximation algorithm implementation (the implementation uses 129.127-bit binary fixed point numbers, thus
2127
thing); finally
log1.010.9999
and
log1.011.0001
are contributed by the imperfection of
getRatioAtTick
implementation.

Approximation of
getRatioAtTick1
(fine ticks)

Function

getRatioAtTick(x) approximates
1.0001x
with relative pricision not worse than
0.00005%
. Thus:

getRatioAtTick(x)=γ(x)1.0001x

where

γ(x)[0.9999995;1.0000005]. By inverting this function we have:

getRatioAtTick1(x)=log1.0001xγ(y)=log1.0001xlog1.0001γ(y)

Here

y is some number. Note, that while actual
getRatioAtTick(x)
function may be calculated only for integer arguments, we assume that it is consinuously and strictly-monotonically defined for all real numbers. This assumtion allows us to consider inverse function
getRatioAtTick1(x)
to be defined for all positive arguments.

We approximate the inverse function

getRatioAtTick1(x) like this:

log1.0001xlog1.0001γ(y)ψli(x)

The absoulte error of such approximation is:

ψli(x)log1.0001x+log1.0001γ(y)

For

x[264;264) the error is within the following range:

(64(ψ1log21.0001)++ψ(2i+3(12i)log2(12127))++log1.00010.9999995;64(ψ1log21.0001)+log1.00011.0000005)

Here

64(ψ1log21.0001) and
64(ψ1log21.0001)
are contributed by the imperfection of
ψ
value;
ψ(2i)
is contributed by the finity of
i
;
ψ3(12i)log2(12127)
is contributed by the rounding errors inside the approximation algorithm implementation (the implementation uses 129.127-bit binary fixed point numbers, thus
2127
thing); finally
log1.00010.9999995
and
log1.00011.0000005
are contributed by the imperfection of
getRatioAtTick
implementation.

Choosing The Right
i
(normal ticks)

What we need is to calculate for given positive value

y the maximum integer
x
such that
getRatioAtTick(x)y
. Basically we need to solve the following inequation in integer numbers:

getRatioAtTick(x)y<getRatioAtTick(x+1)

or

xgetRatioAtTick1(y)<x+1

Thus:

x=getRatioAtTick1(y)

Once we know, that

getRatioAtTick1(y)[xmin;xmax], then
x[xmin;xmax]
. When
xmaxxmin<1
there are at most two integer values fitting into range
[xmin;xmax]
, thus the right value could be chosen by calling
getRatioAtTick
function at most once.

The following table gives possible ranges of absolute approximation error

ε of
getRatioAtTick1(y)
for
i{0,,10}
:

i
minε
maxε
P
0
69.68
0.01005
1
34.85
0.01005
2
17.43
0.01005
3
8.718
0.01005
4
4.364
0.01005
5
2.187
0.01005
6
1.099
0.01005
7
0.5543
0.01005
57%
8
0.2822
0.01005
30%
9
0.1462
0.01005
16%
10
0.07808
0.01005
9%

For

i7 at most one call to
getRatioAtTick
is needed to return bit-perfect
getRatioAtTick1x
value. The probability
P
of
getRatioAtTick
call is shown in the last column.

Choosing The Right
i
(fine ticks)

What we need is to calculate for given positive value

y the maximum integer
x
such that
getRatioAtTick(x)y
. Basically we need to solve the following inequation in integer numbers:

getRatioAtTick(x)y<getRatioAtTick(x+1)

or

xgetRatioAtTick1(y)<x+1

Thus:

x=getRatioAtTick1(y)

Once we know, that

getRatioAtTick1(y)[xmin;xmax], then
x[xmin;xmax]
. When
xmaxxmin<1
there are at most two integer values fitting into range
[xmin;xmax]
, thus the right value could be chosen by calling
getRatioAtTick
function at most once.

The following table gives possible ranges of absolute approximation error

ε of
getRatioAtTick1(y)
for
i{0,,20}
:

i
minε
maxε
P
0
13863.6
0.0100005
1
6931.83
0.0100005
2
3465.92
0.0100005
3
1732.96
0.0100005
4
866.487
0.0100005
5
433.249
0.0100005
6
216.629
0.0100005
7
108.32
0.0100005
8
54.1648
0.0100005
9
27.0874
0.0100005
10
13.5487
0.0100005
11
6.77935
0.0100005
12
3.39468
0.0100005
13
1.70234
0.0100005
14
0.85617
0.0100005
86%
15
0.433085
0.0100005
44%
16
0.221543
0.0100005
23%
17
0.115772
0.0100005
12%
18
0.0628861
0.0100005
7%
19
0.0364433
0.0100005
4%
20
0.0232219
0.0100005
3%

For

i14 at most one call to
getRatioAtTick
is needed to return bit-perfect
getRatioAtTick1x
value. The probability
P
of
getRatioAtTick
call is shown in the last column.