OILS / mycpp / mops.py View on Github | oilshell.org

239 lines, 100 significant
1"""
2Math operations, e.g. for arbitrary precision integers
3
4They are currently int64_t, rather than C int, but we want to upgrade to
5heap-allocated integers.
6
7Regular int ops can use the normal operators + - * /, or maybe i_add() if we
8really want. Does that make code gen harder or worse?
9
10Float ops could be + - * / too, but it feels nicer to develop a formal
11interface?
12"""
13from __future__ import print_function
14
15from typing import Tuple
16
17
18class BigInt(object):
19
20 def __init__(self, i):
21 # type: (int) -> None
22 self.i = i
23
24 def __eq__(self, other):
25 # type: (object) -> bool
26
27 # Disabled check
28 # Prevent possible mistakes. Could do this with other operators
29 # raise AssertionError('Use mops.Equal()')
30
31 if not isinstance(other, BigInt):
32 raise AssertionError()
33
34 # Used for hashing
35 return self.i == other.i
36
37 def __gt__(self, other):
38 # type: (object) -> bool
39 raise AssertionError('Use functions in mops.py')
40
41 def __ge__(self, other):
42 # type: (object) -> bool
43 raise AssertionError('Use functions in mops.py')
44
45 def __hash__(self):
46 # type: () -> int
47 """For dict lookups."""
48 return hash(self.i)
49
50
51ZERO = BigInt(0)
52ONE = BigInt(1)
53MINUS_ONE = BigInt(-1)
54MINUS_TWO = BigInt(-2) # for printf
55
56
57def ToStr(b):
58 # type: (BigInt) -> str
59 return str(b.i)
60
61
62def ToOctal(b):
63 # type: (BigInt) -> str
64 return '%o' % b.i
65
66
67def ToHexUpper(b):
68 # type: (BigInt) -> str
69 return '%X' % b.i
70
71
72def ToHexLower(b):
73 # type: (BigInt) -> str
74 return '%x' % b.i
75
76
77def FromStr(s, base=10):
78 # type: (str, int) -> BigInt
79 return BigInt(int(s, base))
80
81
82def BigTruncate(b):
83 # type: (BigInt) -> int
84 """Only truncates in C++"""
85 return b.i
86
87
88def IntWiden(i):
89 # type: (int) -> BigInt
90 """Only widens in C++"""
91 return BigInt(i)
92
93
94def FromC(i):
95 # type: (int) -> BigInt
96 """A no-op in C, for RLIM_INFINITY"""
97 return BigInt(i)
98
99
100def FromBool(b):
101 # type: (bool) -> BigInt
102 """Only widens in C++"""
103 return BigInt(1) if b else BigInt(0)
104
105
106def ToFloat(b):
107 # type: (BigInt) -> float
108 """Used by float(42) in Oils"""
109 return float(b.i)
110
111
112def FromFloat(f):
113 # type: (float) -> Tuple[bool, BigInt]
114 """Used by int(3.14) in Oils"""
115 try:
116 big = int(f)
117 except ValueError: # NAN
118 return False, MINUS_ONE
119 except OverflowError: # INFINITY
120 return False, MINUS_ONE
121 return True, BigInt(big)
122
123
124# Can't use operator overloading
125
126
127def Negate(b):
128 # type: (BigInt) -> BigInt
129 return BigInt(-b.i)
130
131
132def Add(a, b):
133 # type: (BigInt, BigInt) -> BigInt
134 return BigInt(a.i + b.i)
135
136
137def Sub(a, b):
138 # type: (BigInt, BigInt) -> BigInt
139 return BigInt(a.i - b.i)
140
141
142def Mul(a, b):
143 # type: (BigInt, BigInt) -> BigInt
144 return BigInt(a.i * b.i)
145
146
147def Div(a, b):
148 # type: (BigInt, BigInt) -> BigInt
149 """Integer division.
150
151 Oils rounds toward zero.
152
153 Python rounds toward negative infinity, while C++ rounds toward zero. We
154 have to work around Python a bit.
155 """
156 assert b.i != 0, b.i # divisor can't be zero -- caller checks
157
158 # Only use Python // on non-negative numbers. Apply sign afterward.
159 sign = 1
160
161 if a.i < 0:
162 pa = -a.i
163 sign = -1
164 else:
165 pa = a.i
166
167 if b.i < 0:
168 pb = -b.i
169 sign = -sign
170 else:
171 pb = b.i
172
173 return BigInt(sign * (pa // pb))
174
175
176def Rem(a, b):
177 # type: (BigInt, BigInt) -> BigInt
178 """Integer remainder."""
179 assert b.i != 0, b.i # YSH divisor must be positive, but OSH can be negative
180
181 # Only use Python % on non-negative numbers. Apply sign afterward.
182 if a.i < 0:
183 pa = -a.i
184 sign = -1
185 else:
186 pa = a.i
187 sign = 1
188
189 if b.i < 0:
190 pb = -b.i
191 else:
192 pb = b.i
193
194 return BigInt(sign * (pa % pb))
195
196
197def Equal(a, b):
198 # type: (BigInt, BigInt) -> bool
199 return a.i == b.i
200
201
202def Greater(a, b):
203 # type: (BigInt, BigInt) -> bool
204 return a.i > b.i
205
206
207# GreaterEq, Less, LessEq can all be expressed as the 2 ops above
208
209
210def LShift(a, b):
211 # type: (BigInt, BigInt) -> BigInt
212 assert b.i >= 0, b.i # Must be checked by caller
213 return BigInt(a.i << b.i)
214
215
216def RShift(a, b):
217 # type: (BigInt, BigInt) -> BigInt
218 assert b.i >= 0, b.i # Must be checked by caller
219 return BigInt(a.i >> b.i)
220
221
222def BitAnd(a, b):
223 # type: (BigInt, BigInt) -> BigInt
224 return BigInt(a.i & b.i)
225
226
227def BitOr(a, b):
228 # type: (BigInt, BigInt) -> BigInt
229 return BigInt(a.i | b.i)
230
231
232def BitXor(a, b):
233 # type: (BigInt, BigInt) -> BigInt
234 return BigInt(a.i ^ b.i)
235
236
237def BitNot(a):
238 # type: (BigInt) -> BigInt
239 return BigInt(~a.i)