1 | """
|
2 | Math operations, e.g. for arbitrary precision integers
|
3 |
|
4 | They are currently int64_t, rather than C int, but we want to upgrade to
|
5 | heap-allocated integers.
|
6 |
|
7 | Regular int ops can use the normal operators + - * /, or maybe i_add() if we
|
8 | really want. Does that make code gen harder or worse?
|
9 |
|
10 | Float ops could be + - * / too, but it feels nicer to develop a formal
|
11 | interface?
|
12 | """
|
13 | from __future__ import print_function
|
14 |
|
15 |
|
16 | class BigInt(object):
|
17 |
|
18 | def __init__(self, i):
|
19 | # type: (int) -> None
|
20 | self.i = i
|
21 |
|
22 | def __eq__(self, other):
|
23 | # type: (object) -> bool
|
24 |
|
25 | # Disabled check
|
26 | # Prevent possible mistakes. Could do this with other operators
|
27 | # raise AssertionError('Use mops.Equal()')
|
28 |
|
29 | if not isinstance(other, BigInt):
|
30 | raise AssertionError()
|
31 |
|
32 | # Used for hashing
|
33 | return self.i == other.i
|
34 |
|
35 | def __gt__(self, other):
|
36 | # type: (object) -> bool
|
37 | raise AssertionError('Use functions in mops.py')
|
38 |
|
39 | def __ge__(self, other):
|
40 | # type: (object) -> bool
|
41 | raise AssertionError('Use functions in mops.py')
|
42 |
|
43 | def __hash__(self):
|
44 | # type: () -> int
|
45 | """For dict lookups."""
|
46 | return hash(self.i)
|
47 |
|
48 |
|
49 | ZERO = BigInt(0)
|
50 | ONE = BigInt(1)
|
51 | MINUS_ONE = BigInt(-1)
|
52 | MINUS_TWO = BigInt(-2) # for printf
|
53 |
|
54 |
|
55 | def ToStr(b):
|
56 | # type: (BigInt) -> str
|
57 | return str(b.i)
|
58 |
|
59 |
|
60 | def ToOctal(b):
|
61 | # type: (BigInt) -> str
|
62 | return '%o' % b.i
|
63 |
|
64 |
|
65 | def ToHexUpper(b):
|
66 | # type: (BigInt) -> str
|
67 | return '%X' % b.i
|
68 |
|
69 |
|
70 | def ToHexLower(b):
|
71 | # type: (BigInt) -> str
|
72 | return '%x' % b.i
|
73 |
|
74 |
|
75 | def FromStr(s, base=10):
|
76 | # type: (str, int) -> BigInt
|
77 | return BigInt(int(s, base))
|
78 |
|
79 |
|
80 | def BigTruncate(b):
|
81 | # type: (BigInt) -> int
|
82 | """Only truncates in C++"""
|
83 | return b.i
|
84 |
|
85 |
|
86 | def IntWiden(i):
|
87 | # type: (int) -> BigInt
|
88 | """Only widens in C++"""
|
89 | return BigInt(i)
|
90 |
|
91 |
|
92 | def FromC(i):
|
93 | # type: (int) -> BigInt
|
94 | """A no-op in C, for RLIM_INFINITY"""
|
95 | return BigInt(i)
|
96 |
|
97 |
|
98 | def FromBool(b):
|
99 | # type: (bool) -> BigInt
|
100 | """Only widens in C++"""
|
101 | return BigInt(1) if b else BigInt(0)
|
102 |
|
103 |
|
104 | def ToFloat(b):
|
105 | # type: (BigInt) -> float
|
106 | """Used by float(42) in Oils"""
|
107 | return float(b.i)
|
108 |
|
109 |
|
110 | def FromFloat(f):
|
111 | # type: (float) -> BigInt
|
112 | """Used by int(3.14) in Oils"""
|
113 | return BigInt(int(f))
|
114 |
|
115 |
|
116 | # Can't use operator overloading
|
117 |
|
118 |
|
119 | def Negate(b):
|
120 | # type: (BigInt) -> BigInt
|
121 | return BigInt(-b.i)
|
122 |
|
123 |
|
124 | def Add(a, b):
|
125 | # type: (BigInt, BigInt) -> BigInt
|
126 | return BigInt(a.i + b.i)
|
127 |
|
128 |
|
129 | def Sub(a, b):
|
130 | # type: (BigInt, BigInt) -> BigInt
|
131 | return BigInt(a.i - b.i)
|
132 |
|
133 |
|
134 | def Mul(a, b):
|
135 | # type: (BigInt, BigInt) -> BigInt
|
136 | return BigInt(a.i * b.i)
|
137 |
|
138 |
|
139 | def Div(a, b):
|
140 | # type: (BigInt, BigInt) -> BigInt
|
141 | """
|
142 | Divide, for positive integers only
|
143 |
|
144 | Question: does Oils behave like C remainder when it's positive? Then we
|
145 | could be more efficient with a different layering?
|
146 | """
|
147 | assert a.i >= 0 and b.i >= 0, (a.i, b.i)
|
148 | return BigInt(a.i // b.i)
|
149 |
|
150 |
|
151 | def Rem(a, b):
|
152 | # type: (BigInt, BigInt) -> BigInt
|
153 | """
|
154 | Remainder, for positive integers only
|
155 | """
|
156 | assert a.i >= 0 and b.i >= 0, (a.i, b.i)
|
157 | return BigInt(a.i % b.i)
|
158 |
|
159 |
|
160 | def Equal(a, b):
|
161 | # type: (BigInt, BigInt) -> bool
|
162 | return a.i == b.i
|
163 |
|
164 |
|
165 | def Greater(a, b):
|
166 | # type: (BigInt, BigInt) -> bool
|
167 | return a.i > b.i
|
168 |
|
169 |
|
170 | # GreaterEq, Less, LessEq can all be expressed as the 2 ops above
|
171 |
|
172 |
|
173 | def LShift(a, b):
|
174 | # type: (BigInt, BigInt) -> BigInt
|
175 | """
|
176 | Any semantic issues here? Signed left shift
|
177 | """
|
178 | return BigInt(a.i << b.i)
|
179 |
|
180 |
|
181 | def RShift(a, b):
|
182 | # type: (BigInt, BigInt) -> BigInt
|
183 | return BigInt(a.i >> b.i)
|
184 |
|
185 |
|
186 | def BitAnd(a, b):
|
187 | # type: (BigInt, BigInt) -> BigInt
|
188 | return BigInt(a.i & b.i)
|
189 |
|
190 |
|
191 | def BitOr(a, b):
|
192 | # type: (BigInt, BigInt) -> BigInt
|
193 | return BigInt(a.i | b.i)
|
194 |
|
195 |
|
196 | def BitXor(a, b):
|
197 | # type: (BigInt, BigInt) -> BigInt
|
198 | return BigInt(a.i ^ b.i)
|
199 |
|
200 |
|
201 | def BitNot(a):
|
202 | # type: (BigInt) -> BigInt
|
203 | return BigInt(~a.i)
|