[pypy-commit] pypy py3k: hg merge default
amauryfa
noreply at buildbot.pypy.org
Sun Mar 3 16:05:58 CET 2013
Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: py3k
Changeset: r61952:0bbb8eab0776
Date: 2013-03-03 15:57 +0100
http://bitbucket.org/pypy/pypy/changeset/0bbb8eab0776/
Log: hg merge default
diff --git a/_pytest/pdb.py b/_pytest/pdb.py
--- a/_pytest/pdb.py
+++ b/_pytest/pdb.py
@@ -72,10 +72,10 @@
tw.sep(">", "entering PDB")
# A doctest.UnexpectedException is not useful for post_mortem.
# Use the underlying exception instead:
- if isinstance(call.excinfo.value, py.std.doctest.UnexpectedException):
- tb = call.excinfo.value.exc_info[2]
- else:
- tb = call.excinfo._excinfo[2]
+ #if isinstance(call.excinfo.value, py.std.doctest.UnexpectedException):
+ # tb = call.excinfo.value.exc_info[2]
+ #else:
+ tb = call.excinfo._excinfo[2]
post_mortem(tb)
rep._pdbshown = True
return rep
diff --git a/dotviewer/drawgraph.py b/dotviewer/drawgraph.py
--- a/dotviewer/drawgraph.py
+++ b/dotviewer/drawgraph.py
@@ -7,9 +7,9 @@
import re, os, math
import pygame
from pygame.locals import *
+from strunicode import forceunicode
-RAW_ENCODING = "utf-8"
this_dir = os.path.dirname(os.path.abspath(__file__))
FONT = os.path.join(this_dir, 'font', 'DroidSans.ttf')
FIXEDFONT = os.path.join(this_dir, 'font', 'DroidSansMono.ttf')
@@ -52,12 +52,6 @@
else:
return default
-def forceunicode(name):
- return name if isinstance(name, unicode) else name.decode(RAW_ENCODING)
-
-def forcestr(name):
- return name if isinstance(name, str) else name.encode(RAW_ENCODING)
-
class GraphLayout:
fixedfont = False
diff --git a/dotviewer/graphclient.py b/dotviewer/graphclient.py
--- a/dotviewer/graphclient.py
+++ b/dotviewer/graphclient.py
@@ -1,6 +1,7 @@
import os, sys, re
import subprocess
import msgstruct
+from strunicode import forcestr
this_dir = os.path.dirname(os.path.abspath(__file__))
GRAPHSERVER = os.path.join(this_dir, 'graphserver.py')
@@ -33,7 +34,6 @@
def reload(graph_id):
page = getpage(graph_id)
if save_tmp_file:
- from drawgraph import forcestr
f = open(save_tmp_file, 'w')
f.write(forcestr(page.source))
f.close()
@@ -76,7 +76,6 @@
def page_messages(page, graph_id):
import graphparse
- from drawgraph import forcestr
return graphparse.parse_dot(graph_id, forcestr(page.source), page.links,
getattr(page, 'fixedfont', False))
diff --git a/dotviewer/graphdisplay.py b/dotviewer/graphdisplay.py
--- a/dotviewer/graphdisplay.py
+++ b/dotviewer/graphdisplay.py
@@ -4,7 +4,8 @@
from pygame.locals import *
from drawgraph import GraphRenderer, FIXEDFONT
from drawgraph import Node, Edge
-from drawgraph import EventQueue, wait_for_events, forceunicode, forcestr
+from drawgraph import EventQueue, wait_for_events
+from strunicode import forceunicode, forcestr
METAKEYS = dict([
diff --git a/dotviewer/graphpage.py b/dotviewer/graphpage.py
--- a/dotviewer/graphpage.py
+++ b/dotviewer/graphpage.py
@@ -45,7 +45,7 @@
class DotFileGraphPage(GraphPage):
def compute(self, dotfile):
import codecs
- from drawgraph import RAW_ENCODING
+ from strunicode import RAW_ENCODING
f = codecs.open(dotfile, 'r', RAW_ENCODING)
self.source = f.read()
f.close()
diff --git a/dotviewer/msgstruct.py b/dotviewer/msgstruct.py
--- a/dotviewer/msgstruct.py
+++ b/dotviewer/msgstruct.py
@@ -24,9 +24,15 @@
long_max = 2147483647
+def _encodeme(x):
+ if type(x) is unicode:
+ x = x.encode('utf-8')
+ return x
+
def message(tp, *values):
#print >> sys.stderr, tp, values
typecodes = ['']
+ values = map(_encodeme, values)
for v in values:
if type(v) is str:
typecodes.append('%ds' % len(v))
diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst
--- a/pypy/doc/project-ideas.rst
+++ b/pypy/doc/project-ideas.rst
@@ -88,7 +88,7 @@
PyPy has pluggable garbage collection policy. This means that various garbage
collectors can be written for specialized purposes, or even various
-experiments can be done for the general purpose. Examples
+experiments can be done for the general purpose. Examples:
* An incremental garbage collector that has specified maximal pause times,
crucial for games
@@ -97,6 +97,9 @@
* A concurrent garbage collector (a lot of work)
+* A collector that keeps object flags in separate memory pages, to avoid
+ un-sharing all pages between several fork()ed processes
+
STM (Software Transactional Memory)
-----------------------------------
diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py
--- a/pypy/interpreter/app_main.py
+++ b/pypy/interpreter/app_main.py
@@ -589,7 +589,7 @@
# banner (unless "-q" was specified) and run
# $PYTHONSTARTUP.
if not quiet:
- print_banner()
+ print_banner(not no_site)
python_startup = readenv and os.getenv('PYTHONSTARTUP')
if python_startup:
try:
@@ -679,10 +679,11 @@
return status
-def print_banner():
+def print_banner(copyright):
print('Python %s on %s' % (sys.version, sys.platform))
- print('Type "help", "copyright", "credits" or '
- '"license" for more information.')
+ if copyright:
+ print('Type "help", "copyright", "credits" or '
+ '"license" for more information.')
STDLIB_WARNING = """\
debug: WARNING: Library path not found, using compiled-in sys.path.
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1687,6 +1687,8 @@
'UnicodeTranslateError',
'ValueError',
'ZeroDivisionError',
+ 'RuntimeWarning',
+ 'PendingDeprecationWarning',
]
if sys.platform.startswith("win"):
diff --git a/pypy/interpreter/test2/test_app_main.py b/pypy/interpreter/test2/test_app_main.py
--- a/pypy/interpreter/test2/test_app_main.py
+++ b/pypy/interpreter/test2/test_app_main.py
@@ -757,6 +757,10 @@
expect_prompt=True, expect_banner=False)
assert '42\n' in data
+ def test_option_S_copyright(self):
+ data = self.run('-S -i', expect_prompt=True, expect_banner=True)
+ assert 'copyright' not in data
+
def test_non_interactive_stdout_fully_buffered(self):
path = getscript(r"""
import sys, time
diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py
--- a/pypy/module/_cffi_backend/cdataobj.py
+++ b/pypy/module/_cffi_backend/cdataobj.py
@@ -92,15 +92,20 @@
cdata1 = self._cdata
other = space.interpclass_w(w_other)
if isinstance(other, W_CData):
+ if requires_ordering:
+ if (isinstance(self.ctype, W_CTypePrimitive) or
+ isinstance(other.ctype, W_CTypePrimitive)):
+ raise OperationError(space.w_TypeError,
+ space.wrap("cannot do comparison on a "
+ "primitive cdata"))
cdata2 = other._cdata
+ elif (misc.is_zero(space, w_other) and
+ not isinstance(self.ctype, W_CTypePrimitive)):
+ cdata2 = lltype.nullptr(rffi.CCHARP.TO)
else:
return space.w_NotImplemented
if requires_ordering:
- if (isinstance(self.ctype, W_CTypePrimitive) or
- isinstance(other.ctype, W_CTypePrimitive)):
- raise OperationError(space.w_TypeError,
- space.wrap("cannot do comparison on a primitive cdata"))
cdata1 = rffi.cast(lltype.Unsigned, cdata1)
cdata2 = rffi.cast(lltype.Unsigned, cdata2)
return space.newbool(op(cdata1, cdata2))
diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -156,6 +156,10 @@
space = self.space
ob = space.interpclass_w(w_ob)
if not isinstance(ob, cdataobj.W_CData):
+ if misc.is_zero(space, w_ob):
+ NULL = lltype.nullptr(rffi.CCHARP.TO)
+ rffi.cast(rffi.CCHARPP, cdata)[0] = NULL
+ return
raise self._convert_error("cdata pointer", w_ob)
other = ob.ctype
if not isinstance(other, W_CTypePtrBase):
@@ -258,7 +262,12 @@
def _prepare_pointer_call_argument(self, w_init, cdata):
space = self.space
- if space.is_w(w_init, space.w_None):
+ if misc.is_zero(space, w_init):
+ # Convert 0 to NULL. Note that passing 0 is not ambigous,
+ # despite the potential confusion: as a 'T*' argument, 0 means
+ # NULL, but as a 'T[]' argument it would mean "array of size 0"
+ # --- except that we specifically refuse to interpret numbers
+ # as the array size when passing arguments.
rffi.cast(rffi.CCHARPP, cdata)[0] = lltype.nullptr(rffi.CCHARP.TO)
return 3
elif (space.isinstance_w(w_init, space.w_list) or
diff --git a/pypy/module/_cffi_backend/misc.py b/pypy/module/_cffi_backend/misc.py
--- a/pypy/module/_cffi_backend/misc.py
+++ b/pypy/module/_cffi_backend/misc.py
@@ -209,6 +209,11 @@
neg_msg = "can't convert negative number to unsigned"
ovf_msg = "long too big to convert"
+def is_zero(space, w_ob):
+ return ((space.isinstance_w(w_ob, space.w_int) or
+ space.isinstance_w(w_ob, space.w_long))
+ and not space.is_true(w_ob))
+
# ____________________________________________________________
class _NotStandardObject(Exception):
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -388,6 +388,19 @@
assert (x == ["hello"]) is False
assert (x != ["hello"]) is True
+def test_cmp_pointer_with_0():
+ p = new_pointer_type(new_primitive_type("int"))
+ x = cast(p, 0)
+ assert (x == 0) is True
+ assert (x != 0) is False
+ assert (0 == x) is True
+ assert (0 != x) is False
+ y = cast(p, 42)
+ assert (y == 0) is False
+ assert (y != 0) is True
+ assert (0 == y) is False
+ assert (0 != y) is True
+
def test_invalid_indexing():
p = new_primitive_type("int")
x = cast(p, 42)
@@ -766,6 +779,7 @@
assert s.a2 == 456
assert s.a3 == 0
assert s.p4 == cast(BVoidP, 0)
+ assert s.p4 == 0
#
s = newp(BStructPtr, {'a2': 41122, 'a3': -123})
assert s.a1 == 0
@@ -778,8 +792,13 @@
p = newp(BIntPtr, 14141)
s = newp(BStructPtr, [12, 34, 56, p])
assert s.p4 == p
+ s.p4 = 0
+ assert s.p4 == 0
#
s = newp(BStructPtr, [12, 34, 56, cast(BVoidP, 0)])
+ assert s.p4 == 0
+ #
+ s = newp(BStructPtr, [12, 34, 56, 0])
assert s.p4 == cast(BVoidP, 0)
#
py.test.raises(TypeError, newp, BStructPtr, [12, 34, 56, None])
@@ -998,8 +1017,12 @@
f = cast(BFunc23, _testfunc(23))
res = f(b"foo")
assert res == 1000 * ord(b'f')
- res = f(None)
+ res = f(0) # NULL
assert res == -42
+ res = f(long(0)) # NULL
+ assert res == -42
+ py.test.raises(TypeError, f, None)
+ py.test.raises(TypeError, f, 0.0)
def test_call_function_23_bis():
# declaring the function as int(unsigned char*)
diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py
--- a/pypy/module/_minimal_curses/fficurses.py
+++ b/pypy/module/_minimal_curses/fficurses.py
@@ -35,7 +35,7 @@
c_tigetstr = rffi.llexternal('tigetstr', [rffi.CCHARP], rffi.CCHARP,
compilation_info=eci)
c_tparm = rffi.llexternal('tparm', [rffi.CCHARP, INT, INT, INT, INT, INT,
- INT, INT, INT, INT, INT], rffi.CCHARP,
+ INT, INT, INT, INT], rffi.CCHARP,
compilation_info=eci)
ERR = rffi.CConstant('ERR', lltype.Signed)
@@ -97,13 +97,13 @@
def tparm_llimpl(s, args):
check_setup_invoked()
- l = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
- for i in range(min(len(args), 10)):
+ l = [0, 0, 0, 0, 0, 0, 0, 0, 0]
+ for i in range(min(len(args), 9)):
l[i] = args[i]
ll_s = rffi.str2charp(s)
# XXX nasty trick stolen from CPython
ll_res = c_tparm(ll_s, l[0], l[1], l[2], l[3], l[4], l[5], l[6],
- l[7], l[8], l[9])
+ l[7], l[8])
rffi.free_charp(ll_s)
res = rffi.charp2str(ll_res)
return res
diff --git a/pypy/module/math/interp_math.py b/pypy/module/math/interp_math.py
--- a/pypy/module/math/interp_math.py
+++ b/pypy/module/math/interp_math.py
@@ -416,210 +416,17 @@
def erf(space, w_x):
"""The error function"""
- return math1(space, _erf, w_x)
+ return math1(space, rfloat.erf, w_x)
def erfc(space, w_x):
"""The complementary error function"""
- return math1(space, _erfc, w_x)
+ return math1(space, rfloat.erfc, w_x)
def gamma(space, w_x):
"""Compute the gamma function for x."""
- return math1(space, _gamma, w_x)
+ return math1(space, rfloat.gamma, w_x)
def lgamma(space, w_x):
"""Compute the natural logarithm of the gamma function for x."""
- return math1(space, _lgamma, w_x)
+ return math1(space, rfloat.lgamma, w_x)
-# Implementation of the error function, the complimentary error function, the
-# gamma function, and the natural log of the gamma function. These exist in
-# libm, but I hear those implementations are horrible.
-
-ERF_SERIES_CUTOFF = 1.5
-ERF_SERIES_TERMS = 25
-ERFC_CONTFRAC_CUTOFF = 30.
-ERFC_CONTFRAC_TERMS = 50
-_sqrtpi = 1.772453850905516027298167483341145182798
-
-def _erf_series(x):
- x2 = x * x
- acc = 0.
- fk = ERF_SERIES_TERMS + .5
- for i in range(ERF_SERIES_TERMS):
- acc = 2.0 + x2 * acc / fk
- fk -= 1.
- return acc * x * math.exp(-x2) / _sqrtpi
-
-def _erfc_contfrac(x):
- if x >= ERFC_CONTFRAC_CUTOFF:
- return 0.
- x2 = x * x
- a = 0.
- da = .5
- p = 1.
- p_last = 0.
- q = da + x2
- q_last = 1.
- for i in range(ERFC_CONTFRAC_TERMS):
- a += da
- da += 2.
- b = da + x2
- p_last, p = p, b * p - a * p_last
- q_last, q = q, b * q - a * q_last
- return p / q * x * math.exp(-x2) / _sqrtpi
-
-def _erf(x):
- if rfloat.isnan(x):
- return x
- absx = abs(x)
- if absx < ERF_SERIES_CUTOFF:
- return _erf_series(x)
- else:
- cf = _erfc_contfrac(absx)
- return 1. - cf if x > 0. else cf - 1.
-
-def _erfc(x):
- if rfloat.isnan(x):
- return x
- absx = abs(x)
- if absx < ERF_SERIES_CUTOFF:
- return 1. - _erf_series(x)
- else:
- cf = _erfc_contfrac(absx)
- return cf if x > 0. else 2. - cf
-
-def _sinpi(x):
- y = math.fmod(abs(x), 2.)
- n = int(rfloat.round_away(2. * y))
- if n == 0:
- r = math.sin(math.pi * y)
- elif n == 1:
- r = math.cos(math.pi * (y - .5))
- elif n == 2:
- r = math.sin(math.pi * (1. - y))
- elif n == 3:
- r = -math.cos(math.pi * (y - 1.5))
- elif n == 4:
- r = math.sin(math.pi * (y - 2.))
- else:
- raise AssertionError("should not reach")
- return rfloat.copysign(1., x) * r
-
-_lanczos_g = 6.024680040776729583740234375
-_lanczos_g_minus_half = 5.524680040776729583740234375
-_lanczos_num_coeffs = [
- 23531376880.410759688572007674451636754734846804940,
- 42919803642.649098768957899047001988850926355848959,
- 35711959237.355668049440185451547166705960488635843,
- 17921034426.037209699919755754458931112671403265390,
- 6039542586.3520280050642916443072979210699388420708,
- 1439720407.3117216736632230727949123939715485786772,
- 248874557.86205415651146038641322942321632125127801,
- 31426415.585400194380614231628318205362874684987640,
- 2876370.6289353724412254090516208496135991145378768,
- 186056.26539522349504029498971604569928220784236328,
- 8071.6720023658162106380029022722506138218516325024,
- 210.82427775157934587250973392071336271166969580291,
- 2.5066282746310002701649081771338373386264310793408
-]
-_lanczos_den_coeffs = [
- 0.0, 39916800.0, 120543840.0, 150917976.0, 105258076.0, 45995730.0,
- 13339535.0, 2637558.0, 357423.0, 32670.0, 1925.0, 66.0, 1.0]
-LANCZOS_N = len(_lanczos_den_coeffs)
-_lanczos_n_iter = unroll.unrolling_iterable(range(LANCZOS_N))
-_lanczos_n_iter_back = unroll.unrolling_iterable(range(LANCZOS_N - 1, -1, -1))
-_gamma_integrals = [
- 1.0, 1.0, 2.0, 6.0, 24.0, 120.0, 720.0, 5040.0, 40320.0, 362880.0,
- 3628800.0, 39916800.0, 479001600.0, 6227020800.0, 87178291200.0,
- 1307674368000.0, 20922789888000.0, 355687428096000.0,
- 6402373705728000.0, 121645100408832000.0, 2432902008176640000.0,
- 51090942171709440000.0, 1124000727777607680000.0]
-
-def _lanczos_sum(x):
- num = 0.
- den = 0.
- assert x > 0.
- if x < 5.:
- for i in _lanczos_n_iter_back:
- num = num * x + _lanczos_num_coeffs[i]
- den = den * x + _lanczos_den_coeffs[i]
- else:
- for i in _lanczos_n_iter:
- num = num / x + _lanczos_num_coeffs[i]
- den = den / x + _lanczos_den_coeffs[i]
- return num / den
-
-def _gamma(x):
- if rfloat.isnan(x) or (rfloat.isinf(x) and x > 0.):
- return x
- if rfloat.isinf(x):
- raise ValueError("math domain error")
- if x == 0.:
- raise ValueError("math domain error")
- if x == math.floor(x):
- if x < 0.:
- raise ValueError("math domain error")
- if x < len(_gamma_integrals):
- return _gamma_integrals[int(x) - 1]
- absx = abs(x)
- if absx < 1e-20:
- r = 1. / x
- if rfloat.isinf(r):
- raise OverflowError("math range error")
- return r
- if absx > 200.:
- if x < 0.:
- return 0. / -_sinpi(x)
- else:
- raise OverflowError("math range error")
- y = absx + _lanczos_g_minus_half
- if absx > _lanczos_g_minus_half:
- q = y - absx
- z = q - _lanczos_g_minus_half
- else:
- q = y - _lanczos_g_minus_half
- z = q - absx
- z = z * _lanczos_g / y
- if x < 0.:
- r = -math.pi / _sinpi(absx) / absx * math.exp(y) / _lanczos_sum(absx)
- r -= z * r
- if absx < 140.:
- r /= math.pow(y, absx - .5)
- else:
- sqrtpow = math.pow(y, absx / 2. - .25)
- r /= sqrtpow
- r /= sqrtpow
- else:
- r = _lanczos_sum(absx) / math.exp(y)
- r += z * r
- if absx < 140.:
- r *= math.pow(y, absx - .5)
- else:
- sqrtpow = math.pow(y, absx / 2. - .25)
- r *= sqrtpow
- r *= sqrtpow
- if rfloat.isinf(r):
- raise OverflowError("math range error")
- return r
-
-def _lgamma(x):
- if rfloat.isnan(x):
- return x
- if rfloat.isinf(x):
- return rfloat.INFINITY
- if x == math.floor(x) and x <= 2.:
- if x <= 0.:
- raise ValueError("math range error")
- return 0.
- absx = abs(x)
- if absx < 1e-20:
- return -math.log(absx)
- if x > 0.:
- r = (math.log(_lanczos_sum(x)) - _lanczos_g + (x - .5) *
- (math.log(x + _lanczos_g - .5) - 1))
- else:
- r = (math.log(math.pi) - math.log(abs(_sinpi(absx))) - math.log(absx) -
- (math.log(_lanczos_sum(absx)) - _lanczos_g +
- (absx - .5) * (math.log(absx + _lanczos_g - .5) - 1)))
- if rfloat.isinf(r):
- raise OverflowError("math domain error")
- return r
diff --git a/pypy/module/math/test/test_math.py b/pypy/module/math/test/test_math.py
--- a/pypy/module/math/test/test_math.py
+++ b/pypy/module/math/test/test_math.py
@@ -170,139 +170,6 @@
raises(ValueError, math.atanh, 1.)
assert math.isnan(math.atanh(float("nan")))
- def test_mtestfile(self):
- import math
- import zipfile
- import os
- import struct
- def _parse_mtestfile(fname):
- """Parse a file with test values
-
- -- starts a comment
- blank lines, or lines containing only a comment, are ignored
- other lines are expected to have the form
- id fn arg -> expected [flag]*
-
- """
- with open(fname) as fp:
- for line in fp:
- # strip comments, and skip blank lines
- if '--' in line:
- line = line[:line.index('--')]
- if not line.strip():
- continue
-
- lhs, rhs = line.split('->')
- id, fn, arg = lhs.split()
- rhs_pieces = rhs.split()
- exp = rhs_pieces[0]
- flags = rhs_pieces[1:]
-
- yield (id, fn, float(arg), float(exp), flags)
- def to_ulps(x):
- """Convert a non-NaN float x to an integer, in such a way that
- adjacent floats are converted to adjacent integers. Then
- abs(ulps(x) - ulps(y)) gives the difference in ulps between two
- floats.
-
- The results from this function will only make sense on platforms
- where C doubles are represented in IEEE 754 binary64 format.
-
- """
- n = struct.unpack('<q', struct.pack('<d', x))[0]
- if n < 0:
- n = ~(n+2**63)
- return n
-
- def ulps_check(expected, got, ulps=20):
- """Given non-NaN floats `expected` and `got`,
- check that they're equal to within the given number of ulps.
-
- Returns None on success and an error message on failure."""
-
- ulps_error = to_ulps(got) - to_ulps(expected)
- if abs(ulps_error) <= ulps:
- return None
- return "error = {} ulps; permitted error = {} ulps".format(ulps_error,
- ulps)
-
- def acc_check(expected, got, rel_err=2e-15, abs_err = 5e-323):
- """Determine whether non-NaN floats a and b are equal to within a
- (small) rounding error. The default values for rel_err and
- abs_err are chosen to be suitable for platforms where a float is
- represented by an IEEE 754 double. They allow an error of between
- 9 and 19 ulps."""
-
- # need to special case infinities, since inf - inf gives nan
- if math.isinf(expected) and got == expected:
- return None
-
- error = got - expected
-
- permitted_error = max(abs_err, rel_err * abs(expected))
- if abs(error) < permitted_error:
- return None
- return "error = {}; permitted error = {}".format(error,
- permitted_error)
-
- ALLOWED_ERROR = 20 # permitted error, in ulps
- fail_fmt = "{}:{}({!r}): expected {!r}, got {!r}"
-
- failures = []
- math_testcases = os.path.join(os.path.dirname(zipfile.__file__), "test",
- "math_testcases.txt")
- for id, fn, arg, expected, flags in _parse_mtestfile(math_testcases):
- func = getattr(math, fn)
-
- if 'invalid' in flags or 'divide-by-zero' in flags:
- expected = 'ValueError'
- elif 'overflow' in flags:
- expected = 'OverflowError'
-
- try:
- got = func(arg)
- except ValueError:
- got = 'ValueError'
- except OverflowError:
- got = 'OverflowError'
-
- accuracy_failure = None
- if isinstance(got, float) and isinstance(expected, float):
- if math.isnan(expected) and math.isnan(got):
- continue
- if not math.isnan(expected) and not math.isnan(got):
- if fn == 'lgamma':
- # we use a weaker accuracy test for lgamma;
- # lgamma only achieves an absolute error of
- # a few multiples of the machine accuracy, in
- # general.
- accuracy_failure = acc_check(expected, got,
- rel_err = 5e-15,
- abs_err = 5e-15)
- elif fn == 'erfc':
- # erfc has less-than-ideal accuracy for large
- # arguments (x ~ 25 or so), mainly due to the
- # error involved in computing exp(-x*x).
- #
- # XXX Would be better to weaken this test only
- # for large x, instead of for all x.
- accuracy_failure = ulps_check(expected, got, 2000)
-
- else:
- accuracy_failure = ulps_check(expected, got, 20)
- if accuracy_failure is None:
- continue
-
- if isinstance(got, str) and isinstance(expected, str):
- if got == expected:
- continue
-
- fail_msg = fail_fmt.format(id, fn, arg, expected, got)
- if accuracy_failure is not None:
- fail_msg += ' ({})'.format(accuracy_failure)
- failures.append(fail_msg)
- assert not failures
-
def test_trunc(self):
import math
assert math.trunc(1.9) == 1.0
@@ -420,3 +287,40 @@
return 99.9
assert math.floor(CustomFloat()) == 99
+
+ def test_erf(self):
+ import math
+ assert math.erf(100.0) == 1.0
+ assert math.erf(-1000.0) == -1.0
+ assert math.erf(float("inf")) == 1.0
+ assert math.erf(float("-inf")) == -1.0
+ assert math.isnan(math.erf(float("nan")))
+ # proper tests are in rpython/rlib/test/test_rfloat
+ assert round(math.erf(1.0), 9) == 0.842700793
+
+ def test_erfc(self):
+ import math
+ assert math.erfc(0.0) == 1.0
+ assert math.erfc(-0.0) == 1.0
+ assert math.erfc(float("inf")) == 0.0
+ assert math.erfc(float("-inf")) == 2.0
+ assert math.isnan(math.erf(float("nan")))
+ assert math.erfc(1e-308) == 1.0
+
+ def test_gamma(self):
+ import math
+ assert raises(ValueError, math.gamma, 0.0)
+ assert math.gamma(5.0) == 24.0
+ assert math.gamma(6.0) == 120.0
+ assert raises(ValueError, math.gamma, -1)
+ assert math.gamma(0.5) == math.pi ** 0.5
+
+ def test_lgamma(self):
+ import math
+ math.lgamma(1.0) == 0.0
+ math.lgamma(2.0) == 0.0
+ # proper tests are in rpython/rlib/test/test_rfloat
+ assert round(math.lgamma(5.0), 9) == round(math.log(24.0), 9)
+ assert round(math.lgamma(6.0), 9) == round(math.log(120.0), 9)
+ assert raises(ValueError, math.gamma, -1)
+ assert round(math.lgamma(0.5), 9) == round(math.log(math.pi ** 0.5), 9)
diff --git a/pypy/module/math/test/test_translated.py b/pypy/module/math/test/test_translated.py
deleted file mode 100644
--- a/pypy/module/math/test/test_translated.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from rpython.translator.c.test.test_genc import compile
-from pypy.module.math.interp_math import _gamma
-
-
-def test_gamma_overflow():
- def wrapper(arg):
- try:
- return _gamma(arg)
- except OverflowError:
- return -42
-
- f = compile(wrapper, [float])
- assert f(10.0) == 362880.0
- assert f(1720.0) == -42
- assert f(172.0) == -42
diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py
--- a/pypy/module/micronumpy/arrayimpl/concrete.py
+++ b/pypy/module/micronumpy/arrayimpl/concrete.py
@@ -416,8 +416,8 @@
return raw_storage_getitem(lltype.Char, self.impl.storage, item)
def setitem(self, item, v):
- return raw_storage_setitem(self.impl.storage, item,
- rffi.cast(lltype.Char, v))
+ raw_storage_setitem(self.impl.storage, item,
+ rffi.cast(lltype.Char, v))
def getlength(self):
return self.impl.size
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -304,10 +304,11 @@
reference = [0, -1, 0, 1, 0]
if dtype[0] == 'u':
reference[1] = 0
- elif dtype == 'int32':
- reference[2] = -2147483648
- elif dtype == 'int64':
- reference[2] = -9223372036854775808
+ # XXX need to fix specialization issue in types.py first
+ #elif dtype == 'int32':
+ # reference[2] = -2147483648
+ #elif dtype == 'int64':
+ # reference[2] = -9223372036854775808
a = array([-2, -1, 0, 1, 2], dtype)
b = reciprocal(a)
assert (b == reference).all()
diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py
--- a/pypy/module/micronumpy/types.py
+++ b/pypy/module/micronumpy/types.py
@@ -502,17 +502,18 @@
def invert(self, v):
return ~v
- if 0: # XXX breaks translation
- @simple_unary_op
- def reciprocal(self, v):
- if v == 0:
- # XXX good place to warn
- if self.T in (rffi.INT, rffi.LONG):
- return most_neg_value_of(self.T)
- return 0
- if v == 1 or v == -1:
- return v
+ @simple_unary_op
+ def reciprocal(self, v):
+ if v == 0:
+ # XXX good place to warn
+ # XXX can't do the following, func is specialized only on argtype(v)
+ # (which is the same for all int classes)
+ #if self.T in (rffi.INT, rffi.LONG):
+ # return most_neg_value_of(self.T)
return 0
+ if abs(v) == 1:
+ return v
+ return 0
@raw_unary_op
def signbit(self, v):
diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py
--- a/pypy/module/pypyjit/test_pypy_c/test_min_max.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py
@@ -24,27 +24,42 @@
--TICK--
jump(p0, p1, p2, p3, i11, i9, descr=...)
""")
+
def test_silly_max(self):
def main():
- i = 2
+ i = 13
sa = 0
- while i < 300:
- lst = range(i)
+ while i < 30000:
+ lst = range(i % 1000 + 2)
sa += max(*lst) # ID: max
i += 1
return sa
log = self.run(main, [])
assert log.result == main()
loop, = log.loops_by_filename(self.filepath)
- # We dont want too many guards, but a residual call to min_max_loop
- guards = [n for n in log.opnames(loop.ops_by_id("max")) if n.startswith('guard')]
- assert len(guards) < 20
- assert loop.match_by_id('max',"""
+ assert loop.match("""
...
- p76 = call_may_force(ConstClass(min_max_trampoline), _, _, descr=...)
+ p76 = call_assembler(_, _, _, _, descr=...)
...
""")
+ loop2 = log.loops[0]
+ loop2.match('''
+ ...
+ label(..., descr=...)
+ ...
+ label(..., descr=...)
+ i17 = int_ge(i11, i7)
+ guard_false(i17, descr=...)
+ p18 = getarrayitem_gc(p5, i11, descr=...)
+ i19 = int_add(i11, 1)
+ setfield_gc(p2, i19, descr=...)
+ guard_class(p18, ConstClass(W_IntObject), descr=...)
+ i20 = getfield_gc_pure(p18, descr=...)
+ i21 = int_gt(i20, i14)
+ guard_true(i21, descr=...)
+ jump(..., descr=...)
+ ''')
def test_iter_max(self):
def main():
@@ -61,8 +76,8 @@
# We dont want too many guards, but a residual call to min_max_loop
guards = [n for n in log.opnames(loop.ops_by_id("max")) if n.startswith('guard')]
assert len(guards) < 20
- assert loop.match_by_id('max',"""
+ assert loop.match("""
...
- p76 = call_may_force(ConstClass(min_max_trampoline), _, _, descr=...)
+ p76 = call_assembler(_, _, _, _, descr=...)
...
""")
diff --git a/pypy/objspace/fake/checkmodule.py b/pypy/objspace/fake/checkmodule.py
--- a/pypy/objspace/fake/checkmodule.py
+++ b/pypy/objspace/fake/checkmodule.py
@@ -5,16 +5,18 @@
def checkmodule(*modnames):
config = get_pypy_config(translating=True)
space = FakeObjSpace(config)
+ seeobj_w = []
for modname in modnames:
mod = __import__('pypy.module.%s' % modname, None, None, ['__doc__'])
# force computation and record what we wrap
module = mod.Module(space, W_Root())
for name in module.loaders:
- module._load_lazily(space, name)
+ seeobj_w.append(module._load_lazily(space, name))
if hasattr(module, 'submodules'):
for cls in module.submodules.itervalues():
submod = cls(space, W_Root())
for name in submod.loaders:
- submod._load_lazily(space, name)
+ seeobj_w.append(submod._load_lazily(space, name))
#
- space.translates(**{'translation.list_comprehension_operations': True})
+ space.translates(seeobj_w=seeobj_w,
+ **{'translation.list_comprehension_operations': True})
diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py
--- a/pypy/objspace/fake/objspace.py
+++ b/pypy/objspace/fake/objspace.py
@@ -2,7 +2,9 @@
from pypy.interpreter import argument, gateway
from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable, SpaceCache
from pypy.interpreter.typedef import TypeDef, GetSetProperty
-from rpython.rlib.objectmodel import instantiate, we_are_translated
+from pypy.objspace.std.stdtypedef import StdTypeDef
+from pypy.objspace.std.sliceobject import W_SliceObject
+from rpython.rlib.objectmodel import instantiate, we_are_translated, specialize
from rpython.rlib.nonconst import NonConstant
from rpython.rlib.rarithmetic import r_uint, r_singlefloat
from rpython.rtyper.extregistry import ExtRegistryEntry
@@ -133,11 +135,15 @@
is_root(w_start)
is_root(w_end)
is_root(w_step)
+ W_SliceObject(w_start, w_end, w_step)
return w_some_obj()
def newint(self, x):
return w_some_obj()
+ def newlong(self, x):
+ return w_some_obj()
+
def newfloat(self, x):
return w_some_obj()
@@ -147,6 +153,9 @@
def newlong_from_rbigint(self, x):
return w_some_obj()
+ def newseqiter(self, x):
+ return w_some_obj()
+
def marshal_w(self, w_obj):
"NOT_RPYTHON"
raise NotImplementedError
@@ -231,7 +240,8 @@
def gettypeobject(self, typedef):
assert typedef is not None
- return self.fromcache(TypeCache).getorbuild(typedef)
+ see_typedef(self, typedef)
+ return w_some_type()
def type(self, w_obj):
return w_some_type()
@@ -270,7 +280,7 @@
# ----------
- def translates(self, func=None, argtypes=None, **kwds):
+ def translates(self, func=None, argtypes=None, seeobj_w=[], **kwds):
config = make_config(None, **kwds)
if func is not None:
if argtypes is None:
@@ -282,6 +292,10 @@
ann = t.buildannotator()
if func is not None:
ann.build_types(func, argtypes, complete_now=False)
+ if seeobj_w:
+ def seeme(n):
+ return seeobj_w[n]
+ ann.build_types(seeme, [int], complete_now=False)
#
# annotate all _seen_extras, knowing that annotating some may
# grow the list
@@ -290,8 +304,10 @@
#print self._seen_extras
ann.build_types(self._seen_extras[done], [],
complete_now=False)
+ ann.complete_pending_blocks()
done += 1
ann.complete()
+ assert done == len(self._seen_extras)
#t.viewcg()
t.buildrtyper().specialize()
t.checkgraphs()
@@ -331,12 +347,12 @@
# ____________________________________________________________
-class TypeCache(SpaceCache):
- def build(cache, typedef):
- assert isinstance(typedef, TypeDef)
- for value in typedef.rawdict.values():
- cache.space.wrap(value)
- return w_some_obj()
+ at specialize.memo()
+def see_typedef(space, typedef):
+ assert isinstance(typedef, TypeDef)
+ if not isinstance(typedef, StdTypeDef):
+ for name, value in typedef.rawdict.items():
+ space.wrap(value)
class FakeCompiler(object):
pass
diff --git a/pypy/objspace/fake/test/test_checkmodule.py b/pypy/objspace/fake/test/test_checkmodule.py
--- a/pypy/objspace/fake/test/test_checkmodule.py
+++ b/pypy/objspace/fake/test/test_checkmodule.py
@@ -3,6 +3,7 @@
from pypy.interpreter.baseobjspace import Wrappable
from pypy.interpreter.typedef import TypeDef, GetSetProperty
from pypy.interpreter.gateway import interp2app, W_Root, ObjSpace
+from rpython.rlib.objectmodel import specialize
from rpython.rtyper.test.test_llinterp import interpret
def make_checker():
@@ -34,6 +35,22 @@
space.translates()
assert check
+def test_wrap_interp2app_later():
+ see, check = make_checker()
+ #
+ @specialize.memo()
+ def hithere(space):
+ space.wrap(interp2app(foobar2))
+ #
+ def foobar(space):
+ hithere(space)
+ def foobar2(space):
+ see()
+ space = FakeObjSpace()
+ space.wrap(interp2app(foobar))
+ space.translates()
+ assert check
+
def test_wrap_GetSetProperty():
see, check = make_checker()
def foobar(w_obj, space):
@@ -76,3 +93,23 @@
return len(w_type.mro_w)
assert interpret(f, [1]) == 2
+
+def test_see_objects():
+ see, check = make_checker()
+ class W_Foo(Wrappable):
+ def __init__(self, x):
+ self.x = x
+ def do_it(self):
+ if self.x == 42:
+ return
+ see()
+ def f():
+ W_Foo(42).do_it()
+ #
+ space = FakeObjSpace()
+ space.translates(f)
+ assert not check
+ #
+ space = FakeObjSpace()
+ space.translates(f, seeobj_w=[W_Foo(15)])
+ assert check
diff --git a/rpython/annotator/annrpython.py b/rpython/annotator/annrpython.py
--- a/rpython/annotator/annrpython.py
+++ b/rpython/annotator/annrpython.py
@@ -192,12 +192,15 @@
if not self.annotated[block]:
self.pendingblocks[block] = graph
+ def complete_pending_blocks(self):
+ while self.pendingblocks:
+ block, graph = self.pendingblocks.popitem()
+ self.processblock(graph, block)
+
def complete(self):
"""Process pending blocks until none is left."""
while True:
- while self.pendingblocks:
- block, graph = self.pendingblocks.popitem()
- self.processblock(graph, block)
+ self.complete_pending_blocks()
self.policy.no_more_blocks_to_annotate(self)
if not self.pendingblocks:
break # finished
diff --git a/rpython/annotator/description.py b/rpython/annotator/description.py
--- a/rpython/annotator/description.py
+++ b/rpython/annotator/description.py
@@ -351,6 +351,7 @@
row[desc.rowkey()] = graph
return s_ImpossibleValue # meaningless
desc.pycall(enlist, args, s_ImpossibleValue, op)
+ assert row
return row
row_to_consider = staticmethod(row_to_consider)
diff --git a/rpython/annotator/specialize.py b/rpython/annotator/specialize.py
--- a/rpython/annotator/specialize.py
+++ b/rpython/annotator/specialize.py
@@ -111,7 +111,8 @@
def absorb(self, other):
self.table.update(other.table)
- self.graph = None # just in case
+ assert self.graph is None, "too late for MemoTable merge!"
+ del other.graph # just in case
other.do_not_process = True
fieldnamecounter = 0
diff --git a/rpython/jit/codewriter/test/test_flatten.py b/rpython/jit/codewriter/test/test_flatten.py
--- a/rpython/jit/codewriter/test/test_flatten.py
+++ b/rpython/jit/codewriter/test/test_flatten.py
@@ -137,7 +137,8 @@
if liveness:
from rpython.jit.codewriter.liveness import compute_liveness
compute_liveness(ssarepr)
- assert_format(ssarepr, expected)
+ if expected is not None:
+ assert_format(ssarepr, expected)
def test_simple(self):
def f(n):
@@ -322,6 +323,15 @@
int_return $54
""")
+ def test_switch_longlong(self):
+ def f(n):
+ n = r_longlong(n)
+ if n == r_longlong(-5): return 12
+ elif n == r_longlong(2): return 51
+ elif n == r_longlong(7): return 1212
+ else: return 42
+ self.encoding_test(f, [65], None)
+
def test_exc_exitswitch(self):
def g(i):
pass
diff --git a/rpython/rlib/rfloat.py b/rpython/rlib/rfloat.py
--- a/rpython/rlib/rfloat.py
+++ b/rpython/rlib/rfloat.py
@@ -1,9 +1,9 @@
"""Float constants"""
-import math
+import math, struct
from rpython.annotator.model import SomeString, SomeChar
-from rpython.rlib import objectmodel
+from rpython.rlib import objectmodel, unroll
from rpython.rtyper.extfunc import register_external
from rpython.rtyper.tool import rffi_platform
from rpython.translator.tool.cbuild import ExternalCompilationInfo
@@ -441,3 +441,250 @@
else:
den = exp
return num, den
+
+
+
+# Implementation of the error function, the complimentary error function, the
+# gamma function, and the natural log of the gamma function. These exist in
+# libm, but I hear those implementations are horrible.
+
+ERF_SERIES_CUTOFF = 1.5
+ERF_SERIES_TERMS = 25
+ERFC_CONTFRAC_CUTOFF = 30.
+ERFC_CONTFRAC_TERMS = 50
+_sqrtpi = 1.772453850905516027298167483341145182798
+
+def _erf_series(x):
+ x2 = x * x
+ acc = 0.
+ fk = ERF_SERIES_TERMS + .5
+ for i in range(ERF_SERIES_TERMS):
+ acc = 2.0 + x2 * acc / fk
+ fk -= 1.
+ return acc * x * math.exp(-x2) / _sqrtpi
+
+def _erfc_contfrac(x):
+ if x >= ERFC_CONTFRAC_CUTOFF:
+ return 0.
+ x2 = x * x
+ a = 0.
+ da = .5
+ p = 1.
+ p_last = 0.
+ q = da + x2
+ q_last = 1.
+ for i in range(ERFC_CONTFRAC_TERMS):
+ a += da
+ da += 2.
+ b = da + x2
+ p_last, p = p, b * p - a * p_last
+ q_last, q = q, b * q - a * q_last
+ return p / q * x * math.exp(-x2) / _sqrtpi
+
+def erf(x):
+ """The error function at x."""
+ if isnan(x):
+ return x
+ absx = abs(x)
+ if absx < ERF_SERIES_CUTOFF:
+ return _erf_series(x)
+ else:
+ cf = _erfc_contfrac(absx)
+ return 1. - cf if x > 0. else cf - 1.
+
+def erfc(x):
+ """The complementary error function at x."""
+ if isnan(x):
+ return x
+ absx = abs(x)
+ if absx < ERF_SERIES_CUTOFF:
+ return 1. - _erf_series(x)
+ else:
+ cf = _erfc_contfrac(absx)
+ return cf if x > 0. else 2. - cf
+
+def _sinpi(x):
+ y = math.fmod(abs(x), 2.)
+ n = int(round_away(2. * y))
+ if n == 0:
+ r = math.sin(math.pi * y)
+ elif n == 1:
+ r = math.cos(math.pi * (y - .5))
+ elif n == 2:
+ r = math.sin(math.pi * (1. - y))
+ elif n == 3:
+ r = -math.cos(math.pi * (y - 1.5))
+ elif n == 4:
+ r = math.sin(math.pi * (y - 2.))
+ else:
+ raise AssertionError("should not reach")
+ return copysign(1., x) * r
+
+_lanczos_g = 6.024680040776729583740234375
+_lanczos_g_minus_half = 5.524680040776729583740234375
+_lanczos_num_coeffs = [
+ 23531376880.410759688572007674451636754734846804940,
+ 42919803642.649098768957899047001988850926355848959,
+ 35711959237.355668049440185451547166705960488635843,
+ 17921034426.037209699919755754458931112671403265390,
+ 6039542586.3520280050642916443072979210699388420708,
+ 1439720407.3117216736632230727949123939715485786772,
+ 248874557.86205415651146038641322942321632125127801,
+ 31426415.585400194380614231628318205362874684987640,
+ 2876370.6289353724412254090516208496135991145378768,
+ 186056.26539522349504029498971604569928220784236328,
+ 8071.6720023658162106380029022722506138218516325024,
+ 210.82427775157934587250973392071336271166969580291,
+ 2.5066282746310002701649081771338373386264310793408
+]
+_lanczos_den_coeffs = [
+ 0.0, 39916800.0, 120543840.0, 150917976.0, 105258076.0, 45995730.0,
+ 13339535.0, 2637558.0, 357423.0, 32670.0, 1925.0, 66.0, 1.0]
+LANCZOS_N = len(_lanczos_den_coeffs)
+_lanczos_n_iter = unroll.unrolling_iterable(range(LANCZOS_N))
+_lanczos_n_iter_back = unroll.unrolling_iterable(range(LANCZOS_N - 1, -1, -1))
+_gamma_integrals = [
+ 1.0, 1.0, 2.0, 6.0, 24.0, 120.0, 720.0, 5040.0, 40320.0, 362880.0,
+ 3628800.0, 39916800.0, 479001600.0, 6227020800.0, 87178291200.0,
+ 1307674368000.0, 20922789888000.0, 355687428096000.0,
+ 6402373705728000.0, 121645100408832000.0, 2432902008176640000.0,
+ 51090942171709440000.0, 1124000727777607680000.0]
+
+def _lanczos_sum(x):
+ num = 0.
+ den = 0.
+ assert x > 0.
+ if x < 5.:
+ for i in _lanczos_n_iter_back:
+ num = num * x + _lanczos_num_coeffs[i]
+ den = den * x + _lanczos_den_coeffs[i]
+ else:
+ for i in _lanczos_n_iter:
+ num = num / x + _lanczos_num_coeffs[i]
+ den = den / x + _lanczos_den_coeffs[i]
+ return num / den
+
+def gamma(x):
+ """Compute the gamma function for x."""
+ if isnan(x) or (isinf(x) and x > 0.):
+ return x
+ if isinf(x):
+ raise ValueError("math domain error")
+ if x == 0.:
+ raise ValueError("math domain error")
+ if x == math.floor(x):
+ if x < 0.:
+ raise ValueError("math domain error")
+ if x < len(_gamma_integrals):
+ return _gamma_integrals[int(x) - 1]
+ absx = abs(x)
+ if absx < 1e-20:
+ r = 1. / x
+ if isinf(r):
+ raise OverflowError("math range error")
+ return r
+ if absx > 200.:
+ if x < 0.:
+ return 0. / -_sinpi(x)
+ else:
+ raise OverflowError("math range error")
+ y = absx + _lanczos_g_minus_half
+ if absx > _lanczos_g_minus_half:
+ q = y - absx
+ z = q - _lanczos_g_minus_half
+ else:
+ q = y - _lanczos_g_minus_half
+ z = q - absx
+ z = z * _lanczos_g / y
+ if x < 0.:
+ r = -math.pi / _sinpi(absx) / absx * math.exp(y) / _lanczos_sum(absx)
+ r -= z * r
+ if absx < 140.:
+ r /= math.pow(y, absx - .5)
+ else:
+ sqrtpow = math.pow(y, absx / 2. - .25)
+ r /= sqrtpow
+ r /= sqrtpow
+ else:
+ r = _lanczos_sum(absx) / math.exp(y)
+ r += z * r
+ if absx < 140.:
+ r *= math.pow(y, absx - .5)
+ else:
+ sqrtpow = math.pow(y, absx / 2. - .25)
+ r *= sqrtpow
+ r *= sqrtpow
+ if isinf(r):
+ raise OverflowError("math range error")
+ return r
+
+def lgamma(x):
+ """Compute the natural logarithm of the gamma function for x."""
+ if isnan(x):
+ return x
+ if isinf(x):
+ return INFINITY
+ if x == math.floor(x) and x <= 2.:
+ if x <= 0.:
+ raise ValueError("math range error")
+ return 0.
+ absx = abs(x)
+ if absx < 1e-20:
+ return -math.log(absx)
+ if x > 0.:
+ r = (math.log(_lanczos_sum(x)) - _lanczos_g + (x - .5) *
+ (math.log(x + _lanczos_g - .5) - 1))
+ else:
+ r = (math.log(math.pi) - math.log(abs(_sinpi(absx))) - math.log(absx) -
+ (math.log(_lanczos_sum(absx)) - _lanczos_g +
+ (absx - .5) * (math.log(absx + _lanczos_g - .5) - 1)))
+ if isinf(r):
+ raise OverflowError("math domain error")
+ return r
+
+
+def to_ulps(x):
+ """Convert a non-NaN float x to an integer, in such a way that
+ adjacent floats are converted to adjacent integers. Then
+ abs(ulps(x) - ulps(y)) gives the difference in ulps between two
+ floats.
+
+ The results from this function will only make sense on platforms
+ where C doubles are represented in IEEE 754 binary64 format.
+
+ """
+ n = struct.unpack('<q', struct.pack('<d', x))[0]
+ if n < 0:
+ n = ~(n+2**63)
+ return n
+
+def ulps_check(expected, got, ulps=20):
+ """Given non-NaN floats `expected` and `got`,
+ check that they're equal to within the given number of ulps.
+
+ Returns None on success and an error message on failure."""
+
+ ulps_error = to_ulps(got) - to_ulps(expected)
+ if abs(ulps_error) <= ulps:
+ return None
+ return "error = {} ulps; permitted error = {} ulps".format(ulps_error,
+ ulps)
+
+def acc_check(expected, got, rel_err=2e-15, abs_err = 5e-323):
+ """Determine whether non-NaN floats a and b are equal to within a
+ (small) rounding error. The default values for rel_err and
+ abs_err are chosen to be suitable for platforms where a float is
+ represented by an IEEE 754 double. They allow an error of between
+ 9 and 19 ulps."""
+
+ # need to special case infinities, since inf - inf gives nan
+ if math.isinf(expected) and got == expected:
+ return None
+
+ error = got - expected
+
+ permitted_error = max(abs_err, rel_err * abs(expected))
+ if abs(error) < permitted_error:
+ return None
+ return "error = {}; permitted error = {}".format(error,
+ permitted_error)
diff --git a/lib-python/2.7/test/math_testcases.txt b/rpython/rlib/test/math_testcases.txt
copy from lib-python/2.7/test/math_testcases.txt
copy to rpython/rlib/test/math_testcases.txt
diff --git a/rpython/rlib/test/test_rfloat.py b/rpython/rlib/test/test_rfloat.py
--- a/rpython/rlib/test/test_rfloat.py
+++ b/rpython/rlib/test/test_rfloat.py
@@ -5,6 +5,8 @@
from rpython.rlib.rfloat import copysign
from rpython.rlib.rfloat import round_away
from rpython.rlib.rfloat import round_double
+from rpython.rlib.rfloat import erf, erfc, gamma, lgamma, isnan
+from rpython.rlib.rfloat import ulps_check, acc_check
from rpython.rlib.rbigint import rbigint
def test_copysign():
@@ -129,3 +131,104 @@
float_as_rbigint_ratio(float('-inf'))
with py.test.raises(ValueError):
float_as_rbigint_ratio(float('nan'))
+
+def test_mtestfile():
+ from rpython.rlib import rfloat
+ import zipfile
+ import os
+ def _parse_mtestfile(fname):
+ """Parse a file with test values
+
+ -- starts a comment
+ blank lines, or lines containing only a comment, are ignored
+ other lines are expected to have the form
+ id fn arg -> expected [flag]*
+
+ """
+ with open(fname) as fp:
+ for line in fp:
+ # strip comments, and skip blank lines
+ if '--' in line:
+ line = line[:line.index('--')]
+ if not line.strip():
+ continue
+
+ lhs, rhs = line.split('->')
+ id, fn, arg = lhs.split()
+ rhs_pieces = rhs.split()
+ exp = rhs_pieces[0]
+ flags = rhs_pieces[1:]
+
+ yield (id, fn, float(arg), float(exp), flags)
+
+ ALLOWED_ERROR = 20 # permitted error, in ulps
+ fail_fmt = "{}:{}({!r}): expected {!r}, got {!r}"
+
+ failures = []
+ math_testcases = os.path.join(os.path.dirname(__file__),
+ "math_testcases.txt")
+ for id, fn, arg, expected, flags in _parse_mtestfile(math_testcases):
+ func = getattr(rfloat, fn)
+
+ if 'invalid' in flags or 'divide-by-zero' in flags:
+ expected = 'ValueError'
+ elif 'overflow' in flags:
+ expected = 'OverflowError'
+
+ try:
+ got = func(arg)
+ except ValueError:
+ got = 'ValueError'
+ except OverflowError:
+ got = 'OverflowError'
+
+ accuracy_failure = None
+ if isinstance(got, float) and isinstance(expected, float):
+ if isnan(expected) and isnan(got):
+ continue
+ if not isnan(expected) and not isnan(got):
+ if fn == 'lgamma':
+ # we use a weaker accuracy test for lgamma;
+ # lgamma only achieves an absolute error of
+ # a few multiples of the machine accuracy, in
+ # general.
+ accuracy_failure = acc_check(expected, got,
+ rel_err = 5e-15,
+ abs_err = 5e-15)
+ elif fn == 'erfc':
+ # erfc has less-than-ideal accuracy for large
+ # arguments (x ~ 25 or so), mainly due to the
+ # error involved in computing exp(-x*x).
+ #
+ # XXX Would be better to weaken this test only
+ # for large x, instead of for all x.
+ accuracy_failure = ulps_check(expected, got, 2000)
+
+ else:
+ accuracy_failure = ulps_check(expected, got, 20)
+ if accuracy_failure is None:
+ continue
+
+ if isinstance(got, str) and isinstance(expected, str):
+ if got == expected:
+ continue
+
+ fail_msg = fail_fmt.format(id, fn, arg, expected, got)
+ if accuracy_failure is not None:
+ fail_msg += ' ({})'.format(accuracy_failure)
+ failures.append(fail_msg)
+ assert not failures
+
+
+def test_gamma_overflow_translated():
+ from rpython.translator.c.test.test_genc import compile
+ def wrapper(arg):
+ try:
+ return gamma(arg)
+ except OverflowError:
+ return -42
+
+ f = compile(wrapper, [float])
+ assert f(10.0) == 362880.0
+ assert f(1720.0) == -42
+ assert f(172.0) == -42
diff --git a/rpython/rtyper/lltypesystem/rstr.py b/rpython/rtyper/lltypesystem/rstr.py
--- a/rpython/rtyper/lltypesystem/rstr.py
+++ b/rpython/rtyper/lltypesystem/rstr.py
@@ -302,6 +302,7 @@
b.chars[i] = str.chars[i]
return b
+ @jit.look_inside_iff(lambda s: jit.isvirtual(s))
@jit.elidable
def ll_strhash(s):
# unlike CPython, there is no reason to avoid to return -1
diff --git a/rpython/translator/backendopt/merge_if_blocks.py b/rpython/translator/backendopt/merge_if_blocks.py
--- a/rpython/translator/backendopt/merge_if_blocks.py
+++ b/rpython/translator/backendopt/merge_if_blocks.py
@@ -9,8 +9,10 @@
if len(block.operations) > 1 and not first:
return False
op = block.operations[-1]
- if (op.opname not in ('int_eq', 'uint_eq', 'llong_eq', 'ullong_eq',
- 'char_eq', 'unichar_eq')
+ if (op.opname not in ('int_eq', 'uint_eq', 'char_eq', 'unichar_eq')
+ # note: 'llong_eq', 'ullong_eq' have been removed, as it's not
+ # strictly C-compliant to do a switch() on a long long. It also
+ # crashes the JIT, and it's very very rare anyway.
or op.result != block.exitswitch):
return False
if isinstance(op.args[0], Variable) and isinstance(op.args[1], Variable):
diff --git a/rpython/translator/backendopt/test/test_merge_if_blocks.py b/rpython/translator/backendopt/test/test_merge_if_blocks.py
--- a/rpython/translator/backendopt/test/test_merge_if_blocks.py
+++ b/rpython/translator/backendopt/test/test_merge_if_blocks.py
@@ -38,9 +38,10 @@
return 4
do_test_merge(merge_int, range(4))
do_test_merge(merge_int, [r_uint(i) for i in range(4)])
- if r_longlong is not r_int:
- do_test_merge(merge_int, [r_longlong(i) for i in range(4)])
- do_test_merge(merge_int, [r_ulonglong(i) for i in range(4)])
+ # this has been disabled:
+ #if r_longlong is not r_int:
+ # do_test_merge(merge_int, [r_longlong(i) for i in range(4)])
+ #do_test_merge(merge_int, [r_ulonglong(i) for i in range(4)])
def merge_chr(n):
c = chr(n + 1)
diff --git a/rpython/translator/jvm/test/test_int.py b/rpython/translator/jvm/test/test_int.py
--- a/rpython/translator/jvm/test/test_int.py
+++ b/rpython/translator/jvm/test/test_int.py
@@ -16,5 +16,8 @@
def test_rarithmetic(self):
pass # does this make more sense in jvm
+
+ def test_str_of_uint(self):
+ py.test.skip("we don't care")
div_mod_iteration_count = 20
diff --git a/rpython/translator/platform/netbsd.py b/rpython/translator/platform/netbsd.py
--- a/rpython/translator/platform/netbsd.py
+++ b/rpython/translator/platform/netbsd.py
@@ -18,7 +18,9 @@
class Netbsd(posix.BasePosix):
name = "netbsd"
- link_flags = ['-pthread'] + get_env_vector('LDFLAGS', '')
+ link_flags = ['-pthread',
+ '-Wl,-R' + get_env("LOCALBASE", "/usr/pkg") + '/lib'
+ ] + get_env_vector('LDFLAGS', '')
cflags = ['-O3', '-pthread', '-fomit-frame-pointer'
] + get_env_vector('CFLAGS', '')
standalone_only = []
diff --git a/rpython/translator/sandbox/test/test_sandlib.py b/rpython/translator/sandbox/test/test_sandlib.py
--- a/rpython/translator/sandbox/test/test_sandlib.py
+++ b/rpython/translator/sandbox/test/test_sandlib.py
@@ -106,7 +106,7 @@
pass
def entry_point(argv):
- fd = os.open("tcp://pypy.org:80", os.O_RDONLY, 0777)
+ fd = os.open("tcp://python.org:80", os.O_RDONLY, 0777)
os.write(fd, 'GET /\n')
print os.read(fd, 30)
return 0
diff --git a/rpython/translator/tool/graphpage.py b/rpython/translator/tool/graphpage.py
--- a/rpython/translator/tool/graphpage.py
+++ b/rpython/translator/tool/graphpage.py
@@ -425,6 +425,8 @@
if block not in seen:
pending.append(block)
seen[block] = True
+ elif isinstance(y, dict):
+ pending.append(y) # go back from the dict to the real obj
graph = IncompleteGraph(pending)
SingleGraphPage(graph).display()
else:
More information about the pypy-commit
mailing list