-
Notifications
You must be signed in to change notification settings - Fork 18
/
FractionMath.py
166 lines (133 loc) · 4.71 KB
/
FractionMath.py
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
156
157
158
159
160
161
162
163
164
165
166
from .common.BuiltIn import *
from .common.Uint256 import *
from . import IntegralMath
MAX_EXP_BIT_LEN = 4;
MAX_EXP = 2 ** MAX_EXP_BIT_LEN - 1;
MAX_UINT128 = 2 ** 128 - 1;
'''
@dev Compute the power of a given ratio while opting for accuracy over performance
@param n The ratio numerator
@param d The ratio denominator
@param exp The exponentiation value
@return The powered ratio numerator
@return The powered ratio denominator
'''
def poweredRatioExact(n, d, exp):
return poweredRatio(n, d, exp, productRatio);
'''
@dev Compute the power of a given ratio while opting for performance over accuracy
@param n The ratio numerator
@param d The ratio denominator
@param exp The exponentiation value
@return The powered ratio numerator
@return The powered ratio denominator
'''
def poweredRatioQuick(n, d, exp):
return poweredRatio(n, d, exp, mulRatio128);
'''
@dev Compute the product of two given ratios
@param xn The 1st ratio numerator
@param yn The 2nd ratio numerator
@param xd The 1st ratio denominator
@param yd The 2nd ratio denominator
@return The product ratio numerator
@return The product ratio denominator
'''
def productRatio(xn, yn, xd, yd):
n = IntegralMath.minFactor(xn, yn);
d = IntegralMath.minFactor(xd, yd);
z = n if n > d else d;
return (IntegralMath.mulDivC(xn, yn, z), IntegralMath.mulDivC(xd, yd, z));
'''
@dev Reduce the components of a given ratio to fit up to a given threshold
@param n The ratio numerator
@param d The ratio denominator
@param cap The desired threshold
@return The reduced ratio numerator
@return The reduced ratio denominator
'''
def reducedRatio(n, d, cap):
if (n < d):
(n, d) = reducedRatioCalc(n, d, cap);
else:
(d, n) = reducedRatioCalc(d, n, cap);
return (n, d);
'''
@dev Normalize the components of a given ratio to sum up to a given scale
@param n The ratio numerator
@param d The ratio denominator
@param scale The desired scale
@return The normalized ratio numerator
@return The normalized ratio denominator
'''
def normalizedRatio(n, d, scale):
if (n < d):
(n, d) = normalizedRatioCalc(n, d, scale);
else:
(d, n) = normalizedRatioCalc(d, n, scale);
return (n, d);
'''
@dev Compute the power of a given ratio
@param n The ratio numerator
@param d The ratio denominator
@param exp The exponentiation value
@param safeRatio The computing function
@return The powered ratio numerator
@return The powered ratio denominator
'''
def poweredRatio(n, d, exp, safeRatio):
require(exp <= MAX_EXP, "exp too large");
ns = [0] * MAX_EXP_BIT_LEN;
ds = [0] * MAX_EXP_BIT_LEN;
(ns[0], ds[0]) = safeRatio(n, 1, d, 1);
for i in range(len(bin(exp)) - 3):
(ns[i + 1], ds[i + 1]) = safeRatio(ns[i], ns[i], ds[i], ds[i]);
n = 1;
d = 1;
for i in range(len(bin(exp)) - 2):
if (((exp >> i) & 1) > 0):
(n, d) = safeRatio(n, ns[i], d, ds[i]);
return (n, d);
'''
@dev Reduce the components of a given ratio to fit up to a given threshold,
under the implicit assumption that the ratio is smaller than or equal to 1
@param n The ratio numerator
@param d The ratio denominator
@param cap The desired threshold
@return The reduced ratio numerator
@return The reduced ratio denominator
'''
def reducedRatioCalc(n, d, cap):
if (d > cap):
n = IntegralMath.mulDivR(n, cap, d);
d = cap;
return (n, d);
'''
@dev Normalize the components of a given ratio to sum up to a given scale,
under the implicit assumption that the ratio is smaller than or equal to 1
@param n The ratio numerator
@param d The ratio denominator
@param scale The desired scale
@return The normalized ratio numerator
@return The normalized ratio denominator
'''
def normalizedRatioCalc(n, d, scale):
if (n > MAX_VAL - d):
x = unsafeAdd(n, d) + 1;
y = IntegralMath.mulDivF(x, n // 2, n // 2 + d // 2);
n -= y;
d -= x - y;
z = IntegralMath.mulDivR(scale, n, n + d);
return(z, scale - z);
'''
@dev Compute the product of two ratios and reduce the components of the result to 128 bits,
under the implicit assumption that the components of the product are not larger than 256 bits
@param xn The 1st ratio numerator
@param yn The 2nd ratio numerator
@param xd The 1st ratio denominator
@param yd The 2nd ratio denominator
@return The product ratio numerator
@return The product ratio denominator
'''
def mulRatio128(xn, yn, xd, yd):
return reducedRatio(xn * yn, xd * yd, MAX_UINT128);