templates.fixed_precision

 1# Fixed precision computations - Example for illustrative purposes only.
 2
 3import smartpy as sp
 4
 5
 6"""
 7This has been inspired by
 8
 9https://github.com/Sophia-Gold/michelson/blob/master/log2fix.tz
10
11http://www.claysturner.com/dsp/BinaryLogarithm.pdf
12
131) Initialize result to 0: y = 0.
142)Initialize mantissa-bit decimal value to 0.5: b = 1/2.
15
163) While x < 1, x = 2x, y = y - 1.
174) While x >= 2, x = x/2, y = y + 1.
18
196)Square: x = x * x.
207) If x > 2, x = x/2, y = y + b.
218) Scale for next bit: b = b/2.
229)Go to Step 6 and repeat until desired number of mantissa bits are found.
23
2410) Final log(x) value: y.
25"""
26
27
28@sp.module
29def main():
30    class MyContract(sp.Contract):
31        def __init__(self, precision):
32            self.private.precision = sp.cast(precision, sp.nat)
33            self.data.value = 0
34
35        @sp.entrypoint
36        def log(self, params):
37            assert params != 0
38            y = 0
39            x = params
40            while x < 1 << self.private.precision:
41                x <<= 1
42                y -= sp.to_int(1 << self.private.precision)
43            while x >= 2 << self.private.precision:
44                x >>= 1
45                y += sp.to_int(1 << self.private.precision)
46            b = 1 << sp.as_nat(self.private.precision - 1)
47            while 0 < b:
48                x = (x * x) >> self.private.precision
49                if x > 2 << self.private.precision:
50                    x >>= 1
51                    y += sp.to_int(b)
52                b >>= 1
53            self.data.value = y
54
55
56def direct(x, precision):
57    import math
58
59    return int((math.log(x / (1 << precision)) / math.log(2)) * (1 << precision))
60
61
62@sp.add_test()
63def test():
64    scenario = sp.test_scenario("FixedPrecision", main)
65    scenario.h1("Fixed Precision Computations")
66    c1 = main.MyContract(precision=16)
67    scenario += c1
68
69    def check_ok(scenario, n):
70        d = direct(n, 16)
71        scenario.h3("Computing log(%i / 65536)" % n)
72        scenario.p("Direct computation %i" % direct(n, 16))
73        c1.log(n)
74        scenario.verify(abs(c1.data.value - d) < 2)
75
76    check_ok(scenario, 1000000)
77    check_ok(scenario, 65535)
78    check_ok(scenario, 65536)
79    check_ok(scenario, 65537)
80    check_ok(scenario, 131071)
81    check_ok(scenario, 131072)
82    check_ok(scenario, 131073)
83    check_ok(scenario, 1)
def direct(x, precision):
57def direct(x, precision):
58    import math
59
60    return int((math.log(x / (1 << precision)) / math.log(2)) * (1 << precision))