[pypy-svn] r14252 - pypy/dist/pypy/objspace/std
tismer at codespeak.net
tismer at codespeak.net
Mon Jul 4 21:35:21 CEST 2005
Author: tismer
Date: Mon Jul 4 21:35:20 2005
New Revision: 14252
Modified:
pypy/dist/pypy/objspace/std/longobject.py
Log:
long true divide and longfloor divide are ready,
also conversions to float.
missing:
repr, str, long from float, and, or, xor, hex, oct, hash, pow :-( heelp
Modified: pypy/dist/pypy/objspace/std/longobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/longobject.py (original)
+++ pypy/dist/pypy/objspace/std/longobject.py Mon Jul 4 21:35:20 2005
@@ -91,9 +91,9 @@
return W_LongObject(w_intobj.space, digits, sign)
# long-to-float delegation
-def delegate_Long2Float(w_longobj): #YYYYYY
+def delegate_Long2Float(w_longobj):
try:
- return W_FloatObject(w_longobj.space, float(w_longobj.longval()))
+ return W_FloatObject(w_longobj.space, _AsDouble(w_longobj))
except OverflowError:
raise OperationError(w_longobj.space.w_OverflowError,
w_longobj.space.wrap("long int too large to convert to float"))
@@ -127,9 +127,9 @@
#subtypes of long are converted to long!
return long__Long(space, w_value)
-def float__Long(space, w_longobj): #YYYYYY
+def float__Long(space, w_longobj):
try:
- return space.newfloat(float(w_longobj.longval()))
+ return space.newfloat(_AsDouble(w_longobj))
except OverflowError:
raise OperationError(space.w_OverflowError,
space.wrap("long int too large to convert to float"))
@@ -253,30 +253,15 @@
result.sign = w_long1.sign * w_long2.sign
return result
-def truediv__Long_Long(space, w_long1, w_long2): #YYYYYY
- x = w_long1.longval()
- y = w_long2.longval()
- if not y:
- raise OperationError(space.w_ZeroDivisionError,
- space.wrap("long division"))
- try:
- z = operator.truediv(x, y)
- except OverflowError:
- raise OperationError(space.w_OverflowError,
- space.wrap("long/long too large for a float"))
- return space.newfloat(float(z))
+def truediv__Long_Long(space, w_long1, w_long2):
+ return _long_true_divide(space, w_long1, w_long2)
-def floordiv__Long_Long(space, w_long1, w_long2): #YYYYYY
- x = w_long1.longval()
- y = w_long2.longval()
- if not y:
- raise OperationError(space.w_ZeroDivisionError,
- space.wrap("long division"))
- z = x // y
- return W_LongObject(space, *args_from_long(z))
+def floordiv__Long_Long(space, w_long1, w_long2):
+ div, rem = _divrem(space, w_long1, w_long2)
+ return div
old_style_div = 1 / 2 == 1 // 2
-def div__Long_Long(space, w_long1, w_long2): #YYYYYY
+def div__Long_Long(space, w_long1, w_long2):
# Select the proper div
if old_style_div:
return floordiv__Long_Long(space, w_long1, w_long2)
@@ -284,25 +269,13 @@
return truediv__Long_Long(space, w_long1, w_long2)
-def mod__Long_Long(space, w_long1, w_long2): #YYYYYY
- x = w_long1.longval()
- y = w_long2.longval()
- if not y:
- raise OperationError(space.w_ZeroDivisionError,
- space.wrap("long modulo"))
- z = x % y
- return W_LongObject(space, *args_from_long(z))
+def mod__Long_Long(space, w_long1, w_long2):
+ div, rem = _divrem(space, w_long1, w_long2)
+ return rem
-def divmod__Long_Long(space, w_long1, w_long2): #YYYYYY
- x = w_long1.longval()
- y = w_long2.longval()
- if not y:
- raise OperationError(space.w_ZeroDivisionError,
- space.wrap("long modulo"))
- z1, z2 = divmod(x, y)
- w_result1 = W_LongObject(space, *args_from_long(z1))
- w_result2 = W_LongObject(space, *args_from_long(z2))
- return space.newtuple([w_result1, w_result2])
+def divmod__Long_Long(space, w_long1, w_long2):
+ div, rem = _divrem(space, w_long1, w_long2)
+ return space.newtuple([div, rem])
# helper for pow() #YYYYYY: still needs longval if second argument is negative
def _impl_long_long_pow(space, lv, lw, lz=None):
@@ -868,10 +841,10 @@
rem = a
return z, rem
if size_b == 1:
- z, urem = divrem1(a, b._getshort(0))
+ z, urem = _divrem1(space, a, b._getshort(0))
rem = W_LongObject(space, [urem], int(urem != 0))
else:
- z, rem = _x_divrem(a, b)
+ z, rem = _x_divrem(space, a, b)
# Set the signs.
# The quotient z has the sign of a*b;
# the remainder r has the sign of a,
@@ -881,3 +854,86 @@
if z.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 << SHORT_BIT)
+ if v.sign == 0:
+ return 0.0, 0
+ i = len(v.digits) * 2 - 1
+ if v._getshort(i) == 0:
+ i -= 1
+ sign = v.sign
+ x = float(v._getshort(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._getshort(i))
+ nbitsneeded -= SHORT_BIT
+ # 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
+
+# XXX make ldexp and isinf a builtin float support function
+
+def isinf(x):
+ return x*2 == x
+
+def ldexp(x, exp):
+ assert type(x) is float
+ lb1 = LONG_BIT - 1
+ multiplier = float(r_uint(1) << lb1)
+ while exp >= lb1:
+ x *= multiplier
+ exp -= lb1
+ if exp:
+ x *= float(r_uint(1) << exp)
+ return x
+
+def _AsDouble(v):
+ """ Get a C double from a long int object. """
+ x, e = _AsScaledDouble(v)
+ if e <= sys.maxint / SHORT_BIT:
+ x = ldexp(x, e * SHORT_BIT)
+ if not isinf(x):
+ return x
+ raise OverflowError# sorry, "long int too large to convert to float"
+
+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 / SHORT_BIT:
+ raise OverflowError
+ elif aexp < -(sys.maxint / SHORT_BIT):
+ return 0.0 # underflow to 0
+ ad = ldexp(ad, aexp * SHORT_BIT)
+ if isinf(ad): # ignore underflow to 0.0
+ raise OverflowError
+ return space.newfloat(ad)
+ except OverflowError:
+ raise OperationError(space.w_OverflowError,
+ space.wrap("long/long too large for a float"))
More information about the Pypy-commit
mailing list