-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathMath.move
155 lines (138 loc) · 4.49 KB
/
Math.move
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
address StarcoinFramework {
/// The module provide some improved math calculations.
module Math {
use StarcoinFramework::Vector;
// TODO: verify the module.
spec module {
pragma verify = false;
pragma aborts_if_is_strict;
}
const U64_MAX:u64 = 18446744073709551615;
const U128_MAX:u128 = 340282366920938463463374607431768211455;
/// u64::MAX
public fun u64_max(): u64 {
U64_MAX
}
/// u128::MAX
public fun u128_max(): u128 {
U128_MAX
}
/// babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
public fun sqrt(y: u128): u64 {
if (y < 4) {
if (y == 0) {
0u64
} else {
1u64
}
} else {
let z = y;
let x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
};
(z as u64)
}
}
spec sqrt {
pragma opaque = true;
pragma verify = false; //while loop
aborts_if [abstract] false;
ensures [abstract] result == spec_sqrt();
}
/// We use an uninterpreted function to represent the result of sqrt. The actual value
/// does not matter for the verification of callers.
spec fun spec_sqrt(): u128;
/// calculate the `y` pow of `x`.
public fun pow(x: u64, y: u64): u128 {
let result = 1u128;
let z = y;
let u = (x as u128);
while (z > 0) {
if (z % 2 == 1) {
result = (u * result as u128);
};
u = (u * u as u128);
z = z / 2;
};
result
}
spec pow {
pragma opaque = true;
pragma verify = false; //while loop
aborts_if [abstract] false;
ensures [abstract] result == spec_pow();
}
/// We use an uninterpreted function to represent the result of pow. The actual value
/// does not matter for the verification of callers.
spec fun spec_pow(): u128;
/// https://medium.com/coinmonks/math-in-solidity-part-3-percents-and-proportions-4db014e080b1
/// calculate x * y /z with as little loss of precision as possible and avoid overflow
public fun mul_div(x: u128, y: u128, z: u128): u128 {
if (y == z) {
return x
};
if (x == z) {
return y
};
let a = x / z;
let b = x % z;
//x = a * z + b;
let c = y / z;
let d = y % z;
//y = c * z + d;
a * c * z + a * d + b * c + b * d / z
}
spec mul_div {
pragma opaque = true;
include MulDivAbortsIf;
aborts_if [abstract] false;
ensures [abstract] result == spec_mul_div();
}
spec schema MulDivAbortsIf {
x: u128;
y: u128;
z: u128;
aborts_if y != z && x > z && z == 0;
aborts_if y != z && x > z && z!=0 && x/z*y > MAX_U128;
aborts_if y != z && x <= z && z == 0;
//a * b overflow
aborts_if y != z && x <= z && x / z * (x % z) > MAX_U128;
//a * b * z overflow
aborts_if y != z && x <= z && x / z * (x % z) * z > MAX_U128;
//a * d overflow
aborts_if y != z && x <= z && x / z * (y % z) > MAX_U128;
//a * b * z + a * d overflow
aborts_if y != z && x <= z && x / z * (x % z) * z + x / z * (y % z) > MAX_U128;
//b * c overflow
aborts_if y != z && x <= z && x % z * (y / z) > MAX_U128;
//b * d overflow
aborts_if y != z && x <= z && x % z * (y % z) > MAX_U128;
//b * d / z overflow
aborts_if y != z && x <= z && x % z * (y % z) / z > MAX_U128;
//a * b * z + a * d + b * c overflow
aborts_if y != z && x <= z && x / z * (x % z) * z + x / z * (y % z) + x % z * (y / z) > MAX_U128;
//a * b * z + a * d + b * c + b * d / z overflow
aborts_if y != z && x <= z && x / z * (x % z) * z + x / z * (y % z) + x % z * (y / z) + x % z * (y % z) / z > MAX_U128;
}
spec fun spec_mul_div(): u128;
/// calculate sum of nums
public fun sum(nums: &vector<u128>): u128 {
let len = Vector::length(nums);
let i = 0;
let sum = 0;
while (i < len){
sum = sum + *Vector::borrow(nums, i);
i = i + 1;
};
sum
}
/// calculate average of nums
public fun avg(nums: &vector<u128>): u128{
let len = Vector::length(nums);
let sum = sum(nums);
sum/(len as u128)
}
}
}