[pypy-svn] pypy default: postpone the USE_SHORT_FLOAT_REPR check, else it is executed at import time; we want to be able to change its value later, e.g. in translationoption.py
antocuni
commits-noreply at bitbucket.org
Mon Apr 11 13:06:05 CEST 2011
Author: Antonio Cuni <anto.cuni at gmail.com>
Branch:
Changeset: r43289:6a7e581aa200
Date: 2011-04-11 10:23 +0000
http://bitbucket.org/pypy/pypy/changeset/6a7e581aa200/
Log: postpone the USE_SHORT_FLOAT_REPR check, else it is executed at
import time; we want to be able to change its value later, e.g. in
translationoption.py
diff --git a/pypy/rlib/rfloat.py b/pypy/rlib/rfloat.py
--- a/pypy/rlib/rfloat.py
+++ b/pypy/rlib/rfloat.py
@@ -167,128 +167,132 @@
result = formatd(value, tp, precision, flags)
return result, special
-if USE_SHORT_FLOAT_REPR:
- def round_double(value, ndigits):
- # The basic idea is very simple: convert and round the double to
- # a decimal string using _Py_dg_dtoa, then convert that decimal
- # string back to a double with _Py_dg_strtod. There's one minor
- # difficulty: Python 2.x expects round to do
- # round-half-away-from-zero, while _Py_dg_dtoa does
- # round-half-to-even. So we need some way to detect and correct
- # the halfway cases.
+def round_double(value, ndigits):
+ if USE_SHORT_FLOAT_REPR:
+ return round_double_short_repr(value, ndigits)
+ else:
+ return round_double_fallback_repr(value, ndigits)
- # a halfway value has the form k * 0.5 * 10**-ndigits for some
- # odd integer k. Or in other words, a rational number x is
- # exactly halfway between two multiples of 10**-ndigits if its
- # 2-valuation is exactly -ndigits-1 and its 5-valuation is at
- # least -ndigits. For ndigits >= 0 the latter condition is
- # automatically satisfied for a binary float x, since any such
- # float has nonnegative 5-valuation. For 0 > ndigits >= -22, x
- # needs to be an integral multiple of 5**-ndigits; we can check
- # this using fmod. For -22 > ndigits, there are no halfway
- # cases: 5**23 takes 54 bits to represent exactly, so any odd
- # multiple of 0.5 * 10**n for n >= 23 takes at least 54 bits of
- # precision to represent exactly.
+def round_double_short_repr(value, ndigits):
+ # The basic idea is very simple: convert and round the double to
+ # a decimal string using _Py_dg_dtoa, then convert that decimal
+ # string back to a double with _Py_dg_strtod. There's one minor
+ # difficulty: Python 2.x expects round to do
+ # round-half-away-from-zero, while _Py_dg_dtoa does
+ # round-half-to-even. So we need some way to detect and correct
+ # the halfway cases.
- sign = copysign(1.0, value)
- value = abs(value)
+ # a halfway value has the form k * 0.5 * 10**-ndigits for some
+ # odd integer k. Or in other words, a rational number x is
+ # exactly halfway between two multiples of 10**-ndigits if its
+ # 2-valuation is exactly -ndigits-1 and its 5-valuation is at
+ # least -ndigits. For ndigits >= 0 the latter condition is
+ # automatically satisfied for a binary float x, since any such
+ # float has nonnegative 5-valuation. For 0 > ndigits >= -22, x
+ # needs to be an integral multiple of 5**-ndigits; we can check
+ # this using fmod. For -22 > ndigits, there are no halfway
+ # cases: 5**23 takes 54 bits to represent exactly, so any odd
+ # multiple of 0.5 * 10**n for n >= 23 takes at least 54 bits of
+ # precision to represent exactly.
- # find 2-valuation value
- m, expo = math.frexp(value)
- while m != math.floor(m):
- m *= 2.0
- expo -= 1
+ sign = copysign(1.0, value)
+ value = abs(value)
- # determine whether this is a halfway case.
- halfway_case = 0
- if expo == -ndigits - 1:
- if ndigits >= 0:
+ # find 2-valuation value
+ m, expo = math.frexp(value)
+ while m != math.floor(m):
+ m *= 2.0
+ expo -= 1
+
+ # determine whether this is a halfway case.
+ halfway_case = 0
+ if expo == -ndigits - 1:
+ if ndigits >= 0:
+ halfway_case = 1
+ elif ndigits >= -22:
+ # 22 is the largest k such that 5**k is exactly
+ # representable as a double
+ five_pow = 1.0
+ for i in range(-ndigits):
+ five_pow *= 5.0
+ if math.fmod(value, five_pow) == 0.0:
halfway_case = 1
- elif ndigits >= -22:
- # 22 is the largest k such that 5**k is exactly
- # representable as a double
- five_pow = 1.0
- for i in range(-ndigits):
- five_pow *= 5.0
- if math.fmod(value, five_pow) == 0.0:
- halfway_case = 1
- # round to a decimal string; use an extra place for halfway case
- strvalue = formatd(value, 'f', ndigits + halfway_case)
+ # round to a decimal string; use an extra place for halfway case
+ strvalue = formatd(value, 'f', ndigits + halfway_case)
- if halfway_case:
- buf = [c for c in strvalue]
- if ndigits >= 0:
- endpos = len(buf) - 1
- else:
- endpos = len(buf) + ndigits
- # Sanity checks: there should be exactly ndigits+1 places
- # following the decimal point, and the last digit in the
- # buffer should be a '5'
- if not objectmodel.we_are_translated():
- assert buf[endpos] == '5'
- if '.' in buf:
- assert endpos == len(buf) - 1
- assert buf.index('.') == len(buf) - ndigits - 2
+ if halfway_case:
+ buf = [c for c in strvalue]
+ if ndigits >= 0:
+ endpos = len(buf) - 1
+ else:
+ endpos = len(buf) + ndigits
+ # Sanity checks: there should be exactly ndigits+1 places
+ # following the decimal point, and the last digit in the
+ # buffer should be a '5'
+ if not objectmodel.we_are_translated():
+ assert buf[endpos] == '5'
+ if '.' in buf:
+ assert endpos == len(buf) - 1
+ assert buf.index('.') == len(buf) - ndigits - 2
- # increment and shift right at the same time
- i = endpos - 1
- carry = 1
- while i >= 0:
+ # increment and shift right at the same time
+ i = endpos - 1
+ carry = 1
+ while i >= 0:
+ digit = ord(buf[i])
+ if digit == ord('.'):
+ buf[i+1] = chr(digit)
+ i -= 1
digit = ord(buf[i])
- if digit == ord('.'):
- buf[i+1] = chr(digit)
- i -= 1
- digit = ord(buf[i])
- carry += digit - ord('0')
- buf[i+1] = chr(carry % 10 + ord('0'))
- carry /= 10
- i -= 1
- buf[0] = chr(carry + ord('0'))
- if ndigits < 0:
- buf.append('0')
+ carry += digit - ord('0')
+ buf[i+1] = chr(carry % 10 + ord('0'))
+ carry /= 10
+ i -= 1
+ buf[0] = chr(carry + ord('0'))
+ if ndigits < 0:
+ buf.append('0')
- strvalue = ''.join(buf)
+ strvalue = ''.join(buf)
- return sign * rstring_to_float(strvalue)
+ return sign * rstring_to_float(strvalue)
-else:
- # fallback version, to be used when correctly rounded
- # binary<->decimal conversions aren't available
- def round_double(value, ndigits):
- if ndigits >= 0:
- if ndigits > 22:
- # pow1 and pow2 are each safe from overflow, but
- # pow1*pow2 ~= pow(10.0, ndigits) might overflow
- pow1 = math.pow(10.0, ndigits - 22)
- pow2 = 1e22
- else:
- pow1 = math.pow(10.0, ndigits)
- pow2 = 1.0
+# fallback version, to be used when correctly rounded
+# binary<->decimal conversions aren't available
+def round_double_fallback_repr(value, ndigits):
+ if ndigits >= 0:
+ if ndigits > 22:
+ # pow1 and pow2 are each safe from overflow, but
+ # pow1*pow2 ~= pow(10.0, ndigits) might overflow
+ pow1 = math.pow(10.0, ndigits - 22)
+ pow2 = 1e22
+ else:
+ pow1 = math.pow(10.0, ndigits)
+ pow2 = 1.0
- y = (value * pow1) * pow2
- # if y overflows, then rounded value is exactly x
- if isinf(y):
- return value
+ y = (value * pow1) * pow2
+ # if y overflows, then rounded value is exactly x
+ if isinf(y):
+ return value
- else:
- pow1 = math.pow(10.0, -ndigits);
- pow2 = 1.0 # unused; for translation
- y = value / pow1
+ else:
+ pow1 = math.pow(10.0, -ndigits);
+ pow2 = 1.0 # unused; for translation
+ y = value / pow1
- if y >= 0.0:
- z = math.floor(y + 0.5)
- else:
- z = math.ceil(y - 0.5)
- if math.fabs(y-z) == 1.0: # obscure case, see the test
- z = y
+ if y >= 0.0:
+ z = math.floor(y + 0.5)
+ else:
+ z = math.ceil(y - 0.5)
+ if math.fabs(y-z) == 1.0: # obscure case, see the test
+ z = y
- if ndigits >= 0:
- z = (z / pow2) / pow1
- else:
- z *= pow1
- return z
+ if ndigits >= 0:
+ z = (z / pow2) / pow1
+ else:
+ z *= pow1
+ return z
INFINITY = 1e200 * 1e200
NAN = INFINITY / INFINITY
More information about the Pypy-commit
mailing list