-
Notifications
You must be signed in to change notification settings - Fork 13
/
math-fixed-point.clar
136 lines (123 loc) · 2.95 KB
/
math-fixed-point.clar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
;; math-fixed-point
;; Fixed Point Math
;; following https://github.com/balancer-labs/balancer-monorepo/blob/master/pkg/solidity-utils/contracts/math/FixedPoint.sol
;; constants
;;
(define-constant ONE_8 (pow u10 u8)) ;; 8 decimal places
;; With 8 fixed digits you would have a maximum error of 0.5 * 10^-8 in each entry,
;; which could aggregate to about 8 x 0.5 * 10^-8 = 4 * 10^-8 relative error
;; (i.e. the last digit of the result may be completely lost to this error).
(define-constant MAX_POW_RELATIVE_ERROR u4)
(define-constant TOLERANCE_CONSTANT u10000)
;; public functions
;;
;; @desc get_one
;; @returns (response uint)
(define-read-only (get_one)
(ok ONE_8)
)
;; @desc scale-up
;; @params a
;; @returns uint
(define-read-only (scale-up (a uint))
(* a ONE_8)
)
;; @desc scale-down
;; @params a
;; @returns uint
(define-read-only (scale-down (a uint))
(/ a ONE_8)
)
;; @desc mul-down
;; @params a
;; @params b
;; @returns uint
(define-read-only (mul-down (a uint) (b uint))
(/ (* a b) ONE_8)
)
;; @desc mul-up
;; @params a
;; @params b
;; @returns uint
(define-read-only (mul-up (a uint) (b uint))
(let
(
(product (* a b))
)
(if (is-eq product u0)
u0
(+ u1 (/ (- product u1) ONE_8))
)
)
)
;; @desc div-down
;; @params a
;; @params b
;; @returns uint
(define-read-only (div-down (a uint) (b uint))
(if (is-eq a u0)
u0
(/ (* a ONE_8) b)
)
)
;; @desc div-up
;; @params a
;; @params b
;; @returns uint
(define-read-only (div-up (a uint) (b uint))
(if (is-eq a u0)
u0
(+ u1 (/ (- (* a ONE_8) u1) b))
)
)
;; @desc pow-down
;; @params a
;; @params b
;; @returns uint
(define-read-only (pow-down (a uint) (b uint))
(let
(
(raw (unwrap-panic (contract-call? .math-log-exp pow-fixed a b)))
(max-error (+ u1 (mul-up raw MAX_POW_RELATIVE_ERROR)))
)
;;(if (>= a ONE_8) (round-for-up raw TOLERANCE_CONSTANT)
(if (< raw max-error)
u0
(- raw max-error)
)
;;)
)
)
;; @desc pow-up
;; @params a
;; @params b
;; @returns uint
(define-read-only (pow-up (a uint) (b uint))
(let
(
(raw (unwrap-panic (contract-call? .math-log-exp pow-fixed a b)))
(max-error (+ u1 (mul-up raw MAX_POW_RELATIVE_ERROR)))
)
(+ raw max-error)
;;(if (>= a ONE_8) (round-for-up raw TOLERANCE_CONSTANT) (+ raw max-error))
)
)
;; TODO : Precision for 6 Decimals should be introduced later on.
;; @desc round-for-up
;; @params a
;; @params tolerance
;; @returns (response uint)
(define-read-only (round-for-up (a uint) (tolerance uint))
(begin
(if (is-eq (mod a tolerance) u0) (ok a)
(let
(
(divided (/ a tolerance))
(new-value (+ divided u1))
(rounded (* new-value tolerance))
)
(ok rounded)
)
)
)
)