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 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
|
import sys
from rpython.rlib.rarithmetic import r_longlong, r_uint, intmask
from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.rtyper.lltypesystem.lltype import Signed, SignedLongLong, \
UnsignedLongLong
#XXX original SIGNED_RIGHT_SHIFT_ZERO_FILLS not taken into account
#XXX assuming HAVE_LONG_LONG (int_mul_ovf)
#XXX should int_mod and int_floordiv return an intmask(...) instead?
LONG_MAX = sys.maxint
LONG_MIN = -sys.maxint-1
LLONG_MAX = r_longlong(2 ** (r_longlong.BITS-1) - 1)
LLONG_MIN = -LLONG_MAX-1
def int_floordiv_zer(x, y):
'''#define OP_INT_FLOORDIV_ZER(x,y,r,err) \
if ((y)) { OP_INT_FLOORDIV(x,y,r,err); } \
else FAIL_ZER(err, "integer division")
'''
if y:
return llop.int_floordiv(Signed, x, y)
else:
raise ZeroDivisionError("integer division")
def uint_floordiv_zer(x, y):
'''#define OP_UINT_FLOORDIV_ZER(x,y,r,err) \
if ((y)) { OP_UINT_FLOORDIV(x,y,r,err); } \
else FAIL_ZER(err, "unsigned integer division")
'''
if y:
return x / y
else:
raise ZeroDivisionError("unsigned integer division")
def llong_floordiv_zer(x, y):
'''#define OP_LLONG_FLOORDIV_ZER(x,y,r) \
if ((y)) { OP_LLONG_FLOORDIV(x,y,r); } \
else FAIL_ZER("integer division")
'''
if y:
return llop.llong_floordiv(SignedLongLong, x, y)
else:
raise ZeroDivisionError("integer division")
def ullong_floordiv_zer(x, y):
'''#define OP_ULLONG_FLOORDIV_ZER(x,y,r) \
if ((y)) { OP_ULLONG_FLOORDIV(x,y,r); } \
else FAIL_ZER("unsigned integer division")
'''
if y:
return llop.llong_floordiv(UnsignedLongLong, x, y)
else:
raise ZeroDivisionError("unsigned integer division")
def int_neg_ovf(x):
if x == LONG_MIN:
raise OverflowError("integer negate")
return -x
def llong_neg_ovf(x):
if x == LLONG_MIN:
raise OverflowError("integer negate")
return -x
def int_abs_ovf(x):
if x == LONG_MIN:
raise OverflowError("integer absolute")
if x < 0:
return -x
else:
return x
def llong_abs_ovf(x):
if x == LLONG_MIN:
raise OverflowError("integer absolute")
if x < 0:
return -x
else:
return x
def int_add_ovf(x, y):
'''#define OP_INT_ADD_OVF(x,y,r,err) \
OP_INT_ADD(x,y,r,err); \
if ((r^(x)) >= 0 || (r^(y)) >= 0); \
else FAIL_OVF(err, "integer addition")
'''
r = intmask(r_uint(x) + r_uint(y))
if r^x >= 0 or r^y >= 0:
return r
else:
raise OverflowError("integer addition")
def int_add_nonneg_ovf(x, y):
'''
OP_INT_ADD(x,y,r); \
if (r >= (x)); \
else FAIL_OVF("integer addition")
'''
r = intmask(r_uint(x) + r_uint(y))
if r >= x:
return r
else:
raise OverflowError("integer addition")
def int_sub_ovf(x, y):
'''#define OP_INT_SUB_OVF(x,y,r,err) \
OP_INT_SUB(x,y,r,err); \
if ((r^(x)) >= 0 || (r^~(y)) >= 0); \
else FAIL_OVF(err, "integer subtraction")
'''
r = intmask(r_uint(x) - r_uint(y))
if r^x >= 0 or r^~y >= 0:
return r
else:
raise OverflowError("integer subtraction")
def int_lshift_ovf(x, y):
'''#define OP_INT_LSHIFT_OVF(x,y,r,err) \
OP_INT_LSHIFT(x,y,r,err); \
if ((x) != Py_ARITHMETIC_RIGHT_SHIFT(long, r, (y))) \
FAIL_OVF(err, "x<<y losing bits or changing sign")
'''
r = x << y
if x != _Py_ARITHMETIC_RIGHT_SHIFT(r, y):
raise OverflowError("x<<y losing bits or changing sign")
else:
return r
def int_rshift_val(x, y):
'''#define OP_INT_RSHIFT_VAL(x,y,r,err) \
if ((y) >= 0) { OP_INT_RSHIFT(x,y,r,err); } \
else FAIL_VAL(err, "negative shift count")
'''
if y >= 0:
return _Py_ARITHMETIC_RIGHT_SHIFT(x, y)
else:
raise ValueError("negative shift count")
def int_lshift_val(x, y):
'''#define OP_INT_LSHIFT_VAL(x,y,r,err) \
if ((y) >= 0) { OP_INT_LSHIFT(x,y,r,err); } \
else FAIL_VAL(err, "negative shift count")
'''
if y >= 0:
return x << y
else:
raise ValueError("negative shift count")
def int_lshift_ovf_val(x, y):
'''#define OP_INT_LSHIFT_OVF_VAL(x,y,r,err) \
if ((y) >= 0) { OP_INT_LSHIFT_OVF(x,y,r,err); } \
else FAIL_VAL(err, "negative shift count")
'''
if y >= 0:
return int_lshift_ovf(x, y)
else:
raise ValueError("negative shift count")
def int_floordiv_ovf(x, y):
'''#define OP_INT_FLOORDIV_OVF(x,y,r,err) \
if ((y) == -1 && (x) < 0 && ((unsigned long)(x) << 1) == 0) \
FAIL_OVF(err, "integer division"); \
OP_INT_FLOORDIV(x,y,r,err)
'''
if y == -1 and x < 0 and (r_uint(x) << 1) == 0:
raise OverflowError("integer division")
else:
return llop.int_floordiv(Signed, x, y)
def int_floordiv_ovf_zer(x, y):
'''#define OP_INT_FLOORDIV_OVF_ZER(x,y,r,err) \
if ((y)) { OP_INT_FLOORDIV_OVF(x,y,r,err); } \
else FAIL_ZER(err, "integer division")
'''
if y:
return int_floordiv_ovf(x, y)
else:
raise ZeroDivisionError("integer division")
def int_mod_ovf(x, y):
'''#define OP_INT_MOD_OVF(x,y,r,err) \
if ((y) == -1 && (x) < 0 && ((unsigned long)(x) << 1) == 0) \
FAIL_OVF(err, "integer modulo"); \
OP_INT_MOD(x,y,r,err)
'''
if y == -1 and x < 0 and (r_uint(x) << 1) == 0:
raise OverflowError("integer modulo")
else:
return llop.int_mod(Signed, x, y)
def int_mod_zer(x, y):
'''#define OP_INT_MOD_ZER(x,y,r,err) \
if ((y)) { OP_INT_MOD(x,y,r,err); } \
else FAIL_ZER(err, "integer modulo")
'''
if y:
return llop.int_mod(Signed, x, y)
else:
raise ZeroDivisionError("integer modulo")
def uint_mod_zer(x, y):
'''#define OP_UINT_MOD_ZER(x,y,r,err) \
if ((y)) { OP_UINT_MOD(x,y,r,err); } \
else FAIL_ZER(err, "unsigned integer modulo")
'''
if y:
return x % y
else:
raise ZeroDivisionError("unsigned integer modulo")
def int_mod_ovf_zer(x, y):
'''#define OP_INT_MOD_OVF_ZER(x,y,r,err) \
if ((y)) { OP_INT_MOD_OVF(x,y,r,err); } \
else FAIL_ZER(err, "integer modulo")
'''
if y:
return int_mod_ovf(x, y)
else:
raise ZeroDivisionError("integer modulo")
def llong_mod_zer(x, y):
'''#define OP_LLONG_MOD_ZER(x,y,r) \
if ((y)) { OP_LLONG_MOD(x,y,r); } \
else FAIL_ZER("integer modulo")
'''
if y:
return llop.int_mod(SignedLongLong, x, y)
else:
raise ZeroDivisionError("integer modulo")
# Helpers...
def _Py_ARITHMETIC_RIGHT_SHIFT(i, j):
'''
// Py_ARITHMETIC_RIGHT_SHIFT
// C doesn't define whether a right-shift of a signed integer sign-extends
// or zero-fills. Here a macro to force sign extension:
// Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J)
// Return I >> J, forcing sign extension.
// Requirements:
// I is of basic signed type TYPE (char, short, int, long, or long long).
// TYPE is one of char, short, int, long, or long long, although long long
// must not be used except on platforms that support it.
// J is an integer >= 0 and strictly less than the number of bits in TYPE
// (because C doesn't define what happens for J outside that range either).
// Caution:
// I may be evaluated more than once.
#ifdef SIGNED_RIGHT_SHIFT_ZERO_FILLS
#define Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J) \
((I) < 0 ? ~((~(unsigned TYPE)(I)) >> (J)) : (I) >> (J))
#else
#define Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J) ((I) >> (J))
#endif
'''
return i >> j
#XXX some code from src/int.h seems missing
#def int_mul_ovf(x, y): #HAVE_LONG_LONG version
# '''{ \
# PY_LONG_LONG lr = (PY_LONG_LONG)(x) * (PY_LONG_LONG)(y); \
# r = (long)lr; \
# if ((PY_LONG_LONG)r == lr); \
# else FAIL_OVF(err, "integer multiplication"); \
# }
# '''
# lr = r_longlong(x) * r_longlong(y);
# r = intmask(lr)
# if r_longlong(r) == lr:
# return r
# else:
# raise OverflowError("integer multiplication")
#not HAVE_LONG_LONG version
def int_mul_ovf(a, b): #long a, long b, long *longprod):
longprod = a * b
doubleprod = float(a) * float(b)
doubled_longprod = float(longprod)
# Fast path for normal case: small multiplicands, and no info is lost in either method.
if doubled_longprod == doubleprod:
return longprod
# Somebody somewhere lost info. Close enough, or way off? Note
# that a != 0 and b != 0 (else doubled_longprod == doubleprod == 0).
# The difference either is or isn't significant compared to the
# true value (of which doubleprod is a good approximation).
# absdiff/absprod <= 1/32 iff 32 * absdiff <= absprod -- 5 good bits is "close enough"
if 32.0 * abs(doubled_longprod - doubleprod) <= abs(doubleprod):
return longprod
raise OverflowError("integer multiplication")
|