[pypy-svn] r33637 - in pypy/branch/factor-long-out/pypy: objspace/std objspace/std/test rpython rpython/test
cfbolz at codespeak.net
cfbolz at codespeak.net
Tue Oct 24 11:11:43 CEST 2006
Author: cfbolz
Date: Tue Oct 24 11:11:40 2006
New Revision: 33637
Added:
pypy/branch/factor-long-out/pypy/rpython/rlong.py (contents, props changed)
pypy/branch/factor-long-out/pypy/rpython/test/test_rlong.py (contents, props changed)
Modified:
pypy/branch/factor-long-out/pypy/objspace/std/complexobject.py
pypy/branch/factor-long-out/pypy/objspace/std/floatobject.py
pypy/branch/factor-long-out/pypy/objspace/std/longobject.py
pypy/branch/factor-long-out/pypy/objspace/std/longtype.py
pypy/branch/factor-long-out/pypy/objspace/std/marshal_impl.py
pypy/branch/factor-long-out/pypy/objspace/std/objspace.py
pypy/branch/factor-long-out/pypy/objspace/std/strutil.py
pypy/branch/factor-long-out/pypy/objspace/std/test/test_longobject.py
Log:
first attempt at factoring long out to be useful for general RPython programs.
Not sure if it translates, tests seem to pass.
Modified: pypy/branch/factor-long-out/pypy/objspace/std/complexobject.py
==============================================================================
--- pypy/branch/factor-long-out/pypy/objspace/std/complexobject.py (original)
+++ pypy/branch/factor-long-out/pypy/objspace/std/complexobject.py Tue Oct 24 11:11:40 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/branch/factor-long-out/pypy/objspace/std/floatobject.py
==============================================================================
--- pypy/branch/factor-long-out/pypy/objspace/std/floatobject.py (original)
+++ pypy/branch/factor-long-out/pypy/objspace/std/floatobject.py Tue Oct 24 11:11:40 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/branch/factor-long-out/pypy/objspace/std/longobject.py
==============================================================================
--- pypy/branch/factor-long-out/pypy/objspace/std/longobject.py (original)
+++ pypy/branch/factor-long-out/pypy/objspace/std/longobject.py Tue Oct 24 11:11:40 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/branch/factor-long-out/pypy/objspace/std/longtype.py
==============================================================================
--- pypy/branch/factor-long-out/pypy/objspace/std/longtype.py (original)
+++ pypy/branch/factor-long-out/pypy/objspace/std/longtype.py Tue Oct 24 11:11:40 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/branch/factor-long-out/pypy/objspace/std/marshal_impl.py
==============================================================================
--- pypy/branch/factor-long-out/pypy/objspace/std/marshal_impl.py (original)
+++ pypy/branch/factor-long-out/pypy/objspace/std/marshal_impl.py Tue Oct 24 11:11:40 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/branch/factor-long-out/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/branch/factor-long-out/pypy/objspace/std/objspace.py (original)
+++ pypy/branch/factor-long-out/pypy/objspace/std/objspace.py Tue Oct 24 11:11:40 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/branch/factor-long-out/pypy/objspace/std/strutil.py
==============================================================================
--- pypy/branch/factor-long-out/pypy/objspace/std/strutil.py (original)
+++ pypy/branch/factor-long-out/pypy/objspace/std/strutil.py Tue Oct 24 11:11:40 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/branch/factor-long-out/pypy/objspace/std/test/test_longobject.py
==============================================================================
--- pypy/branch/factor-long-out/pypy/objspace/std/test/test_longobject.py (original)
+++ pypy/branch/factor-long-out/pypy/objspace/std/test/test_longobject.py Tue Oct 24 11:11:40 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, [])
Added: pypy/branch/factor-long-out/pypy/rpython/rlong.py
==============================================================================
--- (empty file)
+++ pypy/branch/factor-long-out/pypy/rpython/rlong.py Tue Oct 24 11:11:40 2006
@@ -0,0 +1,1620 @@
+from pypy.rpython.rarithmetic import LONG_BIT, intmask, r_uint, ovfcheck
+
+import math, sys
+
+# 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
+
+
+USE_KARATSUBA = True # set to False for comparison
+
+# 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).
+
+KARATSUBA_CUTOFF = 70
+KARATSUBA_SQUARE_CUTOFF = 2 * KARATSUBA_CUTOFF
+
+# 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.
+
+FIVEARY_CUTOFF = 8
+
+
+
+class rlong(object):
+ """This is a reimplementation of longs using a list of digits."""
+
+ def __init__(w_self, digits, sign=0):
+ if len(digits) == 0:
+ digits = [0]
+ w_self.digits = DigitArray(digits)
+ w_self.sign = sign
+
+ def fromint(intval):
+ if intval < 0:
+ sign = -1
+ ival = r_uint(-intval)
+ elif intval > 0:
+ sign = 1
+ ival = r_uint(intval)
+ else:
+ return rlong([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 = rlong([0] * ndigits, sign)
+ t = ival
+ p = 0
+ while t:
+ v.digits[p] = intmask(t & MASK)
+ t >>= SHIFT
+ p += 1
+ return v
+ fromint = staticmethod(fromint)
+
+ def frombool(b):
+ return rlong([b & MASK], int(b))
+ frombool = staticmethod(frombool)
+
+ def fromlong(l):
+ return rlong(*args_from_long(l))
+ fromlong = staticmethod(fromlong)
+
+ def fromfloat(dval):
+ """ Create a new long int object from a float """
+ 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 rlong([0], 0)
+ ndig = (expo-1) // SHIFT + 1 # Number of 'digits' in result
+ v = rlong([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
+ fromfloat = staticmethod(fromfloat)
+
+ def fromrarith_int(i):
+ return rlong(*args_from_rarith_int(i))
+ fromrarith_int._annspecialcase_ = "specialize:argtype(0)"
+ fromrarith_int = staticmethod(fromrarith_int)
+
+ def fromdecimalstr(s):
+ return _decimalstr_to_long(s)
+ fromdecimalstr = staticmethod(fromdecimalstr)
+
+ def toint(self):
+ return _AsLong(self)
+
+ def tobool(self):
+ return self.sign != 0
+
+ def touint(self):
+ if self.sign == -1:
+ raise ValueError("cannot convert negative integer to unsigned int")
+ x = r_uint(0)
+ i = len(self.digits) - 1
+ while i >= 0:
+ prev = x
+ x = (x << SHIFT) + self.digits[i]
+ if (x >> SHIFT) != prev:
+ raise OverflowError(
+ "long int too large to convert to unsigned int")
+ i -= 1
+ return x
+
+ def tofloat(self):
+ return _AsDouble(self)
+
+ 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 is_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
+
+ def repr(self):
+ return _format(self, 10, True)
+
+ def str(self):
+ return _format(self, 10, False)
+
+ def eq(w_long1, w_long2):
+ if (w_long1.sign != w_long2.sign or
+ len(w_long1.digits) != len(w_long2.digits)):
+ return False
+ i = 0
+ ld = len(w_long1.digits)
+ while i < ld:
+ if w_long1.digits[i] != w_long2.digits[i]:
+ return False
+ i += 1
+ return True
+
+ def lt(w_long1, w_long2):
+ if w_long1.sign > w_long2.sign:
+ return False
+ if w_long1.sign < w_long2.sign:
+ return True
+ ld1 = len(w_long1.digits)
+ ld2 = len(w_long2.digits)
+ if ld1 > ld2:
+ if w_long2.sign > 0:
+ return False
+ else:
+ return True
+ elif ld1 < ld2:
+ if w_long2.sign > 0:
+ return True
+ else:
+ return 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 True
+ else:
+ return False
+ elif d1 > d2:
+ if w_long2.sign > 0:
+ return False
+ else:
+ return True
+ i -= 1
+ return False
+
+ def hash(w_value):
+ return _hash(w_value)
+
+ def add(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
+
+ def sub(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
+
+ def mul(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
+
+ def truediv(w_long1, w_long2):
+ div = _long_true_divide(w_long1, w_long2)
+ return div
+
+ def floordiv(w_long1, w_long2):
+ div, mod = w_long1.divmod(w_long2)
+ return div
+
+ def div(w_long1, w_long2):
+ return w_long1.floordiv(w_long2)
+
+ def mod(w_long1, w_long2):
+ div, mod = w_long1.divmod(w_long2)
+ return mod
+
+ def divmod(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(v, w)
+ if mod.sign * w.sign == -1:
+ mod = mod.add(w)
+ one = rlong([1], 1)
+ div = div.sub(one)
+ return div, mod
+
+ def pow(a, b, c=None):
+ 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.
+
+ if b.sign < 0: # if exponent is negative
+ if c is not None:
+ raise TypeError(
+ "pow() 2nd argument "
+ "cannot be negative when 3rd argument specified")
+ # XXX failed to implement
+ raise ValueError("long pow() too negative")
+
+ if c is not None:
+ if c.sign == 0:
+ raise ValueError("pow() 3rd argument cannot be 0")
+
+ # if modulus < 0:
+ # negativeOutput = True
+ # modulus = -modulus
+ if c.sign < 0:
+ negativeOutput = True
+ c = rlong(c.digits, -c.sign)
+
+ # if modulus == 1:
+ # return 0
+ if len(c.digits) == 1 and c.digits[0] == 1:
+ return rlong([0], 0)
+
+ # if base < 0:
+ # base = base % modulus
+ # Having the base positive just makes things easier.
+ if a.sign < 0:
+ a, temp = a.divmod(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 = rlong([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(z, z, c)
+ if bi & j:
+ z = _help_mult(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(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(z, z, c)
+ if index:
+ z = _help_mult(z, table[index], c)
+ j -= 5
+ i -= 1
+
+ if negativeOutput and z.sign != 0:
+ z = z.sub(c)
+ return z
+
+ def neg(w_long1):
+ return rlong(w_long1.digits, -w_long1.sign)
+
+ def abs(w_long):
+ return rlong(w_long.digits, abs(w_long.sign))
+
+ def invert(w_long): #Implement ~x as -(x + 1)
+ return w_long.add(rlong([1], 1)).neg()
+
+ def lshift(w_long1, w_long2):
+ if w_long2.sign < 0:
+ raise ValueError("negative shift count")
+ elif w_long2.sign == 0:
+ return w_long1
+ shiftby = w_long2.toint()
+
+ 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 = rlong([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(w_long1, w_long2):
+ if w_long2.sign < 0:
+ raise ValueError("negative shift count")
+ elif w_long2.sign == 0:
+ return w_long1
+ if w_long1.sign == -1:
+ w_a1 = w_long1.invert()
+ w_a2 = w_a1.rshift(w_long2)
+ return w_a2.invert()
+ shiftby = w_long2.toint()
+
+ a = w_long1
+ wordshift = shiftby // SHIFT
+ newsize = len(a.digits) - wordshift
+ if newsize <= 0:
+ return rlong([0], 0)
+
+ loshift = shiftby % SHIFT
+ hishift = SHIFT - loshift
+ lomask = (1 << hishift) - 1
+ himask = MASK ^ lomask
+ z = rlong([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_(w_long1, w_long2):
+ return _bitwise(w_long1, '&', w_long2)
+
+ def xor(w_long1, w_long2):
+ return _bitwise(w_long1, '^', w_long2)
+
+ def or_(w_long1, w_long2):
+ return _bitwise(w_long1, '|', w_long2)
+
+ def oct(w_long1):
+ return _format(w_long1, 8, True)
+
+ def hex(w_long1):
+ return _format(w_long1, 16, True)
+
+ def log(w_long, base):
+ # base is supposed to be positive or 0.0, which means we use e
+ if base == 10.0:
+ return _loghelper(math.log10, w_long)
+ ret = _loghelper(math.log, w_long)
+ if base != 0.0:
+ ret /= math.log(base)
+ return ret
+
+ def tolong(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 _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
+
+#_________________________________________________________________
+
+# Helper Functions
+
+
+def _help_mult(x, y, c):
+ """
+ Multiply two values, then reduce the result:
+ result = X*Y % c. If c is NULL, skip the mod.
+ """
+ res = x.mul(y)
+ # Perform a modular reduction, X = X % c, but leave X alone if c
+ # is NULL.
+ if c is not None:
+ res, temp = res.divmod(c)
+ res = temp
+ return res
+
+
+
+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 = rlong([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 rlong([0], 0)
+ if a.digits[i] < b.digits[i]:
+ sign = -1
+ a, b = b, a
+ size_a = size_b = i+1
+ z = rlong([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 = rlong([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 = rlong(n.digits[:size_lo], 1)
+ hi = rlong(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 rlong([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 = rlong([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 = rlong([0] * (asize + bsize), 1)
+
+ # Successive slices of b are copied into bslice.
+ #bslice = rlong([0] * asize, 1)
+ # XXX we cannot pre-allocate, see comments below!
+ bslice = rlong([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 = rlong([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 = rlong([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 = rlong([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(a, b):
+ """ Long division with remainder, top-level routine """
+ size_a = len(a.digits)
+ size_b = len(b.digits)
+
+ if b.sign == 0:
+ raise ZeroDivisionError("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 = rlong([0], 0)
+ rem = a
+ return z, rem
+ if size_b == 1:
+ z, urem = _divrem1(a, b.digits[0])
+ rem = rlong([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(a, b):
+ ad, aexp = _AsScaledDouble(a)
+ bd, bexp = _AsScaledDouble(b)
+ if bd == 0.0:
+ raise ZeroDivisionError("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
+
+
+
+
+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 = rlong([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(a, op, b): # '&', '|', '^'
+ """ Bitwise and/or/xor operations """
+
+ if a.sign < 0:
+ a = a.invert()
+ maska = MASK
+ else:
+ maska = 0
+ if b.sign < 0:
+ b.invert()
+ 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 = rlong([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 z.invert()
+_bitwise._annspecialcase_ = "specialize:arg(1)"
+
+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(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 = rlong.fromint(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
+
+
Added: pypy/branch/factor-long-out/pypy/rpython/test/test_rlong.py
==============================================================================
--- (empty file)
+++ pypy/branch/factor-long-out/pypy/rpython/test/test_rlong.py Tue Oct 24 11:11:40 2006
@@ -0,0 +1,398 @@
+from __future__ import division
+import py
+from random import random, randint
+from pypy.rpython.rlong import rlong, SHIFT, MASK
+from pypy.rpython import rlong as lobj
+from pypy.rpython.rarithmetic import r_uint
+import operator, sys
+
+class TestRLong(object):
+ def test_simple(self):
+ for op1 in [-2, -1, 0, 1, 2, 50]:
+ for op2 in [-2, -1, 0, 1, 2, 50]:
+ rl_op1 = rlong.fromint(op1)
+ rl_op2 = rlong.fromint(op2)
+ for op in "add sub mul".split():
+ r1 = getattr(rl_op1, op)(rl_op2)
+ r2 = getattr(operator, op)(op1, op2)
+ assert r1.tolong() == r2
+
+ def test_floordiv(self):
+ for op1 in [-12, -2, -1, 1, 2, 50]:
+ for op2 in [-4, -2, -1, 1, 2, 8]:
+ rl_op1 = rlong.fromint(op1)
+ rl_op2 = rlong.fromint(op2)
+ r1 = rl_op1.floordiv(rl_op2)
+ r2 = op1 // op2
+ assert r1.tolong() == r2
+
+ def test_truediv(self):
+ for op1 in [-12, -2, -1, 1, 2, 50]:
+ for op2 in [-4, -2, -1, 1, 2, 8]:
+ rl_op1 = rlong.fromint(op1)
+ rl_op2 = rlong.fromint(op2)
+ r1 = rl_op1.truediv(rl_op2)
+ r2 = op1 / op2
+ assert r1 == r2
+
+ def test_mod(self):
+ for op1 in [-50, -12, -2, -1, 1, 2, 50, 52]:
+ for op2 in [-4, -2, -1, 1, 2, 8]:
+ rl_op1 = rlong.fromint(op1)
+ rl_op2 = rlong.fromint(op2)
+ r1 = rl_op1.mod(rl_op2)
+ r2 = op1 % op2
+ assert r1.tolong() == r2
+
+ def test_pow(self):
+ for op1 in [-50, -12, -2, -1, 1, 2, 50, 52]:
+ for op2 in [0, 1, 2, 8, 9, 10, 11]:
+ rl_op1 = rlong.fromint(op1)
+ rl_op2 = rlong.fromint(op2)
+ r1 = rl_op1.pow(rl_op2)
+ r2 = op1 ** op2
+ assert r1.tolong() == r2
+
+ def test_touint(self):
+ import sys
+ from pypy.rpython.rarithmetic import r_uint
+ result = r_uint(sys.maxint + 42)
+ rl = rlong.fromint(sys.maxint).add(rlong.fromint(42))
+ assert rl.touint() == result
+
+def gen_signs(l):
+ for s in l:
+ if s == 0:
+ yield s
+ else:
+ yield s
+ yield -s
+
+
+class Test_rlong(object):
+
+ def test_args_from_long(self):
+ BASE = 1 << SHIFT
+ assert rlong.fromlong(0).eq(rlong([0], 0))
+ assert rlong.fromlong(17).eq(rlong([17], 1))
+ assert rlong.fromlong(BASE-1).eq(rlong([BASE-1], 1))
+ assert rlong.fromlong(BASE).eq(rlong([0, 1], 1))
+ assert rlong.fromlong(BASE**2).eq(rlong([0, 0, 1], 1))
+ assert rlong.fromlong(-17).eq(rlong([17], -1))
+ assert rlong.fromlong(-(BASE-1)).eq(rlong([BASE-1], -1))
+ assert rlong.fromlong(-BASE).eq(rlong([0, 1], -1))
+ assert rlong.fromlong(-(BASE**2)).eq(rlong([0, 0, 1], -1))
+# assert rlong.fromlong(-sys.maxint-1).eq(
+# rlong.digits_for_most_neg_long(-sys.maxint-1), -1)
+
+ def test_args_from_int(self):
+ BASE = 1 << SHIFT
+ assert rlong.fromrarith_int(0).eq(rlong([0], 0))
+ assert rlong.fromrarith_int(17).eq(rlong([17], 1))
+ assert rlong.fromrarith_int(BASE-1).eq(rlong([BASE-1], 1))
+ assert rlong.fromrarith_int(BASE).eq(rlong([0, 1], 1))
+ assert rlong.fromrarith_int(BASE**2).eq(rlong([0, 0, 1], 1))
+ assert rlong.fromrarith_int(-17).eq(rlong([17], -1))
+ assert rlong.fromrarith_int(-(BASE-1)).eq(rlong([BASE-1], -1))
+ assert rlong.fromrarith_int(-BASE).eq(rlong([0, 1], -1))
+ assert rlong.fromrarith_int(-(BASE**2)).eq(rlong([0, 0, 1], -1))
+# assert rlong.fromrarith_int(-sys.maxint-1).eq((
+# rlong.digits_for_most_neg_long(-sys.maxint-1), -1)
+
+ def test_args_from_uint(self):
+ BASE = 1 << SHIFT
+ assert rlong.fromrarith_int(r_uint(0)).eq(rlong([0], 0))
+ assert rlong.fromrarith_int(r_uint(17)).eq(rlong([17], 1))
+ assert rlong.fromrarith_int(r_uint(BASE-1)).eq(rlong([BASE-1], 1))
+ assert rlong.fromrarith_int(r_uint(BASE)).eq(rlong([0, 1], 1))
+ assert rlong.fromrarith_int(r_uint(BASE**2)).eq(rlong([0, 0, 1], 1))
+ assert rlong.fromrarith_int(r_uint(sys.maxint)).eq(
+ rlong.fromint(sys.maxint))
+ assert rlong.fromrarith_int(r_uint(sys.maxint+1)).eq(
+ rlong.fromlong(sys.maxint+1))
+ assert rlong.fromrarith_int(r_uint(2*sys.maxint+1)).eq(
+ rlong.fromlong(2*sys.maxint+1))
+
+ def test_add(self):
+ x = 123456789123456789000000L
+ y = 123858582373821923936744221L
+ for i in [-1, 1]:
+ for j in [-1, 1]:
+ f1 = rlong.fromlong(x * i)
+ f2 = rlong.fromlong(y * j)
+ result = f1.add(f2)
+ assert result.tolong() == x * i + y * j
+
+ def test_sub(self):
+ x = 12378959520302182384345L
+ y = 88961284756491823819191823L
+ for i in [-1, 1]:
+ for j in [-1, 1]:
+ f1 = rlong.fromlong(x * i)
+ f2 = rlong.fromlong(y * j)
+ result = f1.sub(f2)
+ assert result.tolong() == x * i - y * j
+
+ def test_subzz(self):
+ w_l0 = rlong.fromint(0)
+ assert w_l0.sub(w_l0).tolong() == 0
+
+ def test_mul(self):
+ x = -1238585838347L
+ y = 585839391919233L
+ f1 = rlong.fromlong(x)
+ f2 = rlong.fromlong(y)
+ result = f1.mul(f2)
+ assert result.tolong() == x * y
+ # also test a * a, it has special code
+ result = f1.mul(f1)
+ assert result.tolong() == x * x
+
+ def test_tofloat(self):
+ x = 12345678901234567890L ** 10
+ f1 = rlong.fromlong(x)
+ d = f1.tofloat()
+ assert d == float(x)
+ x = x ** 100
+ f1 = rlong.fromlong(x)
+ assert raises(OverflowError, f1.tofloat)
+
+ def test_fromfloat(self):
+ x = 1234567890.1234567890
+ f1 = rlong.fromfloat(x)
+ y = f1.tofloat()
+ assert f1.tolong() == 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, rlong.fromfloat, x)
+
+ def test_eq(self):
+ x = 5858393919192332223L
+ y = 585839391919233111223311112332L
+ f1 = rlong.fromlong(x)
+ f2 = rlong.fromlong(-x)
+ f3 = rlong.fromlong(y)
+ assert f1.eq(f1)
+ assert f2.eq(f2)
+ assert f3.eq(f3)
+ assert not f1.eq(f2)
+ assert not f1.eq(f3)
+
+ def test_lt(self):
+ val = [0, 0x111111111111, 0x111111111112, 0x111111111112FFFF]
+ for x in gen_signs(val):
+ for y in gen_signs(val):
+ f1 = rlong.fromlong(x)
+ f2 = rlong.fromlong(y)
+ assert (x < y) == f1.lt(f2)
+
+ def test_int_conversion(self):
+ f1 = rlong.fromlong(12332)
+ f2 = rlong.fromint(12332)
+ assert f2.tolong() == f1.tolong()
+ assert f2.toint()
+ assert rlong.fromlong(42).tolong() == 42
+ assert rlong.fromlong(-42).tolong() == -42
+
+ u = f2.touint()
+ assert u == 12332
+ assert type(u) is r_uint
+
+ def test_conversions(self):
+ for v in (0, 1, -1, sys.maxint, -sys.maxint-1):
+ assert rlong.fromlong(long(v)).tolong() == long(v)
+ l = rlong.fromint(v)
+ assert l.toint() == v
+ if v >= 0:
+ u = l.touint()
+ assert u == v
+ assert type(u) is r_uint
+ else:
+ py.test.raises(ValueError, l.touint)
+
+ toobig_lv1 = rlong.fromlong(sys.maxint+1)
+ assert toobig_lv1.tolong() == sys.maxint+1
+ toobig_lv2 = rlong.fromlong(sys.maxint+2)
+ assert toobig_lv2.tolong() == sys.maxint+2
+ toobig_lv3 = rlong.fromlong(-sys.maxint-2)
+ assert toobig_lv3.tolong() == -sys.maxint-2
+
+ for lv in (toobig_lv1, toobig_lv2, toobig_lv3):
+ py.test.raises(OverflowError, lv.toint)
+
+ lmaxuint = rlong.fromlong(2*sys.maxint+1)
+ toobig_lv4 = rlong.fromlong(2*sys.maxint+2)
+
+ u = lmaxuint.touint()
+ assert u == 2*sys.maxint+1
+
+ py.test.raises(ValueError, toobig_lv3.touint)
+ py.test.raises(OverflowError, toobig_lv4.touint)
+
+
+ def test_pow_lll(self):
+ x = 10L
+ y = 2L
+ z = 13L
+ f1 = rlong.fromlong(x)
+ f2 = rlong.fromlong(y)
+ f3 = rlong.fromlong(z)
+ v = f1.pow(f2, f3)
+ assert v.tolong() == pow(x, y, z)
+ f1, f2, f3 = [rlong.fromlong(i)
+ for i in (10L, -1L, 42L)]
+ py.test.raises(TypeError, f1.pow, f2, f3)
+ f1, f2, f3 = [rlong.fromlong(i)
+ for i in (10L, 5L, 0L)]
+ py.test.raises(ValueError, f1.pow, f2, f3)
+
+ def test_pow_lln(self):
+ x = 10L
+ y = 2L
+ f1 = rlong.fromlong(x)
+ f2 = rlong.fromlong(y)
+ v = f1.pow(f2)
+ assert v.tolong() == x ** y
+
+ def test_normalize(self):
+ f1 = rlong([1, 0], 1)
+ f1._normalize()
+ assert len(f1.digits) == 1
+ f0 = rlong([0], 0)
+ assert f1.sub(f1).eq(f0)
+
+ def test_invert(self):
+ x = 3 ** 40
+ f1 = rlong.fromlong(x)
+ f2 = rlong.fromlong(-x)
+ r1 = f1.invert()
+ r2 = f2.invert()
+ assert r1.tolong() == -(x + 1)
+ assert r2.tolong() == -(-x + 1)
+
+ def test_shift(self):
+ negative = rlong.fromlong(-23)
+ big = rlong.fromlong(2L ** 100L)
+ for x in gen_signs([3L ** 30L, 5L ** 20L, 7 ** 300, 0L, 1L]):
+ f1 = rlong.fromlong(x)
+ py.test.raises(ValueError, f1.lshift, negative)
+ py.test.raises(ValueError, f1.rshift, negative)
+ py.test.raises(OverflowError, f1.lshift, big)
+ py.test.raises(OverflowError, f1.rshift, big)
+ for y in [0L, 1L, 32L, 2304L, 11233L, 3 ** 9]:
+ f2 = rlong.fromlong(y)
+ res1 = f1.lshift(f2).tolong()
+ res2 = f1.rshift(f2).tolong()
+ assert res1 == x << y
+ assert res2 == x >> y
+
+class TestInternalFunctions(object):
+ def test__inplace_divrem1(self):
+ # signs are not handled in the helpers!
+ x = 1238585838347L
+ y = 3
+ f1 = rlong.fromlong(x)
+ f2 = y
+ remainder = lobj._inplace_divrem1(f1, f1, f2)
+ assert (f1.tolong(), remainder) == divmod(x, y)
+
+ def test__divrem1(self):
+ # signs are not handled in the helpers!
+ x = 1238585838347L
+ y = 3
+ f1 = rlong.fromlong(x)
+ f2 = y
+ div, rem = lobj._divrem1(f1, f2)
+ assert (div.tolong(), rem) == divmod(x, y)
+
+ def test__muladd1(self):
+ x = 1238585838347L
+ y = 3
+ z = 42
+ f1 = rlong.fromlong(x)
+ f2 = y
+ f3 = z
+ prod = lobj._muladd1(f1, f2, f3)
+ assert prod.tolong() == 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 = rlong.fromlong(x)
+ f2 = rlong.fromlong(y)
+ div, rem = lobj._x_divrem(f1, f2)
+ assert div.tolong(), rem.tolong() == 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 = rlong.fromlong(sx)
+ f2 = rlong.fromlong(sy)
+ div, rem = lobj._x_divrem(f1, f2)
+ assert div.tolong(), rem.tolong() == divmod(sx, sy)
+
+ # testing Karatsuba stuff
+ def test__v_iadd(self):
+ f1 = rlong([lobj.MASK] * 10, 1)
+ f2 = rlong([1], 1)
+ carry = lobj._v_iadd(f1.digits, 1, len(f1.digits)-1, f2.digits, 1)
+ assert carry == 1
+ assert f1.tolong() == lobj.MASK
+
+ def test__v_isub(self):
+ f1 = rlong([lobj.MASK] + [0] * 9 + [1], 1)
+ f2 = rlong([1], 1)
+ borrow = lobj._v_isub(f1.digits, 1, len(f1.digits)-1, f2.digits, 1)
+ assert borrow == 0
+ assert f1.tolong() == (1 << lobj.SHIFT) ** 10 - 1
+
+ def test__kmul_split(self):
+ split = 5
+ diglo = [0] * split
+ dighi = [lobj.MASK] * split
+ f1 = rlong(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 = rlong([lobj.MASK] * digs, 1)
+ f2 = lobj._x_add(f1,rlong([1], 1))
+ ret = lobj._k_mul(f1, f2)
+ assert ret.tolong() == f1.tolong() * f2.tolong()
+
+ def test__k_lopsided_mul(self):
+ digs_a = lobj.KARATSUBA_CUTOFF + 3
+ digs_b = 3 * digs_a
+ f1 = rlong([lobj.MASK] * digs_a, 1)
+ f2 = rlong([lobj.MASK] * digs_b, 1)
+ ret = lobj._k_lopsided_mul(f1, f2)
+ assert ret.tolong() == f1.tolong() * f2.tolong()
+
+
+
+
+class TestTranslatable(object):
+
+ def test_args_from_rarith_int(self):
+ from pypy.rpython.test.test_llinterp import interpret
+ def fn():
+ return (rlong.fromrarith_int(0),
+ rlong.fromrarith_int(17),
+ rlong.fromrarith_int(-17),
+ rlong.fromrarith_int(r_uint(0)),
+ rlong.fromrarith_int(r_uint(17)))
+ interpret(fn, [])
More information about the Pypy-commit
mailing list