[pypy-svn] r33688 - in pypy/dist/pypy: objspace/std objspace/std/test rpython rpython/test
cfbolz at codespeak.net
cfbolz at codespeak.net
Tue Oct 24 21:30:17 CEST 2006
Author: cfbolz
Date: Tue Oct 24 21:30:14 2006
New Revision: 33688
Added:
pypy/dist/pypy/rpython/rlong.py
- copied unchanged from r33687, pypy/branch/factor-long-out/pypy/rpython/rlong.py
pypy/dist/pypy/rpython/test/test_rlong.py
- copied unchanged from r33687, pypy/branch/factor-long-out/pypy/rpython/test/test_rlong.py
Modified:
pypy/dist/pypy/objspace/std/complexobject.py
pypy/dist/pypy/objspace/std/floatobject.py
pypy/dist/pypy/objspace/std/longobject.py
pypy/dist/pypy/objspace/std/longtype.py
pypy/dist/pypy/objspace/std/marshal_impl.py
pypy/dist/pypy/objspace/std/objspace.py
pypy/dist/pypy/objspace/std/strutil.py
pypy/dist/pypy/objspace/std/test/test_longobject.py
pypy/dist/pypy/rpython/rarithmetic.py
Log:
merge long refactoring branch:
svn merge -r 33636:HEAD http://codespeak.net/svn/pypy/branch/factor-long-out
Modified: pypy/dist/pypy/objspace/std/complexobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/complexobject.py (original)
+++ pypy/dist/pypy/objspace/std/complexobject.py Tue Oct 24 21:30:14 2006
@@ -3,7 +3,6 @@
from pypy.objspace.std.objspace import registerimplementation, register_all
from pypy.objspace.std.noneobject import W_NoneObject
from pypy.objspace.std.floatobject import W_FloatObject, _hash_float
-from pypy.objspace.std.longobject import _AsDouble
import math
@@ -118,7 +117,7 @@
def delegate_Long2Complex(space, w_long):
try:
- dval = _AsDouble(w_long)
+ dval = w_long.tofloat()
except OverflowError, e:
raise OperationError(space.w_OverflowError, space.wrap(str(e)))
return W_ComplexObject(dval, 0.0)
Modified: pypy/dist/pypy/objspace/std/floatobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/floatobject.py (original)
+++ pypy/dist/pypy/objspace/std/floatobject.py Tue Oct 24 21:30:14 2006
@@ -1,9 +1,8 @@
from pypy.objspace.std.objspace import *
from pypy.interpreter import gateway
from pypy.objspace.std.noneobject import W_NoneObject
-from pypy.objspace.std.longobject import W_LongObject, _AsDouble, _FromDouble
-from pypy.objspace.std.longobject import isinf
-from pypy.rpython.rarithmetic import ovfcheck_float_to_int, intmask
+from pypy.objspace.std.longobject import W_LongObject
+from pypy.rpython.rarithmetic import ovfcheck_float_to_int, intmask, isinf
##############################################################
# for the time being, all calls that are made to some external
@@ -42,7 +41,7 @@
# long-to-float delegation
def delegate_Long2Float(space, w_longobj):
try:
- return W_FloatObject(_AsDouble(w_longobj))
+ return W_FloatObject(w_longobj.tofloat())
except OverflowError:
raise OperationError(space.w_OverflowError,
space.wrap("long int too large to convert to float"))
@@ -67,7 +66,7 @@
def long__Float(space, w_floatobj):
try:
- return _FromDouble(space, w_floatobj.floatval)
+ return W_LongObject.fromfloat(w_floatobj.floatval)
except OverflowError:
raise OperationError(space.w_OverflowError,
space.wrap("cannot convert float infinity to long"))
@@ -134,7 +133,7 @@
if isinf(x) or math.floor(x) != x:
return space.w_False
try:
- w_long1 = _FromDouble(space, x)
+ w_long1 = W_LongObject.fromfloat(x)
except OverflowError:
return space.w_False
return space.eq(w_long1, w_long2)
@@ -155,7 +154,7 @@
return space.newbool(x < 0.0)
x_floor = math.floor(x)
try:
- w_long1 = _FromDouble(space, x_floor)
+ w_long1 = W_LongObject.fromfloat(x_floor)
except OverflowError:
return space.newbool(x < 0.0)
return space.lt(w_long1, w_long2)
@@ -190,7 +189,7 @@
return space.wrap(_hash_float(space, w_value.floatval))
def _hash_float(space, v):
- from pypy.objspace.std.longobject import _FromDouble, _hash as _hashlong
+ from pypy.objspace.std.longobject import hash__Long
# This is designed so that Python numbers of different types
# that compare equal hash to the same value; otherwise comparisons
@@ -206,14 +205,14 @@
except OverflowError:
# Convert to long and use its hash.
try:
- w_lval = _FromDouble(space, v)
+ w_lval = W_LongObject.fromfloat(v)
except OverflowError:
# can't convert to long int -- arbitrary
if v < 0:
return -271828
else:
return 314159
- return _hashlong(w_lval)
+ return space.int_w(hash__Long(space, w_lval))
# The fractional part is non-zero, so we don't have to worry about
# making this match the hash of some other type.
Modified: pypy/dist/pypy/objspace/std/longobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/longobject.py (original)
+++ pypy/dist/pypy/objspace/std/longobject.py Tue Oct 24 21:30:14 2006
@@ -2,172 +2,59 @@
from pypy.objspace.std.objspace import *
from pypy.objspace.std.intobject import W_IntObject
from pypy.objspace.std.noneobject import W_NoneObject
-from pypy.rpython.rarithmetic import LONG_BIT, intmask, r_uint, ovfcheck
-
-import math
-
-# It took many days of debugging and testing, until
-# I (chris) finally understood how things work and where
-# to expect overflows in the division code.
-# In the end, I decided to throw this all out and to use
-# plain integer expressions. r_uint and friends should go away!
-# Unsignedness can be completely deduced by back-propagation
-# of masking. I will change the annotator to do this.
-# Having no special types at all, but describing everything
-# in terms of operations and masks is the stronger way.
-
-# Digit size:
-# SHIFT cannot be larger than below, for the moment.
-# In division, the native integer type must be able to hold
-# a sign bit plus two digits plus 1 overflow bit.
-# As a result, our digits will be 15 bits with one unused
-# bit, exactly as it is in CPython.
-#
-# The algorithms are anyway not bound to a given digit size.
-# There are different models possible, if we support more
-# native integer sizes. To support this, the annotator should
-# be extended to do some basic size tracking of integers.
-#
-# Examples:
-# C
-# Most C implementations have support for signed long long.
-# use an unsigned 16 bit unsigned short for the digits.
-# The operations which must hold two digits become unsigned long.
-# The sign+two digits+overflow register in division becomes
-# a 64 bit signed long long.
-#
-# X86 assembler
-# Given that we support some more primitive types for integers,
-# this might become a nicer layout for an X86 assembly backend:
-# The digit would be 32 bit long unsigned int,
-# two digits would be 64 bit long long unsigned int,
-# and the signed type mentioned above would be 80 bit extended.
-#
-# Emulation of different integer types
-# Even if we don't have machine support for certain types,
-# it might be worth trying to emulate them by providing some
-# means of multi-precision integers in rpython.
-# It is possible to write primitive code that emits the
-# necessary operations for emulation of larger types.
-# But we should do some careful testing how fast this code
-# will be, compared to just working with native types.
-# Probably the primitive types will outperform this.
-
-SHIFT = (LONG_BIT // 2) - 1
-
-# XXX
-# SHIFT cannot be anything but 15 at the moment, or we break marshal
-SHIFT = 15
-
-MASK = int((1 << SHIFT) - 1)
-
-
-# Debugging digit array access.
-#
-# False == no checking at all
-# True == check 0 <= value <= MASK
-
-CHECK_DIGITS = False # True
-
-if CHECK_DIGITS:
- class DigitArray(list):
- def __setitem__(self, idx, value):
- assert value >=0
- assert value <= MASK
- list.__setitem__(self, idx, value)
-else:
- DigitArray = list
-
+from pypy.rpython.rlong import rlong, SHIFT
class W_LongObject(W_Object):
- """This is a reimplementation of longs using a list of digits."""
- # All functions that still rely on the underlying Python's longs are marked
- # with YYYYYY
- # Actually, all methods to be officially used are native implementations.
+ """This is a wrapper of rlong."""
from pypy.objspace.std.longtype import long_typedef as typedef
- def __init__(w_self, digits, sign=0):
- #if isinstance(digits, long): #YYYYYY
- # digits, sign = args_from_long(digits)
- if len(digits) == 0:
- digits = [0]
- w_self.digits = DigitArray(digits)
- w_self.sign = sign
+ def __init__(w_self, l):
+ w_self.num = l # instance of rlong
def fromint(space, intval):
- if intval < 0:
- sign = -1
- ival = r_uint(-intval)
- elif intval > 0:
- sign = 1
- ival = r_uint(intval)
- else:
- return W_LongObject([0], 0)
- # Count the number of Python digits.
- # We used to pick 5 ("big enough for anything"), but that's a
- # waste of time and space given that 5*15 = 75 bits are rarely
- # needed.
- t = ival
- ndigits = 0
- while t:
- ndigits += 1
- t >>= SHIFT
- v = W_LongObject([0] * ndigits, sign)
- t = ival
- p = 0
- while t:
- v.digits[p] = intmask(t & MASK)
- t >>= SHIFT
- p += 1
- return v
+ return W_LongObject(rlong.fromint(intval))
fromint = staticmethod(fromint)
- def longval(self): #YYYYYY
- l = 0
- digits = list(self.digits)
- digits.reverse()
- for d in digits:
- l = l << SHIFT
- l += long(d)
- return l * self.sign
+ def longval(self):
+ return self.num.tolong()
def unwrap(w_self, space): #YYYYYY
return w_self.longval()
- def _normalize(self):
- if len(self.digits) == 0:
- self.sign = 0
- self.digits = [0]
- return
- i = len(self.digits) - 1
- while i != 0 and self.digits[i] == 0:
- self.digits.pop(-1)
- i -= 1
- if len(self.digits) == 1 and self.digits[0] == 0:
- self.sign = 0
-
-
-registerimplementation(W_LongObject)
+ def tofloat(self):
+ return self.num.tofloat()
-USE_KARATSUBA = True # set to False for comparison
+ def toint(self):
+ return self.num.toint()
-# For long multiplication, use the O(N**2) school algorithm unless
-# both operands contain more than KARATSUBA_CUTOFF digits (this
-# being an internal Python long digit, in base BASE).
+ def fromfloat(f):
+ return W_LongObject(rlong.fromfloat(f))
+ fromfloat = staticmethod(fromfloat)
+
+ def fromlong(l):
+ return W_LongObject(rlong.fromlong(l))
+ fromlong = staticmethod(fromlong)
+
+ def fromrarith_int(i):
+ return W_LongObject(rlong.fromrarith_int(i))
+ fromrarith_int._annspecialcase_ = "specialize:argtype(0)"
+ fromrarith_int = staticmethod(fromrarith_int)
+
+ def fromdecimalstr(s):
+ return W_LongObject(rlong.fromdecimalstr(s))
+ fromdecimalstr = staticmethod(fromdecimalstr)
-KARATSUBA_CUTOFF = 70
-KARATSUBA_SQUARE_CUTOFF = 2 * KARATSUBA_CUTOFF
+ def _count_bits(self):
+ return self.num._count_bits()
-# For exponentiation, use the binary left-to-right algorithm
-# unless the exponent contains more than FIVEARY_CUTOFF digits.
-# In that case, do 5 bits at a time. The potential drawback is that
-# a table of 2**5 intermediate results is computed.
+ def is_odd(self):
+ return self.num.is_odd()
-FIVEARY_CUTOFF = 8
+registerimplementation(W_LongObject)
# bool-to-long
def delegate_Bool2Long(space, w_bool):
- return W_LongObject([w_bool.boolval & MASK], int(w_bool.boolval))
+ return W_LongObject(rlong.frombool(space.is_true(w_bool)))
# int-to-long delegation
def delegate_Int2Long(space, w_intobj):
@@ -180,105 +67,57 @@
def long__Long(space, w_long1):
if space.is_w(space.type(w_long1), space.w_long):
return w_long1
- digits = w_long1.digits
- sign = w_long1.sign
- return W_LongObject(digits, sign)
+ l = w_long1.num
+ return W_LongObject(l)
def long__Int(space, w_intobj):
return W_LongObject.fromint(space, w_intobj.intval)
def int__Long(space, w_value):
try:
- x = _AsLong(w_value)
+ return space.newint(w_value.num.toint())
except OverflowError:
return long__Long(space, w_value)
- else:
- return space.newint(x)
def float__Long(space, w_longobj):
try:
- return space.newfloat(_AsDouble(w_longobj))
+ return space.newfloat(w_longobj.num.tofloat())
except OverflowError:
raise OperationError(space.w_OverflowError,
space.wrap("long int too large to convert to float"))
def int_w__Long(space, w_value):
try:
- return _AsLong(w_value)
+ return w_value.num.toint()
except OverflowError:
raise OperationError(space.w_OverflowError, space.wrap(
"long int too large to convert to int"))
def uint_w__Long(space, w_value):
- if w_value.sign == -1:
+ try:
+ return w_value.num.touint()
+ except ValueError:
raise OperationError(space.w_ValueError, space.wrap(
"cannot convert negative integer to unsigned int"))
- x = r_uint(0)
- i = len(w_value.digits) - 1
- while i >= 0:
- prev = x
- x = (x << SHIFT) + w_value.digits[i]
- if (x >> SHIFT) != prev:
- raise OperationError(space.w_OverflowError, space.wrap(
- "long int too large to convert to unsigned int"))
- i -= 1
- return x
+ except OverflowError:
+ raise OperationError(space.w_OverflowError, space.wrap(
+ "long int too large to convert to unsigned int"))
def repr__Long(space, w_long):
- return space.wrap(_format(w_long, 10, True))
+ return space.wrap(w_long.num.repr())
def str__Long(space, w_long):
- return space.wrap(_format(w_long, 10, False))
+ return space.wrap(w_long.num.str())
def eq__Long_Long(space, w_long1, w_long2):
- if (w_long1.sign != w_long2.sign or
- len(w_long1.digits) != len(w_long2.digits)):
- return space.newbool(False)
- i = 0
- ld = len(w_long1.digits)
- while i < ld:
- if w_long1.digits[i] != w_long2.digits[i]:
- return space.newbool(False)
- i += 1
- return space.newbool(True)
+ return space.newbool(w_long1.num.eq(w_long2.num))
def lt__Long_Long(space, w_long1, w_long2):
- if w_long1.sign > w_long2.sign:
- return space.newbool(False)
- if w_long1.sign < w_long2.sign:
- return space.newbool(True)
- ld1 = len(w_long1.digits)
- ld2 = len(w_long2.digits)
- if ld1 > ld2:
- if w_long2.sign > 0:
- return space.newbool(False)
- else:
- return space.newbool(True)
- elif ld1 < ld2:
- if w_long2.sign > 0:
- return space.newbool(True)
- else:
- return space.newbool(False)
- i = ld1 - 1
- while i >= 0:
- d1 = w_long1.digits[i]
- d2 = w_long2.digits[i]
- if d1 < d2:
- if w_long2.sign > 0:
- return space.newbool(True)
- else:
- return space.newbool(False)
- elif d1 > d2:
- if w_long2.sign > 0:
- return space.newbool(False)
- else:
- return space.newbool(True)
- i -= 1
- return space.newbool(False)
+ return space.newbool(w_long1.num.lt(w_long2.num))
def hash__Long(space, w_value):
- return space.wrap(_hash(w_value))
+ return space.wrap(w_value.num.hash())
# coerce
def coerce__Long_Long(space, w_long1, w_long2):
@@ -286,292 +125,125 @@
def add__Long_Long(space, w_long1, w_long2):
- if w_long1.sign < 0:
- if w_long2.sign < 0:
- result = _x_add(w_long1, w_long2)
- if result.sign != 0:
- result.sign = -result.sign
- else:
- result = _x_sub(w_long2, w_long1)
- else:
- if w_long2.sign < 0:
- result = _x_sub(w_long1, w_long2)
- else:
- result = _x_add(w_long1, w_long2)
- result._normalize()
- return result
+ return W_LongObject(w_long1.num.add(w_long2.num))
def sub__Long_Long(space, w_long1, w_long2):
- if w_long1.sign < 0:
- if w_long2.sign < 0:
- result = _x_sub(w_long1, w_long2)
- else:
- result = _x_add(w_long1, w_long2)
- result.sign = -result.sign
- else:
- if w_long2.sign < 0:
- result = _x_add(w_long1, w_long2)
- else:
- result = _x_sub(w_long1, w_long2)
- result._normalize()
- return result
+ return W_LongObject(w_long1.num.sub(w_long2.num))
def mul__Long_Long(space, w_long1, w_long2):
- if USE_KARATSUBA:
- result = _k_mul(w_long1, w_long2)
- else:
- result = _x_mul(w_long1, w_long2)
- result.sign = w_long1.sign * w_long2.sign
- return result
+ return W_LongObject(w_long1.num.mul(w_long2.num))
def truediv__Long_Long(space, w_long1, w_long2):
- div = _long_true_divide(space, w_long1, w_long2)
- return space.newfloat(div)
+ try:
+ return space.newfloat(w_long1.num.truediv(w_long2.num))
+ except ZeroDivisionError:
+ raise OperationError(space.w_ZeroDivisionError,
+ space.wrap("long division or modulo by zero"))
def floordiv__Long_Long(space, w_long1, w_long2):
- div, mod = _l_divmod(space, w_long1, w_long2)
- return div
+ try:
+ return W_LongObject(w_long1.num.floordiv(w_long2.num))
+ except ZeroDivisionError:
+ raise OperationError(space.w_ZeroDivisionError,
+ space.wrap("long division or modulo by zero"))
def div__Long_Long(space, w_long1, w_long2):
return floordiv__Long_Long(space, w_long1, w_long2)
def mod__Long_Long(space, w_long1, w_long2):
- div, mod = _l_divmod(space, w_long1, w_long2)
- return mod
+ try:
+ return W_LongObject(w_long1.num.mod(w_long2.num))
+ except ZeroDivisionError:
+ raise OperationError(space.w_ZeroDivisionError,
+ space.wrap("long division or modulo by zero"))
def divmod__Long_Long(space, w_long1, w_long2):
- div, mod = _l_divmod(space, w_long1, w_long2)
- return space.newtuple([div, mod])
-
-def _impl_long_long_pow(space, a, b, c=None):
- """ pow(a, b, c) """
-
- negativeOutput = False # if x<0 return negative output
-
- # 5-ary values. If the exponent is large enough, table is
- # precomputed so that table[i] == a**i % c for i in range(32).
- # python translation: the table is computed when needed.
+ try:
+ div, mod = w_long1.num.divmod(w_long2.num)
+ return space.newtuple([W_LongObject(div), W_LongObject(mod)])
+ except ZeroDivisionError:
+ raise OperationError(space.w_ZeroDivisionError,
+ space.wrap("long division or modulo by zero"))
- if b.sign < 0: # if exponent is negative
- if c is not None:
- raise OperationError(space.w_TypeError, space.wrap(
+def pow__Long_Long_Long(space, w_long1, w_long2, w_long3):
+ # XXX need to replicate some of the logic, to get the errors right
+ if w_long2.num.lt(rlong.fromint(0)):
+ raise OperationError(
+ space.w_TypeError,
+ space.wrap(
"pow() 2nd argument "
"cannot be negative when 3rd argument specified"))
- raise FailedToImplement(space.w_ValueError, space.wrap(
- "long pow() to negative"))
-
- if c is not None:
- # if modulus == 0:
- # raise ValueError()
- if c.sign == 0:
- raise OperationError(space.w_ValueError, space.wrap(
- "pow() 3rd argument cannot be 0"))
-
- # if modulus < 0:
- # negativeOutput = True
- # modulus = -modulus
- if c.sign < 0:
- negativeOutput = True
- c = W_LongObject(c.digits, -c.sign)
-
- # if modulus == 1:
- # return 0
- if len(c.digits) == 1 and c.digits[0] == 1:
- return W_LongObject([0], 0)
-
- # if base < 0:
- # base = base % modulus
- # Having the base positive just makes things easier.
- if a.sign < 0:
- a, temp = _l_divmod(space, a, c)
- a = temp
-
- # At this point a, b, and c are guaranteed non-negative UNLESS
- # c is NULL, in which case a may be negative. */
-
- z = W_LongObject([1], 1)
-
- # python adaptation: moved macros REDUCE(X) and MULT(X, Y, result)
- # into helper function result = _help_mult(x, y, c)
- if len(b.digits) <= FIVEARY_CUTOFF:
- # Left-to-right binary exponentiation (HAC Algorithm 14.79)
- # http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf
- i = len(b.digits) - 1
- while i >= 0:
- bi = b.digits[i]
- j = 1 << (SHIFT-1)
- while j != 0:
- z = _help_mult(space, z, z, c)
- if bi & j:
- z = _help_mult(space, z, a, c)
- j >>= 1
- i -= 1
- else:
- # Left-to-right 5-ary exponentiation (HAC Algorithm 14.82)
- # z still holds 1L
- table = [z] * 32
- table[0] = z;
- for i in range(1, 32):
- table[i] = _help_mult(space, table[i-1], a, c)
- i = len(b.digits) - 1
- while i >= 0:
- bi = b.digits[i]
- j = j = SHIFT - 5
- while j >= 0:
- index = (bi >> j) & 0x1f
- for k in range(5):
- z = _help_mult(space, z, z, c)
- if index:
- z = _help_mult(space, z, table[index], c)
- j -= 5
- i -= 1
-
- if negativeOutput and z.sign != 0:
- z = sub__Long_Long(space, z, c)
- return z
-
-def _help_mult(space, x, y, c):
- """
- Multiply two values, then reduce the result:
- result = X*Y % c. If c is NULL, skip the mod.
- """
- res = mul__Long_Long(space, x, y)
- # Perform a modular reduction, X = X % c, but leave X alone if c
- # is NULL.
- if c is not None:
- res, temp = _l_divmod(space, res, c)
- res = temp
- return res
-
-def pow__Long_Long_Long(space, w_long1, w_long2, w_long3):
- return _impl_long_long_pow(space, w_long1, w_long2, w_long3)
+ try:
+ return W_LongObject(w_long1.num.pow(w_long2.num, w_long3.num))
+ except ValueError:
+ raise OperationError(space.w_ValueError,
+ space.wrap("pow 3rd argument cannot be 0"))
def pow__Long_Long_None(space, w_long1, w_long2, w_long3):
- return _impl_long_long_pow(space, w_long1, w_long2, None)
-
+ # XXX need to replicate some of the logic, to get the errors right
+ if w_long2.num.lt(rlong.fromint(0)):
+ raise FailedToImplement(
+ space.w_ValueError,
+ space.wrap("long pow() too negative"))
+ return W_LongObject(w_long1.num.pow(w_long2.num, None))
def neg__Long(space, w_long1):
- return W_LongObject(w_long1.digits, -w_long1.sign)
+ return W_LongObject(w_long1.num.neg())
def pos__Long(space, w_long):
return long__Long(space, w_long)
def abs__Long(space, w_long):
- return W_LongObject(w_long.digits, abs(w_long.sign))
+ return W_LongObject(w_long.num.abs())
def nonzero__Long(space, w_long):
- return space.newbool(w_long.sign != 0)
+ return space.newbool(w_long.num.tobool())
def invert__Long(space, w_long): #Implement ~x as -(x + 1)
- w_lpp = add__Long_Long(space, w_long, W_LongObject([1], 1))
- return neg__Long(space, w_lpp)
+ return W_LongObject(w_long.num.invert())
def lshift__Long_Long(space, w_long1, w_long2):
- if w_long2.sign < 0:
+ # XXX need to replicate some of the logic, to get the errors right
+ if w_long2.num.lt(rlong.fromint(0)):
raise OperationError(space.w_ValueError,
space.wrap("negative shift count"))
- elif w_long2.sign == 0:
- return long__Long(space, w_long1)
try:
- shiftby = int_w__Long(space, w_long2)
+ return W_LongObject(w_long1.num.lshift(w_long2.num))
except OverflowError: # b too big
raise OperationError(space.w_OverflowError,
space.wrap("shift count too large"))
- a = w_long1
- # wordshift, remshift = divmod(shiftby, SHIFT)
- wordshift = shiftby // SHIFT
- remshift = shiftby - wordshift * SHIFT
-
- oldsize = len(a.digits)
- newsize = oldsize + wordshift
- if remshift:
- newsize += 1
- z = W_LongObject([0] * newsize, a.sign)
- # not sure if we will initialize things in the future?
- for i in range(wordshift):
- z.digits[i] = 0
- accum = 0
- i = wordshift
- j = 0
- while j < oldsize:
- accum |= a.digits[j] << remshift
- z.digits[i] = accum & MASK
- accum >>= SHIFT
- i += 1
- j += 1
- if remshift:
- z.digits[newsize-1] = accum
- else:
- assert not accum
- z._normalize()
- return z
-
def rshift__Long_Long(space, w_long1, w_long2):
- if w_long2.sign < 0:
+ # XXX need to replicate some of the logic, to get the errors right
+ if w_long2.num.lt(rlong.fromint(0)):
raise OperationError(space.w_ValueError,
space.wrap("negative shift count"))
- elif w_long2.sign == 0:
- return long__Long(space, w_long1)
- if w_long1.sign == -1:
- w_a1 = invert__Long(space, w_long1)
- w_a2 = rshift__Long_Long(space, w_a1, w_long2)
- return invert__Long(space, w_a2)
try:
- shiftby = int_w__Long(space, w_long2)
+ return W_LongObject(w_long1.num.rshift(w_long2.num))
except OverflowError: # b too big # XXX maybe just return 0L instead?
raise OperationError(space.w_OverflowError,
space.wrap("shift count too large"))
- a = w_long1
- wordshift = shiftby // SHIFT
- newsize = len(a.digits) - wordshift
- if newsize <= 0:
- return W_LongObject([0], 0)
-
- loshift = shiftby % SHIFT
- hishift = SHIFT - loshift
- lomask = (1 << hishift) - 1
- himask = MASK ^ lomask
- z = W_LongObject([0] * newsize, a.sign)
- i = 0
- j = wordshift
- while i < newsize:
- z.digits[i] = (a.digits[j] >> loshift) & lomask
- if i+1 < newsize:
- z.digits[i] |= (a.digits[j+1] << hishift) & himask
- i += 1
- j += 1
- z._normalize()
- return z
-
def and__Long_Long(space, w_long1, w_long2):
- return _bitwise(space, w_long1, '&', w_long2)
+ return W_LongObject(w_long1.num.and_(w_long2.num))
def xor__Long_Long(space, w_long1, w_long2):
- return _bitwise(space, w_long1, '^', w_long2)
+ return W_LongObject(w_long1.num.xor(w_long2.num))
def or__Long_Long(space, w_long1, w_long2):
- return _bitwise(space, w_long1, '|', w_long2)
+ return W_LongObject(w_long1.num.or_(w_long2.num))
def oct__Long(space, w_long1):
- return space.wrap(_format(w_long1, 8, True))
+ return space.wrap(w_long1.num.oct())
def hex__Long(space, w_long1):
- return space.wrap(_format(w_long1, 16, True))
+ return space.wrap(w_long1.num.hex())
def getnewargs__Long(space, w_long1):
- return space.newtuple([W_LongObject(w_long1.digits, w_long1.sign)])
+ return space.newtuple([W_LongObject(w_long1.num)])
def log__Long(space, w_long, base):
- # base is supposed to be positive or 0.0, which means we use e
- if base == 10.0:
- return space.wrap(_loghelper(math.log10, w_long))
- ret = _loghelper(math.log, w_long)
- if base != 0.0:
- ret /= math.log(base)
- return space.wrap(ret)
-
+ return space.wrap(w_long.num.log(base))
register_all(vars())
@@ -612,1122 +284,4 @@
StdObjSpace.MM.pow.register(pow_ovr__Int_Int_None, W_IntObject, W_IntObject, W_NoneObject, order=1)
StdObjSpace.MM.pow.register(pow_ovr__Int_Int_Long, W_IntObject, W_IntObject, W_LongObject, order=1)
-#_________________________________________________________________
-
-# Helper Functions
-def digits_from_nonneg_long(l):
- digits = []
- while True:
- digits.append(intmask(l) & MASK)
- l = l >> SHIFT
- if not l:
- return digits
-digits_from_nonneg_long._annspecialcase_ = "specialize:argtype(0)"
-
-def digits_for_most_neg_long(l):
- # This helper only works if 'l' is the most negative integer of its
- # type, which in base 2 looks like: 1000000..0000
- digits = []
- while (intmask(l) & MASK) == 0:
- digits.append(0)
- l = l >> SHIFT
- # now 'l' looks like: ...111100000
- # turn it into: ...000100000
- # to drop the extra unwanted 1's introduced by the signed right shift
- l = -intmask(l)
- assert l >= 0
- digits.append(l)
- return digits
-digits_for_most_neg_long._annspecialcase_ = "specialize:argtype(0)"
-
-def args_from_rarith_int(x):
- if x >= 0:
- if x == 0:
- return [0], 0
- else:
- return digits_from_nonneg_long(x), 1
- else:
- try:
- y = ovfcheck(-x)
- except OverflowError:
- y = -1
- # be conservative and check again if the result is >= 0, even
- # if no OverflowError was raised (e.g. broken CPython/GCC4.2)
- if y >= 0:
- # normal case
- return digits_from_nonneg_long(y), -1
- else:
- # the most negative integer! hacks needed...
- return digits_for_most_neg_long(x), -1
-args_from_rarith_int._annspecialcase_ = "specialize:argtype(0)"
-# ^^^ specialized by the precise type of 'x', which is typically a r_xxx
-# instance from rpython.rarithmetic
-
-def args_from_long(x):
- "NOT_RPYTHON"
- if x >= 0:
- if x == 0:
- return [0], 0
- else:
- return digits_from_nonneg_long(x), 1
- else:
- return digits_from_nonneg_long(-long(x)), -1
-
-def _x_add(a, b):
- """ Add the absolute values of two long integers. """
- size_a = len(a.digits)
- size_b = len(b.digits)
-
- # Ensure a is the larger of the two:
- if size_a < size_b:
- a, b = b, a
- size_a, size_b = size_b, size_a
- z = W_LongObject([0] * (len(a.digits) + 1), 1)
- i = 0
- carry = 0
- while i < size_b:
- carry += a.digits[i] + b.digits[i]
- z.digits[i] = carry & MASK
- carry >>= SHIFT
- i += 1
- while i < size_a:
- carry += a.digits[i]
- z.digits[i] = carry & MASK
- carry >>= SHIFT
- i += 1
- z.digits[i] = carry
- z._normalize()
- return z
-
-def _x_sub(a, b):
- """ Subtract the absolute values of two integers. """
- size_a = len(a.digits)
- size_b = len(b.digits)
- sign = 1
- borrow = 0
-
- # Ensure a is the larger of the two:
- if size_a < size_b:
- sign = -1
- a, b = b, a
- size_a, size_b = size_b, size_a
- elif size_a == size_b:
- # Find highest digit where a and b differ:
- i = size_a - 1
- while i >= 0 and a.digits[i] == b.digits[i]:
- i -= 1
- if i < 0:
- return W_LongObject([0], 0)
- if a.digits[i] < b.digits[i]:
- sign = -1
- a, b = b, a
- size_a = size_b = i+1
- z = W_LongObject([0] * size_a, 1)
- i = 0
- while i < size_b:
- # The following assumes unsigned arithmetic
- # works modulo 2**N for some N>SHIFT.
- borrow = a.digits[i] - b.digits[i] - borrow
- z.digits[i] = borrow & MASK
- borrow >>= SHIFT
- borrow &= 1 # Keep only one sign bit
- i += 1
- while i < size_a:
- borrow = a.digits[i] - borrow
- z.digits[i] = borrow & MASK
- borrow >>= SHIFT
- borrow &= 1 # Keep only one sign bit
- i += 1
- assert borrow == 0
- if sign < 0:
- z.sign = -1
- z._normalize()
- return z
-
-
-def _x_mul(a, b):
- """
- Grade school multiplication, ignoring the signs.
- Returns the absolute value of the product, or NULL if error.
- """
-
- size_a = len(a.digits)
- size_b = len(b.digits)
- z = W_LongObject([0] * (size_a + size_b), 1)
- if a == b:
- # Efficient squaring per HAC, Algorithm 14.16:
- # http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf
- # Gives slightly less than a 2x speedup when a == b,
- # via exploiting that each entry in the multiplication
- # pyramid appears twice (except for the size_a squares).
- i = 0
- while i < size_a:
- f = a.digits[i]
- pz = i << 1
- pa = i + 1
- paend = size_a
-
- carry = z.digits[pz] + f * f
- z.digits[pz] = carry & MASK
- pz += 1
- carry >>= SHIFT
- assert carry <= MASK
-
- # Now f is added in twice in each column of the
- # pyramid it appears. Same as adding f<<1 once.
- f <<= 1
- while pa < paend:
- carry += z.digits[pz] + a.digits[pa] * f
- pa += 1
- z.digits[pz] = carry & MASK
- pz += 1
- carry >>= SHIFT
- assert carry <= (MASK << 1)
- if carry:
- carry += z.digits[pz]
- z.digits[pz] = carry & MASK
- pz += 1
- carry >>= SHIFT
- if carry:
- z.digits[pz] += carry & MASK
- assert (carry >> SHIFT) == 0
- i += 1
- else:
- # a is not the same as b -- gradeschool long mult
- i = 0
- while i < size_a:
- carry = 0
- f = a.digits[i]
- pz = i
- pb = 0
- pbend = size_b
- while pb < pbend:
- carry += z.digits[pz] + b.digits[pb] * f
- pb += 1
- z.digits[pz] = carry & MASK
- pz += 1
- carry >>= SHIFT
- assert carry <= MASK
- if carry:
- z.digits[pz] += carry & MASK
- assert (carry >> SHIFT) == 0
- i += 1
- z._normalize()
- return z
-
-
-def _kmul_split(n, size):
- """
- A helper for Karatsuba multiplication (k_mul).
- Takes a long "n" and an integer "size" representing the place to
- split, and sets low and high such that abs(n) == (high << size) + low,
- viewing the shift as being by digits. The sign bit is ignored, and
- the return values are >= 0.
- """
- size_n = len(n.digits)
- size_lo = min(size_n, size)
-
- lo = W_LongObject(n.digits[:size_lo], 1)
- hi = W_LongObject(n.digits[size_lo:], 1)
- lo._normalize()
- hi._normalize()
- return hi, lo
-
-def _k_mul(a, b):
- """
- Karatsuba multiplication. Ignores the input signs, and returns the
- absolute value of the product (or raises if error).
- See Knuth Vol. 2 Chapter 4.3.3 (Pp. 294-295).
- """
- asize = len(a.digits)
- bsize = len(b.digits)
- # (ah*X+al)(bh*X+bl) = ah*bh*X*X + (ah*bl + al*bh)*X + al*bl
- # Let k = (ah+al)*(bh+bl) = ah*bl + al*bh + ah*bh + al*bl
- # Then the original product is
- # ah*bh*X*X + (k - ah*bh - al*bl)*X + al*bl
- # By picking X to be a power of 2, "*X" is just shifting, and it's
- # been reduced to 3 multiplies on numbers half the size.
-
- # We want to split based on the larger number; fiddle so that b
- # is largest.
- if asize > bsize:
- a, b, asize, bsize = b, a, bsize, asize
-
- # Use gradeschool math when either number is too small.
- if a == b:
- i = KARATSUBA_SQUARE_CUTOFF
- else:
- i = KARATSUBA_CUTOFF
- if asize <= i:
- if a.sign == 0:
- return W_LongObject([0], 0)
- else:
- return _x_mul(a, b)
-
- # If a is small compared to b, splitting on b gives a degenerate
- # case with ah==0, and Karatsuba may be (even much) less efficient
- # than "grade school" then. However, we can still win, by viewing
- # b as a string of "big digits", each of width a->ob_size. That
- # leads to a sequence of balanced calls to k_mul.
- if 2 * asize <= bsize:
- return _k_lopsided_mul(a, b)
-
- # Split a & b into hi & lo pieces.
- shift = bsize >> 1
- ah, al = _kmul_split(a, shift)
- assert ah.sign == 1 # the split isn't degenerate
-
- if a == b:
- bh = ah
- bl = al
- else:
- bh, bl = _kmul_split(b, shift)
-
- # The plan:
- # 1. Allocate result space (asize + bsize digits: that's always
- # enough).
- # 2. Compute ah*bh, and copy into result at 2*shift.
- # 3. Compute al*bl, and copy into result at 0. Note that this
- # can't overlap with #2.
- # 4. Subtract al*bl from the result, starting at shift. This may
- # underflow (borrow out of the high digit), but we don't care:
- # we're effectively doing unsigned arithmetic mod
- # BASE**(sizea + sizeb), and so long as the *final* result fits,
- # borrows and carries out of the high digit can be ignored.
- # 5. Subtract ah*bh from the result, starting at shift.
- # 6. Compute (ah+al)*(bh+bl), and add it into the result starting
- # at shift.
-
- # 1. Allocate result space.
- ret = W_LongObject([0] * (asize + bsize), 1)
-
- # 2. t1 <- ah*bh, and copy into high digits of result.
- t1 = _k_mul(ah, bh)
- assert t1.sign >= 0
- assert 2*shift + len(t1.digits) <= len(ret.digits)
- ret.digits[2*shift : 2*shift + len(t1.digits)] = t1.digits
-
- # Zero-out the digits higher than the ah*bh copy. */
- ## ignored, assuming that we initialize to zero
- ##i = ret->ob_size - 2*shift - t1->ob_size;
- ##if (i)
- ## memset(ret->ob_digit + 2*shift + t1->ob_size, 0,
- ## i * sizeof(digit));
-
- # 3. t2 <- al*bl, and copy into the low digits.
- t2 = _k_mul(al, bl)
- assert t2.sign >= 0
- assert len(t2.digits) <= 2*shift # no overlap with high digits
- ret.digits[:len(t2.digits)] = t2.digits
-
- # Zero out remaining digits.
- ## ignored, assuming that we initialize to zero
- ##i = 2*shift - t2->ob_size; /* number of uninitialized digits */
- ##if (i)
- ## memset(ret->ob_digit + t2->ob_size, 0, i * sizeof(digit));
-
- # 4 & 5. Subtract ah*bh (t1) and al*bl (t2). We do al*bl first
- # because it's fresher in cache.
- i = len(ret.digits) - shift # # digits after shift
- _v_isub(ret.digits, shift, i, t2.digits, len(t2.digits))
- _v_isub(ret.digits, shift, i, t1.digits, len(t1.digits))
- del t1, t2
-
- # 6. t3 <- (ah+al)(bh+bl), and add into result.
- t1 = _x_add(ah, al)
- del ah, al
-
- if a == b:
- t2 = t1
- else:
- t2 = _x_add(bh, bl)
- del bh, bl
-
- t3 = _k_mul(t1, t2)
- del t1, t2
- assert t3.sign ==1
-
- # Add t3. It's not obvious why we can't run out of room here.
- # See the (*) comment after this function.
- _v_iadd(ret.digits, shift, i, t3.digits, len(t3.digits))
- del t3
-
- ret._normalize()
- return ret
-
-""" (*) Why adding t3 can't "run out of room" above.
-
-Let f(x) mean the floor of x and c(x) mean the ceiling of x. Some facts
-to start with:
-
-1. For any integer i, i = c(i/2) + f(i/2). In particular,
- bsize = c(bsize/2) + f(bsize/2).
-2. shift = f(bsize/2)
-3. asize <= bsize
-4. Since we call k_lopsided_mul if asize*2 <= bsize, asize*2 > bsize in this
- routine, so asize > bsize/2 >= f(bsize/2) in this routine.
-
-We allocated asize + bsize result digits, and add t3 into them at an offset
-of shift. This leaves asize+bsize-shift allocated digit positions for t3
-to fit into, = (by #1 and #2) asize + f(bsize/2) + c(bsize/2) - f(bsize/2) =
-asize + c(bsize/2) available digit positions.
-
-bh has c(bsize/2) digits, and bl at most f(size/2) digits. So bh+hl has
-at most c(bsize/2) digits + 1 bit.
-
-If asize == bsize, ah has c(bsize/2) digits, else ah has at most f(bsize/2)
-digits, and al has at most f(bsize/2) digits in any case. So ah+al has at
-most (asize == bsize ? c(bsize/2) : f(bsize/2)) digits + 1 bit.
-
-The product (ah+al)*(bh+bl) therefore has at most
-
- c(bsize/2) + (asize == bsize ? c(bsize/2) : f(bsize/2)) digits + 2 bits
-
-and we have asize + c(bsize/2) available digit positions. We need to show
-this is always enough. An instance of c(bsize/2) cancels out in both, so
-the question reduces to whether asize digits is enough to hold
-(asize == bsize ? c(bsize/2) : f(bsize/2)) digits + 2 bits. If asize < bsize,
-then we're asking whether asize digits >= f(bsize/2) digits + 2 bits. By #4,
-asize is at least f(bsize/2)+1 digits, so this in turn reduces to whether 1
-digit is enough to hold 2 bits. This is so since SHIFT=15 >= 2. If
-asize == bsize, then we're asking whether bsize digits is enough to hold
-c(bsize/2) digits + 2 bits, or equivalently (by #1) whether f(bsize/2) digits
-is enough to hold 2 bits. This is so if bsize >= 2, which holds because
-bsize >= KARATSUBA_CUTOFF >= 2.
-
-Note that since there's always enough room for (ah+al)*(bh+bl), and that's
-clearly >= each of ah*bh and al*bl, there's always enough room to subtract
-ah*bh and al*bl too.
-"""
-
-def _k_lopsided_mul(a, b):
- """
- b has at least twice the digits of a, and a is big enough that Karatsuba
- would pay off *if* the inputs had balanced sizes. View b as a sequence
- of slices, each with a->ob_size digits, and multiply the slices by a,
- one at a time. This gives k_mul balanced inputs to work with, and is
- also cache-friendly (we compute one double-width slice of the result
- at a time, then move on, never bactracking except for the helpful
- single-width slice overlap between successive partial sums).
- """
- asize = len(a.digits)
- bsize = len(b.digits)
- # nbdone is # of b digits already multiplied
-
- assert asize > KARATSUBA_CUTOFF
- assert 2 * asize <= bsize
-
- # Allocate result space, and zero it out.
- ret = W_LongObject([0] * (asize + bsize), 1)
-
- # Successive slices of b are copied into bslice.
- #bslice = W_LongObject([0] * asize, 1)
- # XXX we cannot pre-allocate, see comments below!
- bslice = W_LongObject([0], 1)
-
- nbdone = 0;
- while bsize > 0:
- nbtouse = min(bsize, asize)
-
- # Multiply the next slice of b by a.
-
- #bslice.digits[:nbtouse] = b.digits[nbdone : nbdone + nbtouse]
- # XXX: this would be more efficient if we adopted CPython's
- # way to store the size, instead of resizing the list!
- # XXX change the implementation, encoding length via the sign.
- bslice.digits = b.digits[nbdone : nbdone + nbtouse]
- product = _k_mul(a, bslice)
-
- # Add into result.
- _v_iadd(ret.digits, nbdone, len(ret.digits) - nbdone,
- product.digits, len(product.digits))
- del product
-
- bsize -= nbtouse
- nbdone += nbtouse
-
- ret._normalize()
- return ret
-
-
-def _inplace_divrem1(pout, pin, n, size=0):
- """
- Divide long pin by non-zero digit n, storing quotient
- in pout, and returning the remainder. It's OK for pin == pout on entry.
- """
- rem = 0
- assert n > 0 and n <= MASK
- if not size:
- size = len(pin.digits)
- size -= 1
- while size >= 0:
- rem = (rem << SHIFT) + pin.digits[size]
- hi = rem // n
- pout.digits[size] = hi
- rem -= hi * n
- size -= 1
- return rem
-
-def _divrem1(a, n):
- """
- Divide a long integer by a digit, returning both the quotient
- and the remainder as a tuple.
- The sign of a is ignored; n should not be zero.
- """
- assert n > 0 and n <= MASK
- size = len(a.digits)
- z = W_LongObject([0] * size, 1)
- rem = _inplace_divrem1(z, a, n)
- z._normalize()
- return z, rem
-
-def _v_iadd(x, xofs, m, y, n):
- """
- x[0:m] and y[0:n] are digit vectors, LSD first, m >= n required. x[0:n]
- is modified in place, by adding y to it. Carries are propagated as far as
- x[m-1], and the remaining carry (0 or 1) is returned.
- Python adaptation: x is addressed relative to xofs!
- """
- carry = 0;
-
- assert m >= n
- i = xofs
- iend = xofs + n
- while i < iend:
- carry += x[i] + y[i-xofs]
- x[i] = carry & MASK
- carry >>= SHIFT
- assert (carry & 1) == carry
- i += 1
- iend = xofs + m
- while carry and i < iend:
- carry += x[i]
- x[i] = carry & MASK
- carry >>= SHIFT
- assert (carry & 1) == carry
- i += 1
- return carry
-
-def _v_isub(x, xofs, m, y, n):
- """
- x[0:m] and y[0:n] are digit vectors, LSD first, m >= n required. x[0:n]
- is modified in place, by subtracting y from it. Borrows are propagated as
- far as x[m-1], and the remaining borrow (0 or 1) is returned.
- Python adaptation: x is addressed relative to xofs!
- """
- borrow = 0
-
- assert m >= n
- i = xofs
- iend = xofs + n
- while i < iend:
- borrow = x[i] - y[i-xofs] - borrow
- x[i] = borrow & MASK
- borrow >>= SHIFT
- borrow &= 1 # keep only 1 sign bit
- i += 1
- iend = xofs + m
- while borrow and i < iend:
- borrow = x[i] - borrow
- x[i] = borrow & MASK
- borrow >>= SHIFT
- borrow &= 1
- i += 1
- return borrow
-
-
-def _muladd1(a, n, extra):
- """Multiply by a single digit and add a single digit, ignoring the sign.
- """
- size_a = len(a.digits)
- z = W_LongObject([0] * (size_a+1), 1)
- carry = extra
- assert carry & MASK == carry
- i = 0
- while i < size_a:
- carry += a.digits[i] * n
- z.digits[i] = carry & MASK
- carry >>= SHIFT
- i += 1
- z.digits[i] = carry
- z._normalize()
- return z
-
-
-def _x_divrem(v1, w1):
- """ Unsigned long division with remainder -- the algorithm """
- size_w = len(w1.digits)
- d = (MASK+1) // (w1.digits[size_w-1] + 1)
- v = _muladd1(v1, d, 0)
- w = _muladd1(w1, d, 0)
- size_v = len(v.digits)
- size_w = len(w.digits)
- assert size_v >= size_w and size_w > 1 # Assert checks by div()
-
- size_a = size_v - size_w + 1
- a = W_LongObject([0] * size_a, 1)
-
- j = size_v
- k = size_a - 1
- while k >= 0:
- if j >= size_v:
- vj = 0
- else:
- vj = v.digits[j]
- carry = 0
-
- if vj == w.digits[size_w-1]:
- q = MASK
- else:
- q = ((vj << SHIFT) + v.digits[j-1]) // w.digits[size_w-1]
-
- while (w.digits[size_w-2] * q >
- ((
- (vj << SHIFT)
- + v.digits[j-1]
- - q * w.digits[size_w-1]
- ) << SHIFT)
- + v.digits[j-2]):
- q -= 1
- i = 0
- while i < size_w and i+k < size_v:
- z = w.digits[i] * q
- zz = z >> SHIFT
- carry += v.digits[i+k] - z + (zz << SHIFT)
- v.digits[i+k] = carry & MASK
- carry >>= SHIFT
- carry -= zz
- i += 1
-
- if i+k < size_v:
- carry += v.digits[i+k]
- v.digits[i+k] = 0
-
- if carry == 0:
- a.digits[k] = q & MASK
- assert not q >> SHIFT
- else:
- assert carry == -1
- q -= 1
- a.digits[k] = q & MASK
- assert not q >> SHIFT
-
- carry = 0
- i = 0
- while i < size_w and i+k < size_v:
- carry += v.digits[i+k] + w.digits[i]
- v.digits[i+k] = carry & MASK
- carry >>= SHIFT
- i += 1
- j -= 1
- k -= 1
-
- a._normalize()
- rem, _ = _divrem1(v, d)
- return a, rem
-
-
-def _divrem(space, a, b):
- """ Long division with remainder, top-level routine """
- size_a = len(a.digits)
- size_b = len(b.digits)
-
- if b.sign == 0:
- raise OperationError(space.w_ZeroDivisionError,
- space.wrap("long division or modulo by zero"))
-
- if (size_a < size_b or
- (size_a == size_b and
- a.digits[size_a-1] < b.digits[size_b-1])):
- # |a| < |b|
- z = W_LongObject([0], 0)
- rem = a
- return z, rem
- if size_b == 1:
- z, urem = _divrem1(a, b.digits[0])
- rem = W_LongObject([urem], int(urem != 0))
- else:
- z, rem = _x_divrem(a, b)
- # Set the signs.
- # The quotient z has the sign of a*b;
- # the remainder r has the sign of a,
- # so a = b*z + r.
- if a.sign != b.sign:
- z.sign = - z.sign
- if a.sign < 0 and rem.sign != 0:
- rem.sign = - rem.sign
- return z, rem
-
-# ______________ conversions to double _______________
-
-def _AsScaledDouble(v):
- """
- NBITS_WANTED should be > the number of bits in a double's precision,
- but small enough so that 2**NBITS_WANTED is within the normal double
- range. nbitsneeded is set to 1 less than that because the most-significant
- Python digit contains at least 1 significant bit, but we don't want to
- bother counting them (catering to the worst case cheaply).
-
- 57 is one more than VAX-D double precision; I (Tim) don't know of a double
- format with more precision than that; it's 1 larger so that we add in at
- least one round bit to stand in for the ignored least-significant bits.
- """
- NBITS_WANTED = 57
- multiplier = float(1 << SHIFT)
- if v.sign == 0:
- return 0.0, 0
- i = len(v.digits) - 1
- sign = v.sign
- x = float(v.digits[i])
- nbitsneeded = NBITS_WANTED - 1
- # Invariant: i Python digits remain unaccounted for.
- while i > 0 and nbitsneeded > 0:
- i -= 1
- x = x * multiplier + float(v.digits[i])
- nbitsneeded -= SHIFT
- # There are i digits we didn't shift in. Pretending they're all
- # zeroes, the true value is x * 2**(i*SHIFT).
- exponent = i
- assert x > 0.0
- return x * sign, exponent
-
-def isinf(x):
- return x != 0.0 and x / 2 == x
-
-##def ldexp(x, exp):
-## assert type(x) is float
-## lb1 = LONG_BIT - 1
-## multiplier = float(1 << lb1)
-## while exp >= lb1:
-## x *= multiplier
-## exp -= lb1
-## if exp:
-## x *= float(1 << exp)
-## return x
-
-# note that math.ldexp checks for overflows,
-# while the C ldexp is not guaranteed to do.
-# XXX make sure that we don't ignore this!
-# YYY no, we decided to do ignore this!
-
-def _AsDouble(v):
- """ Get a C double from a long int object. """
- x, e = _AsScaledDouble(v)
- if e <= sys.maxint / SHIFT:
- x = math.ldexp(x, e * SHIFT)
- #if not isinf(x):
- # this is checked by math.ldexp
- return x
- raise OverflowError # can't say "long int too large to convert to float"
-
-def _loghelper(func, w_arg):
- """
- A decent logarithm is easy to compute even for huge longs, but libm can't
- do that by itself -- loghelper can. func is log or log10, and name is
- "log" or "log10". Note that overflow isn't possible: a long can contain
- no more than INT_MAX * SHIFT bits, so has value certainly less than
- 2**(2**64 * 2**16) == 2**2**80, and log2 of that is 2**80, which is
- small enough to fit in an IEEE single. log and log10 are even smaller.
- """
- x, e = _AsScaledDouble(w_arg);
- if x <= 0.0:
- raise ValueError
- # Value is ~= x * 2**(e*SHIFT), so the log ~=
- # log(x) + log(2) * e * SHIFT.
- # CAUTION: e*SHIFT may overflow using int arithmetic,
- # so force use of double. */
- return func(x) + (e * float(SHIFT) * func(2.0))
-_loghelper._annspecialcase_ = 'specialize:arg(0)'
-
-def _long_true_divide(space, a, b):
- try:
- ad, aexp = _AsScaledDouble(a)
- bd, bexp = _AsScaledDouble(b)
- if bd == 0.0:
- raise OperationError(space.w_ZeroDivisionError,
- space.wrap("long division or modulo by zero"))
-
- # True value is very close to ad/bd * 2**(SHIFT*(aexp-bexp))
- ad /= bd # overflow/underflow impossible here
- aexp -= bexp
- if aexp > sys.maxint / SHIFT:
- raise OverflowError
- elif aexp < -(sys.maxint / SHIFT):
- return 0.0 # underflow to 0
- ad = math.ldexp(ad, aexp * SHIFT)
- ##if isinf(ad): # ignore underflow to 0.0
- ## raise OverflowError
- # math.ldexp checks and raises
- return ad
- except OverflowError:
- raise OperationError(space.w_OverflowError,
- space.wrap("long/long too large for a float"))
-
-def _FromDouble(space, dval):
- """ Create a new long int object from a C double """
- neg = 0
- if isinf(dval):
- raise OverflowError
- if dval < 0.0:
- neg = 1
- dval = -dval
- frac, expo = math.frexp(dval) # dval = frac*2**expo; 0.0 <= frac < 1.0
- if expo <= 0:
- return W_LongObject([0], 0)
- ndig = (expo-1) // SHIFT + 1 # Number of 'digits' in result
- v = W_LongObject([0] * ndig, 1)
- frac = math.ldexp(frac, (expo-1) % SHIFT + 1)
- for i in range(ndig-1, -1, -1):
- bits = int(frac) & MASK # help the future annotator?
- v.digits[i] = bits
- frac -= float(bits)
- frac = math.ldexp(frac, SHIFT)
- if neg:
- v.sign = -1
- return v
-
-def _l_divmod(space, v, w):
- """
- The / and % operators are now defined in terms of divmod().
- The expression a mod b has the value a - b*floor(a/b).
- The _divrem function gives the remainder after division of
- |a| by |b|, with the sign of a. This is also expressed
- as a - b*trunc(a/b), if trunc truncates towards zero.
- Some examples:
- a b a rem b a mod b
- 13 10 3 3
- -13 10 -3 7
- 13 -10 3 -7
- -13 -10 -3 -3
- So, to get from rem to mod, we have to add b if a and b
- have different signs. We then subtract one from the 'div'
- part of the outcome to keep the invariant intact.
- """
- div, mod = _divrem(space, v, w)
- if mod.sign * w.sign == -1:
- mod = add__Long_Long(space, mod, w)
- one = W_LongObject([1], 1)
- div = sub__Long_Long(space, div, one)
- return div, mod
-
-
-def _format(a, base, addL):
- """
- Convert a long int object to a string, using a given conversion base.
- Return a string object.
- If base is 8 or 16, add the proper prefix '0' or '0x'.
- """
- size_a = len(a.digits)
-
- assert base >= 2 and base <= 36
-
- sign = False
-
- # Compute a rough upper bound for the length of the string
- i = base
- bits = 0
- while i > 1:
- bits += 1
- i >>= 1
- i = 5 + int(bool(addL)) + (size_a*SHIFT + bits-1) // bits
- s = [chr(0)] * i
- p = i
- if addL:
- p -= 1
- s[p] = 'L'
- if a.sign < 0:
- sign = True
-
- if a.sign == 0:
- p -= 1
- s[p] = '0'
- elif (base & (base - 1)) == 0:
- # JRH: special case for power-of-2 bases
- accum = 0
- accumbits = 0 # # of bits in accum
- basebits = 1 # # of bits in base-1
- i = base
- while 1:
- i >>= 1
- if i <= 1:
- break
- basebits += 1
-
- for i in range(size_a):
- accum |= a.digits[i] << accumbits
- accumbits += SHIFT
- assert accumbits >= basebits
- while 1:
- cdigit = accum & (base - 1)
- if cdigit < 10:
- cdigit += ord('0')
- else:
- cdigit += ord('A') - 10
- assert p > 0
- p -= 1
- s[p] = chr(cdigit)
- accumbits -= basebits
- accum >>= basebits
- if i < size_a - 1:
- if accumbits < basebits:
- break
- else:
- if accum <= 0:
- break
- else:
- # Not 0, and base not a power of 2. Divide repeatedly by
- # base, but for speed use the highest power of base that
- # fits in a digit.
- size = size_a
- pin = a # just for similarity to C source which uses the array
- # powbase <- largest power of base that fits in a digit.
- powbase = base # powbase == base ** power
- power = 1
- while 1:
- newpow = powbase * base
- if newpow >> SHIFT: # doesn't fit in a digit
- break
- powbase = newpow
- power += 1
-
- # Get a scratch area for repeated division.
- scratch = W_LongObject([0] * size, 1)
-
- # Repeatedly divide by powbase.
- while 1:
- ntostore = power
- rem = _inplace_divrem1(scratch, pin, powbase, size)
- pin = scratch # no need to use a again
- if pin.digits[size - 1] == 0:
- size -= 1
-
- # Break rem into digits.
- assert ntostore > 0
- while 1:
- nextrem = rem // base
- c = rem - nextrem * base
- assert p > 0
- if c < 10:
- c += ord('0')
- else:
- c += ord('A') - 10
- p -= 1
- s[p] = chr(c)
- rem = nextrem
- ntostore -= 1
- # Termination is a bit delicate: must not
- # store leading zeroes, so must get out if
- # remaining quotient and rem are both 0.
- if not (ntostore and (size or rem)):
- break
- if size == 0:
- break
-
- if base == 8:
- if a.sign != 0:
- p -= 1
- s[p] = '0'
- elif base == 16:
- p -= 1
- s[p] ='x'
- p -= 1
- s[p] = '0'
- elif base != 10:
- p -= 1
- s[p] = '#'
- p -= 1
- s[p] = chr(ord('0') + base % 10)
- if base > 10:
- p -= 1
- s[p] = chr(ord('0') + base // 10)
- if sign:
- p -= 1
- s[p] = '-'
-
- assert p >= 0 # otherwise, buffer overflow (this is also a
- # hint for the annotator for the slice below)
- if p == 0:
- return ''.join(s)
- else:
- return ''.join(s[p:])
-
-
-def _bitwise(space, a, op, b): # '&', '|', '^'
- """ Bitwise and/or/xor operations """
-
- if a.sign < 0:
- a = invert__Long(space, a)
- maska = MASK
- else:
- maska = 0
- if b.sign < 0:
- b = invert__Long(space, b)
- maskb = MASK
- else:
- maskb = 0
-
- negz = 0
- if op == '^':
- if maska != maskb:
- maska ^= MASK
- negz = -1
- elif op == '&':
- if maska and maskb:
- op = '|'
- maska ^= MASK
- maskb ^= MASK
- negz = -1
- elif op == '|':
- if maska or maskb:
- op = '&'
- maska ^= MASK
- maskb ^= MASK
- negz = -1
-
- # JRH: The original logic here was to allocate the result value (z)
- # as the longer of the two operands. However, there are some cases
- # where the result is guaranteed to be shorter than that: AND of two
- # positives, OR of two negatives: use the shorter number. AND with
- # mixed signs: use the positive number. OR with mixed signs: use the
- # negative number. After the transformations above, op will be '&'
- # iff one of these cases applies, and mask will be non-0 for operands
- # whose length should be ignored.
-
- size_a = len(a.digits)
- size_b = len(b.digits)
- if op == '&':
- if maska:
- size_z = size_b
- else:
- if maskb:
- size_z = size_a
- else:
- size_z = min(size_a, size_b)
- else:
- size_z = max(size_a, size_b)
-
- z = W_LongObject([0] * size_z, 1)
-
- for i in range(size_z):
- if i < size_a:
- diga = a.digits[i] ^ maska
- else:
- diga = maska
- if i < size_b:
- digb = b.digits[i] ^ maskb
- else:
- digb = maskb
- if op == '&':
- z.digits[i] = diga & digb
- elif op == '|':
- z.digits[i] = diga | digb
- elif op == '^':
- z.digits[i] = diga ^ digb
-
- z._normalize()
- if negz == 0:
- return z
- return invert__Long(space, z)
-_bitwise._annspecialcase_ = "specialize:arg(2)"
-
-def _AsLong(v):
- """
- Get an integer from a long int object.
- Raises OverflowError if overflow occurs.
- """
- # This version by Tim Peters
- i = len(v.digits) - 1
- sign = v.sign
- if not sign:
- return 0
- x = r_uint(0)
- while i >= 0:
- prev = x
- x = (x << SHIFT) + v.digits[i]
- if (x >> SHIFT) != prev:
- raise OverflowError
- i -= 1
-
- # Haven't lost any bits, but if the sign bit is set we're in
- # trouble *unless* this is the min negative number. So,
- # trouble iff sign bit set && (positive || some bit set other
- # than the sign bit).
- if intmask(x) < 0 and (sign > 0 or (x << 1) != 0):
- raise OverflowError
- return intmask(x * sign)
-
-def _hash(v):
- # This is designed so that Python ints and longs with the
- # same value hash to the same value, otherwise comparisons
- # of mapping keys will turn out weird
- i = len(v.digits) - 1
- sign = v.sign
- x = 0
- LONG_BIT_SHIFT = LONG_BIT - SHIFT
- while i >= 0:
- # Force a native long #-bits (32 or 64) circular shift
- x = ((x << SHIFT) & ~MASK) | ((x >> LONG_BIT_SHIFT) & MASK)
- x += v.digits[i]
- i -= 1
- x = intmask(x * sign)
- return x
-
-#_________________________________________________________________
-
-# a few internal helpers
-
-DEC_PER_DIGIT = 1
-while int('9' * DEC_PER_DIGIT) < MASK:
- DEC_PER_DIGIT += 1
-DEC_PER_DIGIT -= 1
-DEC_MAX = 10 ** DEC_PER_DIGIT
-
-def _decimalstr_to_long(space, s):
- # a string that has been already parsed to be decimal and valid,
- # is turned into a long
- p = 0
- lim = len(s)
- sign = False
- if s[p] == '-':
- sign = True
- p += 1
- elif s[p] == '+':
- p += 1
-
- a = W_LongObject.fromint(space, 0)
- cnt = DEC_PER_DIGIT
- tens = 1
- dig = 0
- ord0 = ord('0')
- while p < lim:
- dig = dig * 10 + ord(s[p]) - ord0
- p += 1
- tens *= 10
- if tens == DEC_MAX or p == lim:
- a = _muladd1(a, tens, dig)
- tens = 1
- dig = 0
- if sign:
- a.sign = -1
- return a
-
-def _count_bits(a):
- # return the number of bits in the digits
- if a.sign == 0:
- return 0
- p = len(a.digits) - 1
- bits = SHIFT * p
- digit = a.digits[p]
- while digit:
- digit >>= 1
- bits += 1
- return bits
-
-def _get_odd(a):
- # Note: this is a tiny optimization.
- # Instead of implementing a general "get_bit" operation,
- # which would be expensive for negative numbers,
- # get_odd has the nice feature that it is always correct,
- # no matter what the sign is (two's complement)
- return a.digits[0] & 1
Modified: pypy/dist/pypy/objspace/std/longtype.py
==============================================================================
--- pypy/dist/pypy/objspace/std/longtype.py (original)
+++ pypy/dist/pypy/objspace/std/longtype.py Tue Oct 24 21:30:14 2006
@@ -35,14 +35,7 @@
w_value = w_obj
elif space.is_true(space.isinstance(w_obj, space.w_int)):
intval = space.int_w(w_obj)
- # xxx this logic needs to be put in 1 place
- if intval < 0:
- sign = -1
- elif intval > 0:
- sign = 1
- else:
- sign = 0
- w_value = W_LongObject([abs(intval)], sign)
+ w_value = W_LongObject.fromint(space, intval)
else:
raise OperationError(space.w_ValueError,
space.wrap("value can't be converted to long"))
@@ -66,7 +59,7 @@
space.wrap(e.msg))
w_obj = space.allocate_instance(W_LongObject, w_longtype)
- W_LongObject.__init__(w_obj, w_value.digits, w_value.sign)
+ W_LongObject.__init__(w_obj, w_value.num)
return w_obj
# ____________________________________________________________
Modified: pypy/dist/pypy/objspace/std/marshal_impl.py
==============================================================================
--- pypy/dist/pypy/objspace/std/marshal_impl.py (original)
+++ pypy/dist/pypy/objspace/std/marshal_impl.py Tue Oct 24 21:30:14 2006
@@ -243,15 +243,17 @@
typecode and have our own magic number for pickling"""
m.start(TYPE_LONG)
- lng = len(w_long.digits)
- if w_long.sign < 0:
+ # XXX access internals
+ lng = len(w_long.num.digits)
+ if w_long.num.sign < 0:
m.put_int(-lng)
else:
m.put_int(lng)
- for digit in w_long.digits:
+ for digit in w_long.num.digits:
m.put_short(digit)
def unmarshal_Long(space, u, tc):
+ from pypy.rpython import rlong
lng = u.get_int()
if lng < 0:
sign = -1
@@ -268,8 +270,9 @@
raise_exception(space, 'bad marshal data')
digits[i] = digit
i += 1
- w_long = W_LongObject(digits, sign)
- w_long._normalize()
+ # XXX poking at internals
+ w_long = W_LongObject(rlong.rlong(digits, sign))
+ w_long.num._normalize()
return w_long
register(TYPE_LONG, unmarshal_Long)
Modified: pypy/dist/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/dist/pypy/objspace/std/objspace.py (original)
+++ pypy/dist/pypy/objspace/std/objspace.py Tue Oct 24 21:30:14 2006
@@ -301,14 +301,12 @@
#print 'wrapping', x, '->', w_result
return w_result
if isinstance(x, base_int):
- from pypy.objspace.std.longobject import args_from_rarith_int
- return W_LongObject(*args_from_rarith_int(x))
+ return W_LongObject.fromrarith_int(x)
# _____ below here is where the annotator should not get _____
if isinstance(x, long):
- from pypy.objspace.std.longobject import args_from_long
- return W_LongObject(*args_from_long(x))
+ return W_LongObject.fromlong(x)
if isinstance(x, slice):
return W_SliceObject(self.wrap(x.start),
self.wrap(x.stop),
Modified: pypy/dist/pypy/objspace/std/strutil.py
==============================================================================
--- pypy/dist/pypy/objspace/std/strutil.py (original)
+++ pypy/dist/pypy/objspace/std/strutil.py Tue Oct 24 21:30:14 2006
@@ -413,39 +413,36 @@
# a few abbreviations
from pypy.objspace.std import longobject
mklong = longobject.W_LongObject.fromint
- d2long = longobject._decimalstr_to_long
+ d2long = longobject.W_LongObject.fromdecimalstr
adlong = longobject.add__Long_Long
- long2i = longobject._AsLong
- double = longobject._AsDouble
- longup = longobject._impl_long_long_pow
+ longup = longobject.pow__Long_Long_None
multip = longobject.mul__Long_Long
divide = longobject.div__Long_Long
- bitlen = longobject._count_bits
lshift = longobject.lshift__Long_Long
rshift = longobject.rshift__Long_Long
- getodd = longobject._get_odd
# 4) compute the exponent and truncate to +-400
if not exponent:
exponent = '0'
- w_le = d2long(space, exponent)
+ w_le = d2long(exponent)
w_le = adlong(space, w_le, mklong(space, dexp))
try:
- e = long2i(w_le)
+ e = w_le.toint()
except OverflowError:
- e = w_le.sign * 400
+ # XXX poking at internals
+ e = w_le.num.sign * 400
if e >= 400:
e = 400
elif e <= -400:
e = -400
# 5) compute the value using long math and proper rounding.
- w_lr = d2long(space, digits)
+ w_lr = d2long(digits)
w_10 = mklong(space, 10)
w_1 = mklong(space, 1)
if e >= 0:
bits = 0
- w_pten = longup(space, w_10, mklong(space, e), None)
+ w_pten = longup(space, w_10, mklong(space, e), space.w_None)
w_m = multip(space, w_lr, w_pten)
else:
# compute a sufficiently large scale
@@ -460,7 +457,7 @@
# Shift it and round the last bit.
# first estimate the bits and do a big shift
- mbits = bitlen(w_m)
+ mbits = w_m._count_bits()
needed = MANTISSA_BITS
if mbits > needed:
if mbits > needed+1:
@@ -469,12 +466,12 @@
bits += shifted
# do the rounding
bits += 1
- round = getodd(w_m)
+ round = w_m.is_odd()
w_m = rshift(space, w_m, w_1)
w_m = adlong(space, w_m, mklong(space, round))
try:
- r = math.ldexp(double(w_m), bits)
+ r = math.ldexp(w_m.tofloat(), bits)
# XXX I guess we do not check for overflow in ldexp as we agreed to!
if r == 2*r and r != 0.0:
raise OverflowError
Modified: pypy/dist/pypy/objspace/std/test/test_longobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/test/test_longobject.py (original)
+++ pypy/dist/pypy/objspace/std/test/test_longobject.py Tue Oct 24 21:30:14 2006
@@ -1,357 +1,11 @@
import autopath
+import py
import sys
-from random import random, randint
from pypy.objspace.std import longobject as lobj
from pypy.objspace.std.objspace import FailedToImplement
from pypy.interpreter.error import OperationError
from pypy.rpython.rarithmetic import r_uint
-
-def gen_signs(l):
- for s in l:
- if s == 0:
- yield s
- else:
- yield s
- yield -s
-
-
-class TestW_LongObject:
-
- def test_args_from_long(self):
- BASE = 1 << lobj.SHIFT
- assert lobj.args_from_long(0) == ([0], 0)
- assert lobj.args_from_long(17) == ([17], 1)
- assert lobj.args_from_long(BASE-1) == ([BASE-1], 1)
- assert lobj.args_from_long(BASE) == ([0, 1], 1)
- assert lobj.args_from_long(BASE**2) == ([0, 0, 1], 1)
- assert lobj.args_from_long(-17) == ([17], -1)
- assert lobj.args_from_long(-(BASE-1)) == ([BASE-1], -1)
- assert lobj.args_from_long(-BASE) == ([0, 1], -1)
- assert lobj.args_from_long(-(BASE**2)) == ([0, 0, 1], -1)
- assert lobj.args_from_long(-sys.maxint-1) == (
- lobj.digits_for_most_neg_long(-sys.maxint-1), -1)
-
- def test_args_from_int(self):
- BASE = 1 << lobj.SHIFT
- assert lobj.args_from_rarith_int(0) == ([0], 0)
- assert lobj.args_from_rarith_int(17) == ([17], 1)
- assert lobj.args_from_rarith_int(BASE-1) == ([BASE-1], 1)
- assert lobj.args_from_rarith_int(BASE) == ([0, 1], 1)
- assert lobj.args_from_rarith_int(BASE**2) == ([0, 0, 1], 1)
- assert lobj.args_from_rarith_int(-17) == ([17], -1)
- assert lobj.args_from_rarith_int(-(BASE-1)) == ([BASE-1], -1)
- assert lobj.args_from_rarith_int(-BASE) == ([0, 1], -1)
- assert lobj.args_from_rarith_int(-(BASE**2)) == ([0, 0, 1], -1)
- assert lobj.args_from_rarith_int(-sys.maxint-1) == (
- lobj.digits_for_most_neg_long(-sys.maxint-1), -1)
-
- def test_args_from_uint(self):
- BASE = 1 << lobj.SHIFT
- assert lobj.args_from_rarith_int(r_uint(0)) == ([0], 0)
- assert lobj.args_from_rarith_int(r_uint(17)) == ([17], 1)
- assert lobj.args_from_rarith_int(r_uint(BASE-1)) == ([BASE-1], 1)
- assert lobj.args_from_rarith_int(r_uint(BASE)) == ([0, 1], 1)
- assert lobj.args_from_rarith_int(r_uint(BASE**2)) == ([0, 0, 1], 1)
- assert lobj.args_from_rarith_int(r_uint(sys.maxint)) == (
- lobj.args_from_long(sys.maxint))
- assert lobj.args_from_rarith_int(r_uint(sys.maxint+1)) == (
- lobj.args_from_long(sys.maxint+1))
- assert lobj.args_from_rarith_int(r_uint(2*sys.maxint+1)) == (
- lobj.args_from_long(2*sys.maxint+1))
-
- def test_add(self):
- x = 123456789123456789000000L
- y = 123858582373821923936744221L
- for i in [-1, 1]:
- for j in [-1, 1]:
- f1 = lobj.W_LongObject(*lobj.args_from_long(x * i))
- f2 = lobj.W_LongObject(*lobj.args_from_long(y * j))
- result = lobj.add__Long_Long(self.space, f1, f2)
- assert result.longval() == x * i + y * j
-
- def test_sub(self):
- x = 12378959520302182384345L
- y = 88961284756491823819191823L
- for i in [-1, 1]:
- for j in [-1, 1]:
- f1 = lobj.W_LongObject(*lobj.args_from_long(x * i))
- f2 = lobj.W_LongObject(*lobj.args_from_long(y * j))
- result = lobj.sub__Long_Long(self.space, f1, f2)
- assert result.longval() == x * i - y * j
-
- def test_subzz(self):
- w_l0 = lobj.W_LongObject([0])
- assert self.space.sub(w_l0, w_l0).longval() == 0
-
- def test_mul(self):
- x = -1238585838347L
- y = 585839391919233L
- f1 = lobj.W_LongObject(*lobj.args_from_long(x))
- f2 = lobj.W_LongObject(*lobj.args_from_long(y))
- result = lobj.mul__Long_Long(self.space, f1, f2)
- assert result.longval() == x * y
- # also test a * a, it has special code
- result = lobj.mul__Long_Long(self.space, f1, f1)
- assert result.longval() == x * x
-
- def test__inplace_divrem1(self):
- # signs are not handled in the helpers!
- x = 1238585838347L
- y = 3
- f1 = lobj.W_LongObject(*lobj.args_from_long(x))
- f2 = y
- remainder = lobj._inplace_divrem1(f1, f1, f2)
- assert (f1.longval(), remainder) == divmod(x, y)
-
- def test__divrem1(self):
- # signs are not handled in the helpers!
- x = 1238585838347L
- y = 3
- f1 = lobj.W_LongObject(*lobj.args_from_long(x))
- f2 = y
- div, rem = lobj._divrem1(f1, f2)
- assert (div.longval(), rem) == divmod(x, y)
-
- def test__muladd1(self):
- x = 1238585838347L
- y = 3
- z = 42
- f1 = lobj.W_LongObject(*lobj.args_from_long(x))
- f2 = y
- f3 = z
- prod = lobj._muladd1(f1, f2, f3)
- assert prod.longval() == x * y + z
-
- def test__x_divrem(self):
- x = 12345678901234567890L
- for i in range(100):
- y = long(randint(0, 1 << 30))
- y <<= 30
- y += randint(0, 1 << 30)
- f1 = lobj.W_LongObject(*lobj.args_from_long(x))
- f2 = lobj.W_LongObject(*lobj.args_from_long(y))
- div, rem = lobj._x_divrem(f1, f2)
- assert div.longval(), rem.longval() == divmod(x, y)
-
- def test__divrem(self):
- x = 12345678901234567890L
- for i in range(100):
- y = long(randint(0, 1 << 30))
- y <<= 30
- y += randint(0, 1 << 30)
- for sx, sy in (1, 1), (1, -1), (-1, -1), (-1, 1):
- sx *= x
- sy *= y
- f1 = lobj.W_LongObject(*lobj.args_from_long(sx))
- f2 = lobj.W_LongObject(*lobj.args_from_long(sy))
- div, rem = lobj._x_divrem(f1, f2)
- assert div.longval(), rem.longval() == divmod(sx, sy)
-
- def test__AsDouble(self):
- x = 12345678901234567890L ** 10
- f1 = lobj.W_LongObject(*lobj.args_from_long(x))
- d = lobj._AsDouble(f1)
- assert d == float(x)
- x = x ** 100
- f1 = lobj.W_LongObject(*lobj.args_from_long(x))
- assert raises(OverflowError, lobj._AsDouble, f1)
-
- def test__FromDouble(self):
- x = 1234567890.1234567890
- f1 = lobj._FromDouble(self.space, x)
- y = lobj._AsDouble(f1)
- assert f1.longval() == long(x)
- # check overflow
- #x = 12345.6789e10000000000000000000000000000
- # XXX don't use such consts.Marshal doesn't handle them right.
- x = 12345.6789e200
- x *= x
- assert raises(OverflowError, lobj._FromDouble, self.space, x)
-
- # testing Karatsuba stuff
- def test__v_iadd(self):
- f1 = lobj.W_LongObject([lobj.MASK] * 10, 1)
- f2 = lobj.W_LongObject([1], 1)
- carry = lobj._v_iadd(f1.digits, 1, len(f1.digits)-1, f2.digits, 1)
- assert carry == 1
- assert f1.longval() == lobj.MASK
-
- def test__v_isub(self):
- f1 = lobj.W_LongObject([lobj.MASK] + [0] * 9 + [1], 1)
- f2 = lobj.W_LongObject([1], 1)
- borrow = lobj._v_isub(f1.digits, 1, len(f1.digits)-1, f2.digits, 1)
- assert borrow == 0
- assert f1.longval() == (1 << lobj.SHIFT) ** 10 - 1
-
- def test__kmul_split(self):
- split = 5
- diglo = [0] * split
- dighi = [lobj.MASK] * split
- f1 = lobj.W_LongObject(diglo + dighi, 1)
- hi, lo = lobj._kmul_split(f1, split)
- assert lo.digits == [0]
- assert hi.digits == dighi
-
- def test__k_mul(self):
- digs= lobj.KARATSUBA_CUTOFF * 5
- f1 = lobj.W_LongObject([lobj.MASK] * digs, 1)
- f2 = lobj._x_add(f1,lobj.W_LongObject([1], 1))
- ret = lobj._k_mul(f1, f2)
- assert ret.longval() == f1.longval() * f2.longval()
-
- def test__k_lopsided_mul(self):
- digs_a = lobj.KARATSUBA_CUTOFF + 3
- digs_b = 3 * digs_a
- f1 = lobj.W_LongObject([lobj.MASK] * digs_a, 1)
- f2 = lobj.W_LongObject([lobj.MASK] * digs_b, 1)
- ret = lobj._k_lopsided_mul(f1, f2)
- assert ret.longval() == f1.longval() * f2.longval()
-
- def test_eq(self):
- x = 5858393919192332223L
- y = 585839391919233111223311112332L
- f1 = lobj.W_LongObject(*lobj.args_from_long(x))
- f2 = lobj.W_LongObject(*lobj.args_from_long(-x))
- f3 = lobj.W_LongObject(*lobj.args_from_long(y))
- assert self.space.is_true(lobj.eq__Long_Long(self.space, f1, f1))
- assert self.space.is_true(lobj.eq__Long_Long(self.space, f2, f2))
- assert self.space.is_true(lobj.eq__Long_Long(self.space, f3, f3))
- assert not self.space.is_true(lobj.eq__Long_Long(self.space, f1, f2))
- assert not self.space.is_true(lobj.eq__Long_Long(self.space, f1, f3))
-
- def test_lt(self):
- val = [0, 0x111111111111, 0x111111111112, 0x111111111112FFFF]
- for x in gen_signs(val):
- for y in gen_signs(val):
- f1 = lobj.W_LongObject(*lobj.args_from_long(x))
- f2 = lobj.W_LongObject(*lobj.args_from_long(y))
- assert (x < y) == self.space.is_true(
- lobj.lt__Long_Long(self.space, f1, f2))
-
- def test_int_conversion(self):
- f1 = lobj.W_LongObject(*lobj.args_from_long(12332))
- f2 = lobj.delegate_Int2Long(self.space, self.space.newint(12332))
- assert f2.longval() == f1.longval()
- assert lobj.int__Long(self.space, f2).intval == 12332
- assert lobj.int_w__Long(self.space, f2) == 12332
- assert lobj.long__Int(self.space, self.space.wrap(42)).longval() == 42
- assert lobj.long__Int(self.space, self.space.wrap(-42)).longval() == -42
-
- u = lobj.uint_w__Long(self.space, f2)
- assert u == 12332
- assert type(u) is r_uint
-
- def test_conversions(self):
- space = self.space
- for v in (0, 1, -1, sys.maxint, -sys.maxint-1):
- assert lobj.W_LongObject(*lobj.args_from_long(v)).longval() == v
- w_v = space.newint(v)
- for w_lv in (lobj.long__Int(space, w_v),
- lobj.delegate_Int2Long(self.space, w_v)):
- assert w_lv.longval() == v
- assert lobj.int_w__Long(space, w_lv) == v
- assert space.is_true(space.isinstance(lobj.int__Long(space, w_lv), space.w_int))
- assert space.eq_w(lobj.int__Long(space, w_lv), w_v)
-
- if v >= 0:
- u = lobj.uint_w__Long(space, w_lv)
- assert u == v
- assert type(u) is r_uint
- else:
- space.raises_w(space.w_ValueError, lobj.uint_w__Long, space, w_lv)
-
- w_toobig_lv1 = lobj.W_LongObject(*lobj.args_from_long(sys.maxint+1))
- assert w_toobig_lv1.longval() == sys.maxint+1
- w_toobig_lv2 = lobj.W_LongObject(*lobj.args_from_long(sys.maxint+2))
- assert w_toobig_lv2.longval() == sys.maxint+2
- w_toobig_lv3 = lobj.W_LongObject(*lobj.args_from_long(-sys.maxint-2))
- assert w_toobig_lv3.longval() == -sys.maxint-2
-
- for w_lv in (w_toobig_lv1, w_toobig_lv2, w_toobig_lv3):
- space.raises_w(space.w_OverflowError, lobj.int_w__Long, space, w_lv)
- assert space.is_true(space.isinstance(lobj.int__Long(space, w_lv), space.w_long))
-
- w_lmaxuint = lobj.W_LongObject(*lobj.args_from_long(2*sys.maxint+1))
- w_toobig_lv4 = lobj.W_LongObject(*lobj.args_from_long(2*sys.maxint+2))
-
- u = lobj.uint_w__Long(space, w_lmaxuint)
- assert u == 2*sys.maxint+1
-
- space.raises_w(space.w_ValueError, lobj.uint_w__Long, space, w_toobig_lv3)
- space.raises_w(space.w_OverflowError, lobj.uint_w__Long, space, w_toobig_lv4)
-
-
-
- def test_pow_lll(self):
- x = 10L
- y = 2L
- z = 13L
- f1 = lobj.W_LongObject(*lobj.args_from_long(x))
- f2 = lobj.W_LongObject(*lobj.args_from_long(y))
- f3 = lobj.W_LongObject(*lobj.args_from_long(z))
- v = lobj.pow__Long_Long_Long(self.space, f1, f2, f3)
- assert v.longval() == pow(x, y, z)
- f1, f2, f3 = [lobj.W_LongObject(*lobj.args_from_long(i))
- for i in (10L, -1L, 42L)]
- self.space.raises_w(self.space.w_TypeError,
- lobj.pow__Long_Long_Long,
- self.space, f1, f2, f3)
- f1, f2, f3 = [lobj.W_LongObject(*lobj.args_from_long(i))
- for i in (10L, 5L, 0L)]
- self.space.raises_w(self.space.w_ValueError,
- lobj.pow__Long_Long_Long,
- self.space, f1, f2, f3)
-
- def test_pow_lln(self):
- x = 10L
- y = 2L
- f1 = lobj.W_LongObject(*lobj.args_from_long(x))
- f2 = lobj.W_LongObject(*lobj.args_from_long(y))
- v = lobj.pow__Long_Long_None(self.space, f1, f2, self.space.w_None)
- assert v.longval() == x ** y
-
- def test_normalize(self):
- f1 = lobj.W_LongObject([1, 0], 1)
- f1._normalize()
- assert len(f1.digits) == 1
- f0 = lobj.W_LongObject([0], 0)
- assert self.space.is_true(
- self.space.eq(lobj.sub__Long_Long(self.space, f1, f1), f0))
-
- def test_invert(self):
- x = 3 ** 40
- f1 = lobj.W_LongObject(*lobj.args_from_long(x))
- f2 = lobj.W_LongObject(*lobj.args_from_long(-x))
- r1 = lobj.invert__Long(self.space, f1)
- r2 = lobj.invert__Long(self.space, f2)
- assert r1.longval() == -(x + 1)
- assert r2.longval() == -(-x + 1)
-
- def test_shift(self):
- negative = lobj.W_LongObject(*lobj.args_from_long(-23))
- big = lobj.W_LongObject(*lobj.args_from_long(2L ** 100L))
- for x in gen_signs([3L ** 30L, 5L ** 20L, 7 ** 300, 0L, 1L]):
- f1 = lobj.W_LongObject(*lobj.args_from_long(x))
- self.space.raises_w(self.space.w_ValueError,
- lobj.lshift__Long_Long, self.space, f1,
- negative)
- self.space.raises_w(self.space.w_ValueError,
- lobj.rshift__Long_Long, self.space, f1,
- negative)
- self.space.raises_w(self.space.w_OverflowError,
- lobj.lshift__Long_Long, self.space, f1,
- big)
- self.space.raises_w(self.space.w_OverflowError,
- lobj.rshift__Long_Long, self.space, f1,
- big)
- for y in [0L, 1L, 32L, 2304L, 11233L, 3 ** 9]:
- f2 = lobj.W_LongObject(*lobj.args_from_long(y))
- res1 = lobj.lshift__Long_Long(self.space, f1, f2).longval()
- res2 = lobj.rshift__Long_Long(self.space, f1, f2).longval()
- assert res1 == x << y
- assert res2 == x >> y
-
class AppTestLong:
def test_add(self):
assert int(123L + 12443L) == 123 + 12443
@@ -470,14 +124,3 @@
assert str(long(n)) == str(n)
-class TestTranslatable:
-
- def test_args_from_rarith_int(self):
- from pypy.rpython.test.test_llinterp import interpret
- def fn():
- return (lobj.args_from_rarith_int(0),
- lobj.args_from_rarith_int(17),
- lobj.args_from_rarith_int(-17),
- lobj.args_from_rarith_int(r_uint(0)),
- lobj.args_from_rarith_int(r_uint(17)))
- interpret(fn, [])
Modified: pypy/dist/pypy/rpython/rarithmetic.py
==============================================================================
--- pypy/dist/pypy/rpython/rarithmetic.py (original)
+++ pypy/dist/pypy/rpython/rarithmetic.py Tue Oct 24 21:30:14 2006
@@ -44,6 +44,9 @@
LONG_MASK = _Ltest*2-1
LONG_TEST = _Ltest
+def isinf(x):
+ return x != 0.0 and x / 2 == x
+
def intmask(n):
if isinstance(n, int):
return int(n) # possibly bool->int
More information about the Pypy-commit
mailing list